[
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release with goreleaser\non:\n  push:\n    tags:\n      - v*.*.*\njobs:\n  build:\n    runs-on: macos-latest\n    name: goreleaser\n    steps:\n      - uses: actions/checkout@v2\n      - name: Unshallow Fetch\n        run: git fetch --prune --unshallow\n      - uses: actions/setup-go@v2\n        with:\n          go-version: 1.14\n      - name: Add MacOS certs\n        run: cp ./ci/add-osx-cert.sh /tmp/add-osx-cert.sh && chmod +x /tmp/add-osx-cert.sh && /tmp/add-osx-cert.sh\n        env:\n          CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}\n          CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}\n      - name: Install gon via HomeBrew for code signing and app notarization\n        run: |\n          brew tap mitchellh/gon\n          brew install mitchellh/gon/gon\n      - name: Set stage to prd for all\n        run: |\n          echo \"STAGE=PRD\" >> $GITHUB_ENV\n      - name: Set stage to dev if tagged develop\n        if: endsWith(github.ref, '-dev')\n        run: |\n          echo \"STAGE=DEV\" >> $GITHUB_ENV\n      - name: Set secret names\n        id: secretnames\n        run: |\n          echo $STAGE\n          echo \"::set-output name=SERVICES_API_URL::SERVICES_API_URL_${STAGE}\"\n          echo \"::set-output name=VAULT_API_URL::VAULT_API_URL_${STAGE}\"\n          echo \"::set-output name=VAULT_SALT_SECRET::VAULT_SALT_SECRET_${STAGE}\"\n          echo \"::set-output name=SERVICES_HUB_AUTH_URL::SERVICES_HUB_AUTH_URL_${STAGE}\"\n          echo \"::set-output name=TXL_HUB_TARGET::TXL_HUB_TARGET_${STAGE}\"\n          echo \"::set-output name=TXL_HUB_MA::TXL_HUB_MA_${STAGE}\"\n          echo \"::set-output name=TXL_THREADS_TARGET::TXL_THREADS_TARGET_${STAGE}\"\n          echo \"::set-output name=TXL_HUB_GATEWAY_URL::TXL_HUB_GATEWAY_URL_${STAGE}\"\n          echo \"::set-output name=TXL_USER_KEY::TXL_USER_KEY_${STAGE}\"\n          echo \"::set-output name=TXL_USER_SECRET::TXL_USER_SECRET_${STAGE}\"\n          echo \"::set-output name=SPACE_STORAGE_SITE_URL::SPACE_STORAGE_SITE_URL_${STAGE}\"\n      - name: Release via goreleaser\n        uses: goreleaser/goreleaser-action@master\n        with:\n          args: release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          IPFS_ADDR: ${{ secrets.IPFS_ADDR }}\n          IPFS_NODE_ADDR: ${{ secrets.IPFS_NODE_ADDR }}\n          IPFS_NODE_PATH: ${{ secrets.IPFS_NODE_PATH }}\n          SERVICES_API_URL: ${{ secrets[steps.secretnames.outputs.SERVICES_API_URL] }}\n          VAULT_API_URL: ${{ secrets[steps.secretnames.outputs.VAULT_API_URL] }}\n          VAULT_SALT_SECRET: ${{ secrets[steps.secretnames.outputs.VAULT_SALT_SECRET] }}\n          SERVICES_HUB_AUTH_URL: ${{ secrets[steps.secretnames.outputs.SERVICES_HUB_AUTH_URL] }}\n          TXL_HUB_TARGET: ${{ secrets[steps.secretnames.outputs.TXL_HUB_TARGET] }}\n          TXL_HUB_MA: ${{ secrets[steps.secretnames.outputs.TXL_HUB_MA] }}\n          TXL_THREADS_TARGET: ${{ secrets[steps.secretnames.outputs.TXL_THREADS_TARGET] }}\n          TXL_HUB_GATEWAY_URL: ${{ secrets[steps.secretnames.outputs.TXL_HUB_GATEWAY_URL] }}\n          TXL_USER_KEY: ${{ secrets[steps.secretnames.outputs.TXL_USER_KEY] }}\n          TXL_USER_SECRET: ${{ secrets[steps.secretnames.outputs.TXL_USER_SECRET] }}\n          SPACE_STORAGE_SITE_URL: ${{ secrets[steps.secretnames.outputs.SPACE_STORAGE_SITE_URL] }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "#on: [push, pull_request]\non: [pull_request]\nname: Test\njobs:\n  unit-test:\n    strategy:\n      matrix:\n        go-version: [1.14.x]\n        platform: [ubuntu-latest, macos-latest, windows-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Install Go\n        uses: actions/setup-go@v2\n        with:\n          go-version: ${{ matrix.go-version }}\n      - name: Checkout code\n        uses: actions/checkout@v2\n      - name: Unit Test\n        if: ${{ matrix.platform != 'windows-latest' }}\n        run: go test -race -coverprofile=coverage/unitcoverage.out $(go list ./... | grep -v integration_tests)\n      - name: Unit Test (Win)\n        if: ${{ matrix.platform == 'windows-latest' }} # skipping coverage collection on windows\n        run: go test -race $(go list ./... | grep -v integration_tests)\n      - name: Coveralls\n        if: ${{ matrix.platform != 'windows-latest' }}\n        uses: shogo82148/actions-goveralls@v1\n        with:\n          flag-name: unit-test-${{ matrix.platform }}\n          path-to-profile: coverage/unitcoverage.out\n          parallel: true\n  integration-test:\n    strategy:\n      matrix:\n        go-version: [ 1.14.x ]\n#        platform: [ ubuntu-latest, macos-latest, windows-latest ]\n        platform: [ macos-latest ]\n    runs-on: ${{ matrix.platform }}\n    env:\n      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      SERVICES_API_URL: ${{ secrets.outputs.SERVICES_API_URL_DEV }}\n      VAULT_API_URL: ${{ secrets.VAULT_API_URL_DEV }}\n      VAULT_SALT_SECRET: ${{ secrets.VAULT_SALT_SECRET_DEV }}\n      SERVICES_HUB_AUTH_URL: ${{ secrets.SERVICES_HUB_AUTH_URL_DEV }}\n      TXL_HUB_TARGET: ${{ secrets.TXL_HUB_TARGET_DEV }}\n      TXL_HUB_MA: ${{ secrets.TXL_HUB_MA_DEV }}\n      TXL_THREADS_TARGET: ${{ secrets.TXL_THREADS_TARGET_DEV }}\n      TXL_HUB_GATEWAY_URL: ${{ secrets.TXL_HUB_GATEWAY_URL_DEV }}\n      TXL_USER_KEY: ${{ secrets.TXL_USER_KEY_DEV }}\n      TXL_USER_SECRET: ${{ secrets.TXL_USER_SECRET_DEV }}\n      SPACE_STORAGE_SITE_URL: ${{ secrets.SPACE_STORAGE_SITE_URL_DEV }}\n    steps:\n      - name: Install Go\n        uses: actions/setup-go@v2\n        with:\n          go-version: ${{ matrix.go-version }}\n      - name: Install gnome-keyring (Ubuntu)\n        if: ${{ matrix.platform == 'ubuntu-latest' }}\n        run: sudo apt-get install pass gnome-keyring dbus-x11\n      - name: Verify gnome-keyring is installed (Ubuntu)\n        if: ${{ matrix.platform == 'ubuntu-latest' }}\n        run: gnome-keyring-daemon -V\n      - name: Checkout code\n        uses: actions/checkout@v2\n      - name: Integration Test\n        if: ${{ matrix.platform != 'windows-latest' }}\n        run: go test -v -timeout 60m -coverprofile=coverage/integrationcoverage.out ./integration_tests/...\n      - name: Integration Test (Win)\n        if: ${{ matrix.platform == 'windows-latest' }} # skipping coverage collection on windows\n        run: go test -v -timeout 60m ./integration_tests/...\n      - name: Coveralls\n        if: ${{ matrix.platform != 'windows-latest' }}\n        uses: shogo82148/actions-goveralls@v1\n        with:\n          flag-name: integration-test-${{ matrix.platform }}\n          path-to-profile: coverage/integrationcoverage.out\n          parallel: true\n  submit-coverage:\n    needs: [unit-test, integration-test]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Coveralls Finished\n        uses: shogo82148/actions-goveralls@v1\n        with:\n          parallel-finished: true"
  },
  {
    "path": ".gitignore",
    "content": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\ncoverage/*\n!coverage/.gitkeep\n\n# Dependency directories (remove the comment below to include it)\n# vendor/\n\n.idea/\ndebug/\n.DS_Store\n\n.env\nspace.json\nbin\n\ndebug/\n\ndist/\nmain\ndevtools/grpc-ecosystem\n__debug_bin"
  },
  {
    "path": ".goreleaser.yml",
    "content": "# Make sure to check the documentation at http://goreleaser.com\nbefore:\n  hooks:\n    # You may remove this if you don't use go modules.\n    - go mod download\n    # you may remove this if you don't need go generate\n    # - go generate ./...\nproject_name: space\nbuilds:\n  - id: space\n    # env:\n    #   - CGO_ENABLED=0\n    ldflags:\n      - -s -w -X  main.spaceapi={{ .Env.SERVICES_API_URL }}\n      - -X main.vaultapi={{ .Env.VAULT_API_URL }}\n      - -X main.vaultsaltsecret={{ .Env.VAULT_SALT_SECRET }}\n      - -X main.spacehubauth={{ .Env.SERVICES_HUB_AUTH_URL }}\n      - -X main.textilehub={{ .Env.TXL_HUB_TARGET }}\n      - -X main.textilehubma={{ .Env.TXL_HUB_MA }}\n      - -X main.textilethreads={{ .Env.TXL_THREADS_TARGET }}\n      - -X main.textilehubgatewayurl={{ .Env.TXL_HUB_GATEWAY_URL }}\n      - -X main.textileuserkey={{ .Env.TXL_USER_KEY }}\n      - -X main.textileusersecret={{ .Env.TXL_USER_SECRET }}\n      - -X main.spacestoragesiteurl={{ .Env.SPACE_STORAGE_SITE_URL }}\n      - -X main.ipfsaddr={{ .Env.IPFS_ADDR }}\n      - -X main.ipfsnodeaddr={{ .Env.IPFS_NODE_ADDR }}\n      - -X main.ipfsnodepath={{ .Env.IPFS_NODE_PATH }}\n    main: ./cmd/space-daemon/main.go\n    binary: space\n    goos:\n      - linux\n\n  - id: space-darwin\n    # env:\n    #   - CGO_ENABLED=0\n    ldflags:\n      - -s -w -X main.spaceapi={{ .Env.SERVICES_API_URL }}\n      - -X main.vaultapi={{ .Env.VAULT_API_URL }}\n      - -X main.vaultsaltsecret={{ .Env.VAULT_SALT_SECRET }}\n      - -X main.spacehubauth={{ .Env.SERVICES_HUB_AUTH_URL }}\n      - -X main.textilehub={{ .Env.TXL_HUB_TARGET }}\n      - -X main.textilehubma={{ .Env.TXL_HUB_MA }}\n      - -X main.textilethreads={{ .Env.TXL_THREADS_TARGET }}\n      - -X main.textilehubgatewayurl={{ .Env.TXL_HUB_GATEWAY_URL }}\n      - -X main.textileuserkey={{ .Env.TXL_USER_KEY }}\n      - -X main.textileusersecret={{ .Env.TXL_USER_SECRET }}\n      - -X main.spacestoragesiteurl={{ .Env.SPACE_STORAGE_SITE_URL }}\n      - -X main.ipfsaddr={{ .Env.IPFS_ADDR }}\n      - -X main.ipfsnodeaddr={{ .Env.IPFS_NODE_ADDR }}\n      - -X main.ipfsnodepath={{ .Env.IPFS_NODE_PATH }}\n    main: ./cmd/space-daemon/main.go\n    binary: space\n    goos:\n      - darwin\n    # hooks:\n    #   post: gon -log-level debug ci/gon.hcl\n\n  - id: space-win\n    # env:\n    #   - CGO_ENABLED=1\n    ldflags:\n      - -s -w -X main.spaceapi={{ .Env.SERVICES_API_URL }}\n      - -X main.vaultapi={{ .Env.VAULT_API_URL }}\n      - -X main.vaultsaltsecret={{ .Env.VAULT_SALT_SECRET }}\n      - -X main.spacehubauth={{ .Env.SERVICES_HUB_AUTH_URL }}\n      - -X main.textilehub={{ .Env.TXL_HUB_TARGET }}\n      - -X main.textilehubma={{ .Env.TXL_HUB_MA }}\n      - -X main.textilethreads={{ .Env.TXL_THREADS_TARGET }}\n      - -X main.textilehubgatewayurl={{ .Env.TXL_HUB_GATEWAY_URL }}\n      - -X main.textileuserkey={{ .Env.TXL_USER_KEY }}\n      - -X main.textileusersecret={{ .Env.TXL_USER_SECRET }}\n      - -X main.spacestoragesiteurl={{ .Env.SPACE_STORAGE_SITE_URL }}\n      - -X main.ipfsaddr={{ .Env.IPFS_ADDR }}\n      - -X main.ipfsnodeaddr={{ .Env.IPFS_NODE_ADDR }}\n      - -X main.ipfsnodepath={{ .Env.IPFS_NODE_PATH }}\n    main: ./cmd/space-daemon/main.go\n    binary: space\n    goos:\n      - windows\n    # ignore:\n    #   - goos: windows\n    #     goarch: 386\narchives:\n- name_template: '{{ .Binary }}_{{ .Os }}_{{ .Arch }}'\n  format: binary\n  files:\n    - LICENSE*\n    - README*\n    - CHANGELOG*\n    - dist/space-macos-i386.dmg\n    - dist/space-macos-x86_64.dmg\n  replacements:\n    darwin: Darwin\n    linux: Linux\n    windows: Windows\n    386: i386\n    amd64: x86_64\nchecksum:\n  name_template: 'checksums.txt'\nsnapshot:\n  name_template: \"{{ .Tag }}-next\"\nchangelog:\n  sort: asc\n  filters:\n    exclude:\n    - '^docs:'\n    - '^test:'\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Launch\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"auto\",\n      \"program\": \"${workspaceFolder}/cmd/space-daemon\",\n      \"envFile\": \"${workspaceFolder}/.env\",\n      \"args\": [\"-dev=true\"]\n    }\n  ]\n}"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2020 FleekHQ\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "Makefile",
    "content": "build:\n\tgo build \\\n\t-o bin/space \\\n\t-ldflags \\\n\t\"-X 'main.ipfsaddr=${IPFS_ADDR}' \\\n\t-X 'main.ipfsnodeaddr=${IPFS_NODE_ADDR}' \\\n\t-X 'main.ipfsnodepath=${IPFS_NODE_PATH}' \\\n\t-X 'main.spaceapi=${SERVICES_API_URL}' \\\n\t-X 'main.spacestoragesiteurl=${SPACE_STORAGE_SITE_URL}' \\\n\t-X 'main.vaultapi=${VAULT_API_URL}' \\\n\t-X 'main.vaultsaltsecret=${VAULT_SALT_SECRET}' \\\n\t-X 'main.spacehubauth=${SERVICES_HUB_AUTH_URL}' \\\n\t-X 'main.textilehub=${TXL_HUB_TARGET}' \\\n\t-X 'main.textilehubma=${TXL_HUB_MA}' \\\n\t-X 'main.textilethreads=${TXL_THREADS_TARGET}' \\\n\t-X 'main.textilehubgatewayurl=${TXL_HUB_GATEWAY_URL}' \\\n    -X 'main.textileuserkey=${TXL_USER_KEY}' \\\n\t-X 'main.textileusersecret=${TXL_USER_SECRET}'\" \\\n\tcmd/space-daemon/main.go\n\ntest:\n\tgo test $$(go list ./... | grep -v integration_tests)\n\ntest_coverage:\n\tgo test -coverprofile=coverage/unitcoverage.out $$(go list ./... | grep -v integration_tests)\n\nintegration_test:\n\tgo test -v -p 1 ./integration_tests/...\n\nintegration_test_coverage:\n\tgo test -v -p 1 -coverprofile=coverage/integrationcoverage.out ./integration_tests/...\n\nproto_gen:\n\tprotoc -I grpc/pb/ -I grpc/proto/ -I./devtools/googleapis grpc/proto/space.proto --go_out=plugins=grpc:grpc/pb\n\ngen_rest:\n\tprotoc -I grpc/pb/ -I grpc/proto/ -I./devtools/googleapis grpc/proto/space.proto --go_out=plugins=grpc:grpc/pb --grpc-gateway_out=logtostderr=true:grpc/pb\n\n\ngen_all: proto_gen gen_rest\n\n## runs jaeger tracing server, should be used when trace is enabled on daemon\njaegar:\n\tdocker run \\\n\t\t--rm \\\n\t\t--name jaeger \\\n\t\t-p 6831:6831/udp \\\n\t\t-p 16686:16686 \\\n\t\tjaegertracing/all-in-one:latest\n"
  },
  {
    "path": "README.md",
    "content": "# Space Daemon\n\nSpace Daemon is a wrapper built in Go around awesome IPFS tools so that you can have start coding a decentralized desktop app as fast as possible. It's built on top of Textile Threads and Buckets. Out of the box it includes:\n\n- A running local instance of [Textile Threads](https://github.com/textileio/go-threads).\n\n- Interfaces to create local private, encrypted buckets.\n\n- Interfaces for sharing those buckets and the files within.\n\n- Identity service so that sharing can be done through usernames or emails.\n\n- FUSE for drive mounting, so that the files can be explored natively in your OS.\n\n- Key management.\n\nNote: This project is in active development, so it might change its API until it reaches a stable version.\n\n## Installation\n\nBy default, Space Daemon connects to hosted services provided by Fleek. This should be good if you just want to get it running quickly. However, if you want to connect to your own services, read the [Modules Section](https://github.com/FleekHQ/space-daemon#Modules).\n\n### Downloading the binary\n\nCheck out the releases [here](https://github.com/FleekHQ/space-daemon/releases). You can download the latest version for your OS and you should be good to go.\n\nIf you want to run Space Daemon by source, check out [this section](https://github.com/FleekHQ/space-daemon#Running)\n\n## Usage\n\nSpace Daemon provides a gRPC interface. You can read its proto schema [here](https://github.com/FleekHQ/space-daemon/blob/master/grpc/proto/space.proto). It contains methods to:\n\n- Create files and directories\n\n- List files and directories\n\n- Creating buckets\n\n- Sharing buckets\n\n- Creating identities\n\nYou can also use the JavaScript client here [https://github.com/FleekHQ/space-client](https://github.com/FleekHQ/space-client)\n\nThis can be useful if, for example, you are building a web app that needs to interact with a user's locally running Space Daemon.\n\n## Modules\n\nSpace Daemon requires a few modules to run successfully. If you downloaded the binary, you don't have to worry about this since it will be connecting to our services. It's good to understand what's happening behind the scenes though.\n\n### IPFS Node\n\nAll encrypted files are stored in an IPFS node. For convenience, Space Daemon runs an embedded node within the daemon that can be configured as well as the option to specify an external node to connect to. \n\nIf you have your own node outside of the daemon, then set the flag `-ipfsnode` to `false`.  This will not spin up an embedded node. You can then connect to your external node by providing the `-ipfsaddr` flag (e.g. `-ipfsaddr=/ip4/127.0.0.1/tcp/5001`).\n\nIn the case you are running the embedded IPFS node, you can further configure the listen address and data directory by setting these flags respectively: `-ipfsnodeaddr` and `-ipfsnodepath`.\n\n### Textile Hub\n\nRequired for sharing files between users and backing it up. It stores all backed up files encrypted using a set of keys so that only you, and people you share files with, can read the data. We host our own instance of the Textile Hub, and by default, Space Daemon will conect to it. It can be customized by providing the `-textilehub` flag and `-textilethreads` flag.\n\nIf you want to host your own Textile Hub node, you can [read its documentation here](https://github.com/textileio/textile)\n\n### Space Services\n\nWe provide hosted alternatives for these services. You can deploy your own by following the instructions in its repo:\n\n[https://github.com/fleekHQ/space-services](https://github.com/fleekHQ/space-services)\n\n#### Identity\n\nThese are centralized services that are optional, but offer additional convenience. Used mainly for identity. By using these services, you can allow users to claim usernames, so that Space Daemon can know the public key of a given username and in that way share files via username without having to input public keys directly.\n\n#### Authentication\n\nOur hosted Textile Hub requires authentication via public key for logging in. This service sends a challenge to Space Daemon, which signs the challenge with the private key of the user and in that way our hosted Textile Hub can allow the user to store data.\n\n## Running from source\n\nAfter cloning this repo, you can run it from source by running `go run ./cmd/space-daemon -dev`. Consider that you will need the following environment variables exported in your system:\n\n```\nIPFS_ADDR=[Your IPFS node address]\nSERVICES_API_URL=[The URL where Space Services API is located]\nVAULT_API_URL=[The URL where Space Vault API is located]\nVAULT_SALT_SECRET=[A random string used for kdf functions before storing keys to the vault]\nSERVICES_HUB_AUTH_URL=[The URL where Space Services Textile Hub Authorizer is located]\nTXL_HUB_TARGET=[The URL of the Textile Hub]\nTXL_HUB_MA=[The multiaddress for the Textile hub]\nTXL_THREADS_TARGET=[The URL of the Textile Hub where Threads are hosted, can be the same that TXL_HUB_TARGET]\n\n# NOTE: the following are required temporarily and will be removed once hub auth wrapper is setup\nTXL_USER_KEY=[Space level key for hub access]\nTXL_USER_SECRET=[Space level secret for hub access]\n```\n\nAlternatively, you can run `make` to compile the binary. Make sure you have these environment variables exposed though. You can see some example environment variables in `.env.example`.\n\n## Contributting\n\nWe are happy to receive issues and review pull requests. Please make sure to write tests for the code you are introducing and make sure it doesn't break already passing tests.\n\nRead the following sections for an introduction into the code.\n\n### Package Structure\n\nLoosely based on these resources:\nhttps://github.com/golang-standards/project-layout\n\n\n- `/grpc` Folder structure for gRPC and REST API.\n- `/cmd` Entry point directory for all binaries this repo handles. E.g cmd/{binary-name}/main.go\n- `/config` Global Config code\n- `/core` Directory for the core objects of the package\n- `/logger` Directory for app logging\n- `/examples` Directory playground for general examples and drafts\n\n### Main classes\n\n- `ipfs`: contains utils for general IPFS operations.\n- `keychain`: manages user public/private key pair.\n- `libfuse`: interoperates with FUSE for mounting drives.\n- `space`: contains the main integration from the services to the final Textile or FS operations.\n- `store`: contains a wrapper around a local db.\n- `sync`: keeps track of open files so that the updates get pushed to IPFS\n- `textile`: wrapper around Textile booting and operations\n\n### Generating Mocks\n\nMocks are generated using https://github.com/vektra/mockery.\n\nFor Linux it needs to be built from source.\n\n`mockery --name InterfaceToMock --dir path/to/go/files`\n\n### Protobuf\n\nIf you update the gRPC API, you need to regenerate the Protobuf file.\n\nYou will need to install the following binaries in your Go path:\n\n- `go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway`\n\nChecking the binaries:\n`ls $GOPATH/bin`\nShould show the following binaries in your path: protoc-gen-go, protoc-gen-grpc-gateway\n\nRun the protobuf generation:\n`make proto_gen`\n\nRun the REST proxy generation:\n`make gen_rest`\n\n** Ideally you should run `make gen_all` before commiting as this would run all the above three code generations and\nensure everything is up to date **\n\nNOTE: See here for instructions on Reverse Proxy:\nhttps://github.com/grpc-ecosystem/grpc-gateway\n\n### Debugging, Profiling and Tracing\n\nThe following flags can be run with the binary to output profiling files for debugging.\nFlags support a full path to a file.\n`-cpuprofile cpu.prof -memprofile mem.prof`\n\nBy default, the binary runs in debug mode (this may change after release) and it boots a pprof\nserver in localhost:6060. See docs how to interact with pprof server here: https://github.com/google/pprof/blob/master/doc/README.md\n\nTo disable debug mode add this flag to binary arguments\n`-debug=false`\n\nTo enable trace in the daemon, pass `-trace` to the binary arguments. The daemon uses [jaegar](https://www.jaegertracing.io/) \nfor collecting trace information. Run `make jaegar` to quickly start a jaeger agent that collects the daemons trace information.\nYou can `http://localhost:16686/` to explore the web ui for traces collected.\n\n### CI Secrets\n\nSecrets are set by adding them in Github and then specifying them in `release.yml`. Secrets can be constant across environment/stages or be stage specific.\n\nIf specified, the release file will dynamically generate the secret name based on the stage by adding a `_DEV` or `_PRD` suffix to the secret name only for the specificed environment variable. It will always use `_PRD` unless the tag ends in `-dev`.  So for example tag `v0.0.15` will use PRD values, while `v0.0.15-dev` will use DEV values.\n\nStage specific secret names will only be used for secrets in `release.yml` that point to the step output instead of the secret name directly (i.e., `SERVICES_API_URL: ${{ secrets[steps.secretnames.outputs.SERVICES_API_URL] }}` instead of `SERVICES_API_URL: ${{ secrets.SERVICES_API_URL }}`.\n\nSo to add a new secret:\n* If it's not stage specific then add the secret in GH with no suffix and in `release.yml`, refer to it based on the secret name.\n* If it is stage specific, then create the 2 secrets in GH (ending in `_PRD` and `_DEV`), add the entry in step `secretnames`, and make sure the secret name in the next step points to the step output"
  },
  {
    "path": "app/app.go",
    "content": "package app\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/fuse/installer\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search/bleve\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core\"\n\t\"github.com/FleekHQ/space-daemon/grpc\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/fuse\"\n\t\"github.com/FleekHQ/space-daemon/core/vault\"\n\n\t\"github.com/FleekHQ/space-daemon/core/fsds\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n\ttextile \"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\t\"github.com/FleekHQ/space-daemon/core/space\"\n\n\tnode \"github.com/FleekHQ/space-daemon/core/ipfs/node\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/sync\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\tw \"github.com/FleekHQ/space-daemon/core/watcher\"\n\t\"github.com/golang-collections/collections/stack\"\n)\n\n// Shutdown logic follows this example https://gist.github.com/akhenakh/38dbfea70dc36964e23acc19777f3869\ntype App struct {\n\teg         *errgroup.Group\n\tcomponents *stack.Stack\n\tcfg        config.Config\n\tenv        env.SpaceEnv\n\tIsRunning  bool\n}\n\ntype componentMap struct {\n\tname      string\n\tcomponent core.Component\n}\n\nfunc New(cfg config.Config, env env.SpaceEnv) *App {\n\treturn &App{\n\t\tcomponents: stack.New(),\n\t\tcfg:        cfg,\n\t\tenv:        env,\n\t\tIsRunning:  false,\n\t}\n}\n\n// Start is the Entry point for the app.\n// All module components are initialized and managed here.\n// When a top level module that need to be shutdown on exit is initialized. It should be\n// added to the apps list of tracked components using the `Run()` function, but if the component has a blocking\n// start/run function it should be tracked with the `RunAsync()` function and call the blocking function in the\n// input function block.\nfunc (a *App) Start() error {\n\tvar ctx context.Context\n\ta.eg, ctx = errgroup.WithContext(context.Background())\n\n\tlog.SetLogLevel(a.cfg.GetString(config.LogLevel, \"debug\"))\n\n\t// init appStore\n\tappStore := store.New(\n\t\tstore.WithPath(a.cfg.GetString(config.SpaceStorePath, \"\")),\n\t)\n\tif err := appStore.Open(); err != nil {\n\t\treturn err\n\t}\n\ta.Run(\"Store\", appStore)\n\n\t// Init keychain\n\tkc := keychain.New(keychain.WithPath(a.cfg.GetString(config.SpaceStorePath, \"\")), keychain.WithStore(appStore))\n\n\t// Init Vault\n\tv := vault.New(a.cfg.GetString(config.SpaceVaultAPIURL, \"\"), a.cfg.GetString(config.SpaceVaultSaltSecret, \"\"))\n\n\twatcher, err := w.New()\n\tif err != nil {\n\t\treturn err\n\t}\n\ta.Run(\"FolderWatcher\", watcher)\n\n\t// setup local ipfs node if Ipfsnode is set\n\tif a.cfg.GetBool(config.Ipfsnode, true) {\n\t\t// setup local ipfs node\n\t\tnode := node.NewIpsNode(a.cfg)\n\t\terr = a.RunAsync(\"IpfsNode\", node, func() error {\n\t\t\treturn node.Start(ctx)\n\t\t})\n\t\tif err != nil {\n\t\t\tlog.Error(\"error starting embedded IPFS node\", err)\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tlog.Info(\"Skipping embedded IPFS node\")\n\t}\n\n\t// setup local buckets\n\tbuckd := textile.NewBuckd(a.cfg)\n\terr = a.RunAsync(\"BucketDaemon\", buckd, func() error {\n\t\treturn buckd.Start(ctx)\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thubAuth := hub.New(appStore, kc, a.cfg)\n\n\t// setup files search engine\n\tsearchEngine := bleve.NewSearchEngine(bleve.WithDBPath(a.cfg.GetString(config.SpaceStorePath, \"\")))\n\ta.Run(\"FilesSearchEngine\", searchEngine)\n\n\t// setup textile client\n\tuc := textile.CreateUserClient(a.cfg.GetString(config.TextileHubTarget, \"\"))\n\ttextileClient := textile.NewClient(appStore, kc, hubAuth, uc, nil, searchEngine)\n\terr = a.RunAsync(\"TextileClient\", textileClient, func() error {\n\t\treturn textileClient.Start(ctx, a.cfg)\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// watcher is started inside bucket sync\n\tbucketSync := sync.New(watcher, textileClient, appStore, nil)\n\n\t// setup the Space Service\n\tsv, svErr := space.NewService(\n\t\tappStore,\n\t\ttextileClient,\n\t\tbucketSync,\n\t\ta.cfg,\n\t\tkc,\n\t\tv,\n\t\thubAuth,\n\t\tspace.WithEnv(a.env),\n\t)\n\tif svErr != nil {\n\t\treturn svErr\n\t}\n\n\t// setup FUSE FS Handler\n\tsfs := spacefs.New(fsds.NewSpaceFSDataSource(\n\t\tsv,\n\t\tfsds.WithFilesDataSources(sv),\n\t\tfsds.WithSharedWithMeDataSources(sv),\n\t))\n\tfuseInstaller := installer.NewFuseInstaller()\n\tfuseController := fuse.NewController(ctx, a.cfg, appStore, sfs, fuseInstaller)\n\tif fuseController.ShouldMount() {\n\t\tlog.Info(\"Mounting FUSE Drive\")\n\t\tif err := fuseController.Mount(); err != nil {\n\t\t\tlog.Error(\"Mounting FUSE drive failed\", err)\n\t\t} else {\n\t\t\tlog.Info(\"Mounting FUSE Drive successful\")\n\t\t}\n\t}\n\ta.Run(\"FuseController\", fuseController)\n\n\t// setup gRPC Server\n\tsrv := grpc.New(\n\t\tsv,\n\t\tfuseController,\n\t\tkc,\n\t\tgrpc.WithPort(a.cfg.GetInt(config.SpaceServerPort, 0)),\n\t\tgrpc.WithProxyPort(a.cfg.GetInt(config.SpaceProxyServerPort, 0)),\n\t\tgrpc.WithRestProxyPort(a.cfg.GetInt(config.SpaceRestProxyServerPort, 0)),\n\t)\n\n\ttextileClient.AttachMailboxNotifier(srv)\n\ttextileClient.AttachSynchronizerNotifier(srv)\n\n\t// start the gRPC server\n\terr = a.RunAsync(\"gRPCServer\", srv, func() error {\n\t\treturn srv.Start(ctx)\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = a.RunAsync(\"BucketSync\", bucketSync, func() error {\n\t\tbucketSync.RegisterNotifier(srv)\n\t\treturn bucketSync.Start(ctx)\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Info(\"Daemon ready\")\n\ta.IsRunning = true\n\n\treturn nil\n}\n\n// Run registers this component to be cleaned up on Shutdown\nfunc (a *App) Run(name string, component core.Component) {\n\tlog.Debug(\"Starting Component\", \"name:\"+name)\n\ta.components.Push(&componentMap{\n\t\tname:      name,\n\t\tcomponent: component,\n\t})\n}\n\n// RunAsync performs the same function as Run() but also accepts an function to be run\n// async to initialize the component.\nfunc (a *App) RunAsync(name string, component core.AsyncComponent, fn func() error) error {\n\tlog.Debug(\"Starting Async Component\", \"name:\"+name)\n\tif a.eg == nil {\n\t\tlog.Warn(\"App.RunAsync() should be called after App.Start()\")\n\t\treturn nil\n\t}\n\n\terrc := make(chan error)\n\n\ta.eg.Go(func() error {\n\t\terr := fn()\n\t\tif err != nil {\n\t\t\terrc <- err\n\t\t}\n\n\t\treturn err\n\t})\n\n\tselect {\n\tcase err := <-errc:\n\t\treturn err\n\tcase <-component.WaitForReady():\n\t\ta.components.Push(&componentMap{\n\t\t\tname:      name,\n\t\t\tcomponent: component,\n\t\t})\n\t}\n\n\treturn nil\n}\n\n// Shutdown would perform a graceful shutdown of all components added through the\n// Run() or RunAsync() functions\nfunc (a *App) Shutdown() error {\n\tlog.Info(\"Daemon shutdown started\")\n\tif !a.IsRunning {\n\t\treturn errors.New(\"app is not running\")\n\t}\n\n\tfor a.components.Len() > 0 {\n\t\tm, ok := a.components.Pop().(*componentMap)\n\t\tif ok {\n\t\t\tlog.Debug(\"Shutting down Component\", fmt.Sprintf(\"name:%s\", m.name))\n\t\t\tif err := m.component.Shutdown(); err != nil {\n\t\t\t\tlog.Error(fmt.Sprintf(\"error shutting down %s\", m.name), err)\n\t\t\t}\n\t\t}\n\t}\n\n\terr := a.eg.Wait()\n\tlog.Info(\"Shutdown complete\")\n\ta.IsRunning = false\n\treturn err\n}\n"
  },
  {
    "path": "ci/add-osx-cert.sh",
    "content": "#!/usr/bin/env sh\n\nKEY_CHAIN=build.keychain\nCERTIFICATE_P12=certificate.p12\n\n# Recreate the certificate from the secure environment variable\necho $CERTIFICATE_OSX_APPLICATION | base64 --decode > $CERTIFICATE_P12\n\n#create a keychain\nsecurity create-keychain -p actions $KEY_CHAIN\n\n# Make the keychain the default so identities are found\nsecurity default-keychain -s $KEY_CHAIN\n\n# Unlock the keychain\nsecurity unlock-keychain -p actions $KEY_CHAIN\n\nsecurity import $CERTIFICATE_P12 -k $KEY_CHAIN -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign;\n\nsecurity set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN\n\n# remove certs\nrm -fr *.p12"
  },
  {
    "path": "ci/gon.hcl",
    "content": "# The path follows a pattern\n# ./dist/BUILD-ID_TARGET/BINARY-NAME\nsource = [\"./dist/space-darwin_darwin_amd64/space\",\"./dist/space-darwin_darwin_386/space\"]\nbundle_id = \"co.fleek.space\"\n\napple_id {\n  username = \"daniel@fleek.co\"\n  password = \"@env:APPLE_DEVELOPER_DANIEL_PASSWORD\"\n}\n\nsign {\n  application_identity = \"Mac Developer: Daniel Merrill (8257VLCFL7)\"\n}"
  },
  {
    "path": "cmd/space-daemon/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"os/signal\"\n\t\"runtime\"\n\t\"runtime/pprof\"\n\t\"syscall\"\n\n\t\"github.com/FleekHQ/space-daemon/tracing\"\n\n\t\"github.com/opentracing/opentracing-go\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"github.com/FleekHQ/space-daemon/app\"\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\t\"github.com/FleekHQ/space-daemon/core/util/rlimit\"\n)\n\nvar (\n\tcpuprofile           = flag.String(\"cpuprofile\", \"\", \"write cpu profile to `file`\")\n\tmemprofile           = flag.String(\"memprofile\", \"\", \"write memory profile to `file`\")\n\tdebugMode            = flag.Bool(\"debug\", true, \"run daemon with debug mode for profiling\")\n\tenableTracing        = flag.Bool(\"trace\", false, \"run tracing on daemon rpc\")\n\tdevMode              = flag.Bool(\"dev\", false, \"run daemon in dev mode to use .env file\")\n\tipfsnode             = flag.Bool(\"ipfsnode\", true, \"run IPFS embedded into the daemon (defaults to true)\")\n\tipfsaddr             string\n\tipfsnodeaddr         string\n\tipfsnodepath         string\n\tspaceapi             string\n\tspacestoragesiteurl  string\n\tvaultapi             string\n\tvaultsaltsecret      string\n\tspacehubauth         string\n\ttextilehub           string\n\ttextilehubma         string\n\ttextilethreads       string\n\ttextilehubgatewayurl string\n\ttextileuserkey       string\n\ttextileusersecret    string\n)\n\nfunc main() {\n\t// this defer code here ensures all profile defer call work properly\n\treturnCode := 0\n\tdefer func() { os.Exit(returnCode) }()\n\n\t// flags\n\tflag.Parse()\n\n\tlog.Debug(\"Running mode\", fmt.Sprintf(\"DevMode:%v\", *devMode))\n\n\tcf := &config.Flags{\n\t\tIpfsaddr:             ipfsaddr,\n\t\tIpfsnode:             *ipfsnode == true,\n\t\tIpfsnodeaddr:         ipfsnodeaddr,\n\t\tIpfsnodepath:         ipfsnodepath,\n\t\tServicesAPIURL:       spaceapi,\n\t\tSpaceStorageSiteUrl:  spacestoragesiteurl,\n\t\tVaultAPIURL:          vaultapi,\n\t\tVaultSaltSecret:      vaultsaltsecret,\n\t\tServicesHubAuthURL:   spacehubauth,\n\t\tDevMode:              *devMode == true,\n\t\tTextileHubTarget:     textilehub,\n\t\tTextileHubMa:         textilehubma,\n\t\tTextileThreadsTarget: textilethreads,\n\t\tTextileHubGatewayUrl: textilehubgatewayurl,\n\t\tTextileUserKey:       textileuserkey,\n\t\tTextileUserSecret:    textileusersecret,\n\t}\n\n\t// CPU profiling\n\tif *debugMode == true {\n\t\tlog.Debug(\"Running daemon with profiler. Visit http://localhost:6060/debug/pprof\")\n\t\tgo func() {\n\t\t\tfmt.Println(http.ListenAndServe(\"localhost:6060\", nil))\n\t\t}()\n\t}\n\n\t// initialize tracing\n\tif *enableTracing {\n\t\tlog.Debug(\"Enabling Tracing on the Daemon\")\n\t\ttracer, closer := tracing.MustInit(\"space-daemon\")\n\t\tdefer closer.Close()\n\t\topentracing.SetGlobalTracer(tracer)\n\t}\n\n\tif *cpuprofile != \"\" {\n\t\tcleanupCpuProfile := runCpuProfiler(*cpuprofile)\n\t\tdefer cleanupCpuProfile()\n\t}\n\n\t// env\n\tenv := env.New()\n\n\t// load configs\n\tcfg := config.NewMap(cf)\n\n\trlimit.SetRLimit()\n\n\tspaceApp := app.New(cfg, env)\n\n\terr := spaceApp.Start()\n\tif err != nil {\n\t\tlog.Error(\"Application startup failed\", err)\n\t\treturnCode = 1\n\t}\n\n\t// setup to detect interruption\n\tinterrupt := make(chan os.Signal, 1)\n\tsignal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)\n\tdefer signal.Stop(interrupt)\n\n\t<-interrupt // wait for interrupt and then shutdown app\n\terr = spaceApp.Shutdown()\n\n\tif *memprofile != \"\" {\n\t\tcleanupMemProfile := runMemProfiler(*memprofile)\n\t\tdefer cleanupMemProfile()\n\t}\n\n\tif err != nil {\n\t\tlog.Error(\"Application shutdown failed\", err)\n\t\treturnCode = 1\n\t}\n}\n\nfunc runCpuProfiler(outputFilePath string) func() {\n\tf, err := os.Create(outputFilePath)\n\tif err != nil {\n\t\tlog.Error(\"Could not create CPU profile\", err)\n\t\treturn func() {}\n\t}\n\n\tif err := pprof.StartCPUProfile(f); err != nil {\n\t\tlog.Error(\"Could not start CPU profile\", err)\n\t}\n\n\t// return cleanup function\n\treturn func() {\n\t\tpprof.StopCPUProfile()\n\t\tif f != nil {\n\t\t\t_ = f.Close() // error is ignored\n\t\t}\n\t}\n}\n\nfunc runMemProfiler(outputFilePath string) func() {\n\tf, err := os.Create(outputFilePath)\n\tif err != nil {\n\t\tlog.Error(\"could not create memory profile\", err)\n\t\treturn func() {}\n\t}\n\n\truntime.GC() // get up-to-date statistics\n\tif err := pprof.WriteHeapProfile(f); err != nil {\n\t\tlog.Error(\"could not write memory profile\", err)\n\t}\n\n\t// return cleanup function\n\treturn func() {\n\t\tif f != nil {\n\t\t\t_ = f.Close()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/config.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n)\n\nconst (\n\tJsonConfigFileName       = \"space.json\"\n\tSpaceServerPort          = \"space/rpcPort\"\n\tSpaceProxyServerPort     = \"space/rpcProxyPort\"\n\tSpaceRestProxyServerPort = \"space/restProxyPort\"\n\tSpaceStorageSiteUrl      = \"space/storageSiteUrl\"\n\tSpaceStorePath           = \"space/storePath\"\n\tTextileHubTarget         = \"space/textileHubTarget\"\n\tTextileHubMa             = \"space/textileHubMa\"\n\tTextileThreadsTarget     = \"space/textileThreadsTarget\"\n\tTextileHubGatewayUrl     = \"space/TextileHubGatewayUrl\"\n\tTextileUserKey           = \"space/textileUserKey\"\n\tTextileUserSecret        = \"space/textileUserSecret\"\n\tMountFuseDrive           = \"space/mountFuseDrive\"\n\tFuseMountPath            = \"space/fuseMountPath\"\n\tFuseDriveName            = \"space/fuseDriveName\"\n\tSpaceServicesAPIURL      = \"space/servicesApiUrl\"\n\tSpaceVaultAPIURL         = \"space/vaultApiUrl\"\n\tSpaceVaultSaltSecret     = \"space/vaultSaltSecret\"\n\tSpaceServicesHubAuthURL  = \"space/servicesHubAuthUrl\"\n\tIpfsaddr                 = \"space/ipfsAddr\"\n\tIpfsnode                 = \"space/ipfsNode\"\n\tIpfsnodeaddr             = \"space/ipfsNodeAddr\"\n\tIpfsnodepath             = \"space/ipfsNodePath\"\n\tMinThreadsConnection     = \"space/minThreadsConn\"\n\tMaxThreadsConnection     = \"space/maxThreadsConn\"\n\tBuckdPath                = \"space/BuckdPath\"\n\tBuckdApiMaAddr           = \"space/BuckdApiMaAddr\"\n\tBuckdApiProxyMaAddr      = \"space/BuckdApiProxyMaAddr\"\n\tBuckdThreadsHostMaAddr   = \"Space/BuckdThreadsHostMaAddr\"\n\tBuckdGatewayPort         = \"Space/BuckdGatewayPort\"\n\tLogLevel                 = \"Space/LogLevel\"\n)\n\nvar (\n\tErrConfigNotLoaded = errors.New(\"config file was not loaded correctly or it does not exist\")\n)\n\ntype Flags struct {\n\tIpfsaddr               string\n\tIpfsnode               bool\n\tIpfsnodeaddr           string\n\tIpfsnodepath           string\n\tDevMode                bool\n\tServicesAPIURL         string\n\tSpaceStorageSiteUrl    string\n\tVaultAPIURL            string\n\tVaultSaltSecret        string\n\tServicesHubAuthURL     string\n\tTextileHubTarget       string\n\tTextileHubMa           string\n\tTextileThreadsTarget   string\n\tTextileHubGatewayUrl   string\n\tTextileUserKey         string\n\tTextileUserSecret      string\n\tSpaceStorePath         string\n\tRpcServerPort          int\n\tRpcProxyServerPort     int\n\tRestProxyServerPort    int\n\tBuckdPath              string\n\tBuckdApiMaAddr         string\n\tBuckdApiProxyMaAddr    string\n\tBuckdThreadsHostMaAddr string\n\tBuckdGatewayPort       int\n\tLogLevel               string\n}\n\n// Config used to fetch config information\ntype Config interface {\n\tGetString(key string, defaultValue interface{}) string\n\tGetInt(key string, defaultValue interface{}) int\n\tGetBool(key string, defaultValue interface{}) bool\n}\n"
  },
  {
    "path": "config/json_config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/creamdog/gonfig\"\n)\n\n// standardConfig implements Config\n// It loads its config information from the space.json file\ntype jsonConfig struct {\n\tcfg gonfig.Gonfig\n}\n\ntype defaultSpaceJson struct {\n\tTextileHubTarget     string `json:\"textileHubTarget\"`\n\tTextileThreadsTarget string `json:\"textileThreadsTarget\"`\n\tRPCPort              int    `json:\"rpcPort\"`\n\tStorePath            string `json:\"storePath\"`\n}\n\ntype defaultJson struct {\n\tSpace defaultSpaceJson `json:\"space\"`\n}\n\n// Deprecated for the default values config\nfunc NewJson(env env.SpaceEnv) Config {\n\twd := env.WorkingFolder()\n\tf, err := os.Open(wd + \"/\" + JsonConfigFileName)\n\tif err != nil {\n\t\t// TODO: this may turn into a fatal panic error\n\t\tlog.Info(\"could not find space.json file in \" + wd + \", using defaults\")\n\t}\n\n\tdefer f.Close()\n\tconfig, err := gonfig.FromJson(f)\n\tif err != nil {\n\t\tlog.Info(\"could not read space.json file, using defaults\")\n\t}\n\n\tc := jsonConfig{\n\t\tcfg: config,\n\t}\n\n\treturn c\n}\n\n// Gets the configuration value given a path in the json config file\n// defaults to empty value if non is found and just logs errors\nfunc (c jsonConfig) GetString(key string, defaultValue interface{}) string {\n\tif c.cfg == nil {\n\t\treturn \"\"\n\t}\n\tv, err := c.cfg.GetString(key, defaultValue)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error getting key %s from config\", key), err)\n\t\treturn \"\"\n\t}\n\tlog.Debug(\"Getting conf \" + key + \": \" + v)\n\n\treturn v\n}\n\n// Gets the configuration value given a path in the json config file\n// defaults to empty value if non is found and just logs errors\nfunc (c jsonConfig) GetInt(key string, defaultValue interface{}) int {\n\tif c.cfg == nil {\n\t\treturn 0\n\t}\n\tv, err := c.cfg.GetInt(key, defaultValue)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error getting key %s from config\", key), err)\n\t\treturn 0\n\t}\n\n\treturn v\n}\n\n// Gets the configuration value given a path in the json config file\n// defaults to empty value if non is found and just logs errors\nfunc (c jsonConfig) GetBool(key string, defaultValue interface{}) bool {\n\tif c.cfg == nil {\n\t\treturn false\n\t}\n\tv, err := c.cfg.GetBool(key, defaultValue)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error getting key %s from config\", key), err)\n\t\treturn false\n\t}\n\n\treturn v\n}\n\nfunc CreateConfigJson() error {\n\tfmt.Println(\"Generating default config file\")\n\tspaceJson := defaultSpaceJson{\n\t\tTextileHubTarget:     \"textile-hub-dev.fleek.co:3006\",\n\t\tTextileThreadsTarget: \"textile-hub-dev.fleek.co:3006\",\n\t\tRPCPort:              9999,\n\t\tStorePath:            \"~/.fleek-space\",\n\t}\n\n\tfinalJson := defaultJson{\n\t\tSpace: spaceJson,\n\t}\n\n\tcurrExecutablePath, err := os.Executable()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpathSegments := strings.Split(currExecutablePath, \"/\")\n\twd := strings.Join(pathSegments[:len(pathSegments)-1], \"/\")\n\n\tjsonPath := wd + \"/\" + JsonConfigFileName\n\tmarshalled, err := json.MarshalIndent(finalJson, \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = ioutil.WriteFile(jsonPath, marshalled, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Println(\"Default config file generated\")\n\n\treturn nil\n}\n"
  },
  {
    "path": "config/map_config.go",
    "content": "package config\n\nimport (\n\t\"os\"\n\t\"os/user\"\n\t\"path/filepath\"\n\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n)\n\ntype mapConfig struct {\n\tconfigStr  map[string]string\n\tconfigInt  map[string]int\n\tconfigBool map[string]bool\n}\n\nfunc NewMap(flags *Flags) Config {\n\tconfigStr := make(map[string]string)\n\tconfigInt := make(map[string]int)\n\tconfigBool := make(map[string]bool)\n\n\tusr, _ := user.Current()\n\n\t// default values\n\tconfigStr[LogLevel] = flags.LogLevel\n\tconfigStr[SpaceStorePath] = filepath.Join(usr.HomeDir, \".fleek-space\")\n\tconfigStr[MountFuseDrive] = \"false\"\n\tconfigStr[FuseDriveName] = \"Space\"\n\tconfigInt[SpaceServerPort] = 9999\n\tconfigInt[SpaceProxyServerPort] = 9998\n\tconfigInt[SpaceRestProxyServerPort] = 9997\n\tif flags.DevMode {\n\t\tconfigStr[Ipfsaddr] = os.Getenv(env.IpfsAddr)\n\t\tconfigStr[Ipfsnodeaddr] = os.Getenv(env.IpfsNodeAddr)\n\t\tconfigStr[Ipfsnodepath] = os.Getenv(env.IpfsNodePath)\n\t\tconfigStr[SpaceServicesAPIURL] = os.Getenv(env.ServicesAPIURL)\n\t\tconfigStr[SpaceVaultAPIURL] = os.Getenv(env.VaultAPIURL)\n\t\tconfigStr[SpaceVaultSaltSecret] = os.Getenv(env.VaultSaltSecret)\n\t\tconfigStr[SpaceServicesHubAuthURL] = os.Getenv(env.ServicesHubAuthURL)\n\t\tconfigStr[SpaceStorageSiteUrl] = os.Getenv(env.SpaceStorageSiteUrl)\n\t\tconfigStr[TextileHubTarget] = os.Getenv(env.TextileHubTarget)\n\t\tconfigStr[TextileHubMa] = os.Getenv(env.TextileHubMa)\n\t\tconfigStr[TextileThreadsTarget] = os.Getenv(env.TextileThreadsTarget)\n\t\tconfigStr[TextileHubGatewayUrl] = os.Getenv(env.TextileHubGatewayUrl)\n\t\tconfigStr[TextileUserKey] = os.Getenv(env.TextileUserKey)\n\t\tconfigStr[TextileUserSecret] = os.Getenv(env.TextileUserSecret)\n\n\t\tif os.Getenv(env.IpfsNode) != \"false\" {\n\t\t\tconfigBool[Ipfsnode] = true\n\t\t}\n\t} else {\n\t\tconfigStr[Ipfsaddr] = flags.Ipfsaddr\n\t\tconfigStr[Ipfsnodeaddr] = flags.Ipfsnodeaddr\n\t\tconfigStr[Ipfsnodepath] = flags.Ipfsnodepath\n\t\tconfigStr[SpaceServicesAPIURL] = flags.ServicesAPIURL\n\t\tconfigStr[SpaceVaultAPIURL] = flags.VaultAPIURL\n\t\tconfigStr[SpaceVaultSaltSecret] = flags.VaultSaltSecret\n\t\tconfigStr[SpaceServicesHubAuthURL] = flags.ServicesHubAuthURL\n\t\tif flags.SpaceStorageSiteUrl != \"\" {\n\t\t\tconfigStr[SpaceStorageSiteUrl] = flags.SpaceStorageSiteUrl\n\t\t}\n\t\tconfigStr[TextileHubTarget] = flags.TextileHubTarget\n\t\tconfigStr[TextileHubMa] = flags.TextileHubMa\n\t\tconfigStr[TextileThreadsTarget] = flags.TextileThreadsTarget\n\t\tconfigStr[TextileHubGatewayUrl] = flags.TextileHubGatewayUrl\n\t\tconfigStr[TextileUserKey] = flags.TextileUserKey\n\t\tconfigStr[TextileUserSecret] = flags.TextileUserSecret\n\t\tconfigBool[Ipfsnode] = flags.Ipfsnode\n\t\tif flags.SpaceStorePath != \"\" {\n\t\t\tconfigStr[SpaceStorePath] = flags.SpaceStorePath\n\t\t}\n\t\tif flags.RpcServerPort != 0 {\n\t\t\tconfigInt[SpaceServerPort] = flags.RpcServerPort\n\t\t}\n\t\tif flags.RpcProxyServerPort != 0 {\n\t\t\tconfigInt[SpaceProxyServerPort] = flags.RpcProxyServerPort\n\t\t}\n\t\tif flags.RestProxyServerPort != 0 {\n\t\t\tconfigInt[SpaceRestProxyServerPort] = flags.RestProxyServerPort\n\t\t}\n\t\tif flags.BuckdPath != \"\" {\n\t\t\tconfigStr[BuckdPath] = flags.BuckdPath\n\t\t}\n\t\tif flags.BuckdApiMaAddr != \"\" {\n\t\t\tconfigStr[BuckdApiMaAddr] = flags.BuckdApiMaAddr\n\t\t}\n\t\tif flags.BuckdApiProxyMaAddr != \"\" {\n\t\t\tconfigStr[BuckdApiProxyMaAddr] = flags.BuckdApiProxyMaAddr\n\t\t}\n\t\tif flags.BuckdThreadsHostMaAddr != \"\" {\n\t\t\tconfigStr[BuckdThreadsHostMaAddr] = flags.BuckdThreadsHostMaAddr\n\t\t}\n\t\tif flags.BuckdGatewayPort != 0 {\n\t\t\tconfigInt[BuckdGatewayPort] = flags.BuckdGatewayPort\n\t\t}\n\t}\n\n\t// Temp fix until we move to viper\n\tif configStr[Ipfsaddr] == \"\" {\n\t\tconfigStr[Ipfsaddr] = \"/ip4/127.0.0.1/tcp/5001\"\n\t}\n\n\tc := mapConfig{\n\t\tconfigStr:  configStr,\n\t\tconfigInt:  configInt,\n\t\tconfigBool: configBool,\n\t}\n\n\treturn c\n}\n\nfunc (m mapConfig) GetString(key string, defaultValue interface{}) string {\n\tif val, exists := m.configStr[key]; exists {\n\t\treturn val\n\t}\n\n\tif stringValue, ok := defaultValue.(string); ok {\n\t\treturn stringValue\n\t}\n\n\treturn \"\"\n}\n\nfunc (m mapConfig) GetInt(key string, defaultValue interface{}) int {\n\tif val, exists := m.configInt[key]; exists {\n\t\treturn val\n\t}\n\n\tif intVal, ok := defaultValue.(int); ok {\n\t\treturn intVal\n\t}\n\n\treturn 0\n}\n\nfunc (m mapConfig) GetBool(key string, defaultValue interface{}) bool {\n\tif val, exists := m.configBool[key]; exists {\n\t\treturn val\n\t}\n\n\tif boolVal, ok := defaultValue.(bool); ok {\n\t\treturn boolVal\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "core/backup/backup.go",
    "content": "package backup\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n)\n\ntype Backup struct {\n\tPrivateKey string `json:\"privateKey\"`\n}\n\n// Note: Using static key since the goal of this is to obfuscate the file, not to encrypt it\nvar key = []byte{0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC}\n\nfunc obfuscate(data []byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnonce := make([]byte, gcm.NonceSize())\n\t_, err = io.ReadFull(rand.Reader, nonce)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn gcm.Seal(nonce, nonce, data, nil), nil\n}\n\nfunc deobfuscate(ciphertext []byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(ciphertext) < gcm.NonceSize() {\n\t\treturn nil, errors.New(\"malformed ciphertext\")\n\t}\n\n\treturn gcm.Open(nil,\n\t\tciphertext[:gcm.NonceSize()],\n\t\tciphertext[gcm.NonceSize():],\n\t\tnil,\n\t)\n}\n\n// Creates a backup file in the given path\nfunc MarshalBackup(path string, b *Backup) error {\n\tjsonData, err := json.Marshal(b)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tobfuscatedBackup, err := obfuscate(jsonData)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = ioutil.WriteFile(path, obfuscatedBackup, 0644)\n\treturn err\n}\n\n// Reads a file in the given path and returns a Backup object\nfunc UnmarshalBackup(path string) (*Backup, error) {\n\tobfuscatedBackup, err := ioutil.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tjsonData, err := deobfuscate(obfuscatedBackup)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar result Backup\n\terr = json.Unmarshal(jsonData, &result)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &result, nil\n}\n"
  },
  {
    "path": "core/component.go",
    "content": "package core\n\n// Component represents core application components. Modules should implement this interface to allow for proper\n// dependency checks and shutdown\ntype Component interface {\n\tShutdown() error\n}\n\n// AsyncComponent represents components that have some async initialization\n// and therefore must provide a ready channel to listen to\ntype AsyncComponent interface {\n\tComponent\n\tWaitForReady() chan bool\n}\n"
  },
  {
    "path": "core/env/env.go",
    "content": "package env\n\nimport (\n\tsyslog \"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nconst (\n\tSpaceWorkingDir      = \"SPACE_APP_DIR\"\n\tLogLevel             = \"LOG_LEVEL\"\n\tIpfsAddr             = \"IPFS_ADDR\"\n\tIpfsNode             = \"IPFS_NODE\"\n\tIpfsNodeAddr         = \"IPFS_NODE_ADDR\"\n\tIpfsNodePath         = \"IPFS_NODE_PATH\"\n\tServicesAPIURL       = \"SERVICES_API_URL\"\n\tVaultAPIURL          = \"VAULT_API_URL\"\n\tVaultSaltSecret      = \"VAULT_SALT_SECRET\"\n\tServicesHubAuthURL   = \"SERVICES_HUB_AUTH_URL\"\n\tSpaceStorageSiteUrl  = \"SPACE_STORAGE_SITE_URL\"\n\tTextileHubTarget     = \"TXL_HUB_TARGET\"\n\tTextileHubMa         = \"TXL_HUB_MA\"\n\tTextileThreadsTarget = \"TXL_THREADS_TARGET\"\n\tTextileHubGatewayUrl = \"TXL_HUB_GATEWAY_URL\"\n\tTextileUserKey       = \"TXL_USER_KEY\"\n\tTextileUserSecret    = \"TXL_USER_SECRET\"\n)\n\ntype SpaceEnv interface {\n\tCurrentFolder() (string, error)\n\tWorkingFolder() string\n\tLogLevel() string\n}\n\ntype defaultEnv struct {\n}\n\nfunc (d defaultEnv) CurrentFolder() (string, error) {\n\tpath, err := os.Executable()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpathSegments := strings.Split(path, \"/\")\n\twd := strings.Join(pathSegments[:len(pathSegments)-1], \"/\")\n\n\treturn wd, nil\n}\n\nfunc (d defaultEnv) WorkingFolder() string {\n\tcf, err := d.CurrentFolder()\n\tif err != nil {\n\t\tsyslog.Fatal(\"unable to get working folder\", err)\n\t\tpanic(err)\n\t}\n\treturn cf\n}\n\nfunc (d defaultEnv) LogLevel() string {\n\treturn \"Info\"\n}\n\n// TODO: use this one after figuring textile keys\nfunc NewDefault() SpaceEnv {\n\treturn defaultEnv{}\n}\n"
  },
  {
    "path": "core/env/file_env.go",
    "content": "package env\n\nimport (\n\tsyslog \"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/joho/godotenv\"\n)\n\ntype spaceEnv struct {\n}\n\n// Loads environment from .env file for dev mode\nfunc New() SpaceEnv {\n\terr := godotenv.Load()\n\tif err != nil {\n\t\tsyslog.Println(\"Error loading .env file. Using defaults\")\n\t}\n\n\treturn spaceEnv{}\n}\n\nfunc (s spaceEnv) CurrentFolder() (string, error) {\n\tpath, err := os.Executable()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpathSegments := strings.Split(path, \"/\")\n\twd := strings.Join(pathSegments[:len(pathSegments)-1], \"/\")\n\n\treturn wd, nil\n}\n\nfunc (s spaceEnv) WorkingFolder() string {\n\tvar wd = os.Getenv(SpaceWorkingDir)\n\t// use default\n\tif wd == \"\" {\n\t\tcf, err := s.CurrentFolder()\n\t\tif err != nil {\n\t\t\tsyslog.Fatal(\"unable to get working folder\", err)\n\t\t\tpanic(err)\n\t\t}\n\t\twd = cf\n\t}\n\n\treturn wd\n}\n\nfunc (s spaceEnv) LogLevel() string {\n\tvar ll = os.Getenv(LogLevel)\n\n\tif ll == \"\" {\n\t\treturn \"Info\"\n\t}\n\n\treturn ll\n}\n"
  },
  {
    "path": "core/events/events.go",
    "content": "package events\n\nimport \"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n// These file defines events that daemon can propagate through all layers\n\ntype FileEventType string\n\nconst (\n\tFileAdded            FileEventType = \"FileAdded\"\n\tFileDeleted          FileEventType = \"FileDeleted\"\n\tFileUpdated          FileEventType = \"FileUpdated\"\n\tFileBackupInProgress FileEventType = \"FileBackupInProgress\"\n\tFileBackupReady      FileEventType = \"FileBackupReady\"\n\n\tFileRestored  FileEventType = \"FileRestored\"\n\tFileRestoring FileEventType = \"FileRestoring\"\n\n\tFolderAdded   FileEventType = \"FolderAdded\"\n\tFolderDeleted FileEventType = \"FolderDeleted\"\n\t// NOTE: not sure if this needs to be specific to rename or copy\n\tFolderUpdated FileEventType = \"FolderUpdated\"\n)\n\ntype FileEvent struct {\n\tInfo   domain.FileInfo\n\tType   FileEventType\n\tBucket string\n\tDbID   string\n}\n\nfunc NewFileEvent(info domain.FileInfo, eventType FileEventType, bucket, dbID string) FileEvent {\n\treturn FileEvent{\n\t\tInfo:   info,\n\t\tType:   eventType,\n\t\tBucket: bucket,\n\t\tDbID:   dbID,\n\t}\n}\n\ntype TextileEvent struct {\n\tBucketName string\n}\n\nfunc NewTextileEvent(bucketname string) TextileEvent {\n\treturn TextileEvent{\n\t\tBucketName: bucketname,\n\t}\n}\n\ntype InvitationStatus int\n\nconst (\n\tPending InvitationStatus = 0\n\tAccepted\n\tRejected\n)\n\ntype NotificationType int\n\nconst (\n\tInvitationType NotificationType = 0\n)\n\ntype Invitation struct {\n\tInviterPublicKey string\n\tInvitationID     string\n\tStatus           InvitationStatus\n\tItemPaths        []string\n}\n\ntype NotificationEvent struct {\n\tSubject       string\n\tBody          string\n\tRelatedObject interface{}\n\tType          NotificationType\n\tCreatedAt     int64\n\tReadAt        int64\n}\n"
  },
  {
    "path": "core/fsds/config.go",
    "content": "package fsds\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space\"\n)\n\nvar DefaultBucketName = \"personal\"\n\ntype dataSourceConfig struct {\n\ttlfSources []*TLFDataSource\n}\n\ntype FSDataSourceConfig func(config *dataSourceConfig)\n\nfunc WithTLFDataSource(source *TLFDataSource) FSDataSourceConfig {\n\treturn func(config *dataSourceConfig) {\n\t\tconfig.tlfSources = append(config.tlfSources, source)\n\t}\n}\n\n// Configure the default 'Files` data source to be included as a data source\nfunc WithFilesDataSources(service space.Service) FSDataSourceConfig {\n\tbasePath := fmt.Sprintf(\"%cFiles\", os.PathSeparator)\n\treturn WithTLFDataSource(&TLFDataSource{\n\t\tname:         \"Files\",\n\t\tbasePath:     basePath,\n\t\tFSDataSource: &filesDataSource{service: service},\n\t})\n}\n\n// Configure the default 'Shared With Me` data source to be included as a data source\nfunc WithSharedWithMeDataSources(service space.Service) FSDataSourceConfig {\n\tbasePath := fmt.Sprintf(\"%cShared With Me\", os.PathSeparator)\n\treturn WithTLFDataSource(&TLFDataSource{\n\t\tname:     \"Shared With Me\",\n\t\tbasePath: basePath,\n\t\tFSDataSource: &sharedWithMeDataSource{\n\t\t\tservice:     service,\n\t\t\tmaxDirLimit: 1000,\n\t\t\tcache:       make(map[string]*sharedFileEntry),\n\t\t},\n\t})\n}\n\nvar blackListedDirEntryNames = map[string]bool{\n\t// OSX specific special directories\n\t\".Trashes\":              true,\n\t\".localized\":            true,\n\t\".fseventsd\":            true,\n\t\".ql_disablethumbnails\": true,\n\t\".ql_disablecache\":      true,\n\t// special space empty directory file\n\t\".keep\": true,\n}\n"
  },
  {
    "path": "core/fsds/data_source.go",
    "content": "package fsds\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// FileReadWriterCloser implements interfaces to read, copy, seek and close.\ntype FileReadWriterCloser interface {\n\tRead(ctx context.Context, data []byte, offset int64) (int, error)\n\tWrite(ctx context.Context, data []byte, offset int64) (int, error)\n\tClose(ctx context.Context) error\n\tStats(ctx context.Context) (*DirEntry, error)\n\tTruncate(ctx context.Context, size uint64) error\n}\n\n// FSDataSource is data source of file/directories and their information\n// It is used as a local/remote cache for looking up information about the directories.\n// It should also ensure that the user in the context has permission to data that is being request\ntype FSDataSource interface {\n\t// Get a single node, this can be called on either a file or folder entry\n\t// This is typically used by the OS for lookup of the information about the entry at path\n\tGet(ctx context.Context, path string) (*DirEntry, error)\n\t// GetChildren returns child entries in the directory/folder\n\tGetChildren(ctx context.Context, path string) ([]*DirEntry, error)\n\t// OpenReader returns a file reader\n\tOpen(ctx context.Context, path string) (FileReadWriterCloser, error)\n\t// CreateEntry should create a directory or file based on the mode at the path\n\tCreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error)\n\t// RenameEntry should rename the directory entry from old to new\n\tRenameEntry(ctx context.Context, oldPath, newPath string) error\n\t// DeleteEntry should delete the item at the path\n\tDeleteEntry(ctx context.Context, path string) error\n}\n\n// TLFDataSource represents a data source handler for a particular top level file.\ntype TLFDataSource struct {\n\tname     string\n\tbasePath string\n\tFSDataSource\n}\n\n// Returns child path inside data source\nfunc (t *TLFDataSource) ChildPath(path string) string {\n\treturn strings.TrimPrefix(path, t.basePath)\n}\n\n// returns the path with the datasource base path prefixed\nfunc (t *TLFDataSource) ParentPath(path string) string {\n\treturn filepath.Join(t.basePath, path)\n}\n"
  },
  {
    "path": "core/fsds/dir_entry.go",
    "content": "package fsds\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\nvar StandardFileAccessMode os.FileMode = 0777   // -rw-------\nvar StandardDirAccessMode = os.ModeDir | 0777   //0700   // drwx------\nvar RestrictedDirAccessMode = os.ModeDir | 0500 // dr-x------ only allow reading and opening directory for user\n\n// DirEntry implements the DirEntryOps\ntype DirEntry struct {\n\tentry domain.DirEntry\n\tmode  os.FileMode\n\tdbId  string\n}\n\nfunc NewDirEntry(entry domain.DirEntry) *DirEntry {\n\treturn NewDirEntryWithMode(entry, 0)\n}\n\nfunc NewDirEntryFromFileInfo(info os.FileInfo, path string) *DirEntry {\n\treturn &DirEntry{\n\t\tentry: domain.DirEntry{\n\t\t\tPath:          filepath.Dir(path),\n\t\t\tIsDir:         info.IsDir(),\n\t\t\tName:          filepath.Base(path),\n\t\t\tSizeInBytes:   fmt.Sprintf(\"%d\", info.Size()),\n\t\t\tCreated:       info.ModTime().Format(time.RFC3339),\n\t\t\tUpdated:       info.ModTime().Format(time.RFC3339),\n\t\t\tFileExtension: filepath.Ext(path),\n\t\t},\n\t\tmode: StandardFileAccessMode,\n\t\tdbId: \"\",\n\t}\n}\n\nfunc NewDirEntryWithMode(entry domain.DirEntry, mode os.FileMode) *DirEntry {\n\treturn &DirEntry{\n\t\tentry: entry,\n\t\tmode:  mode,\n\t}\n}\n\nfunc (d *DirEntry) Path() string {\n\tif d.IsDir() {\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s%c\",\n\t\t\tstrings.TrimRight(d.entry.Path, fmt.Sprintf(\"%c\", os.PathSeparator)),\n\t\t\tos.PathSeparator,\n\t\t)\n\t}\n\n\treturn d.entry.Path\n}\n\n// IsDir implement DirEntryAttribute\n// And returns if the directory is a boolean or not\nfunc (d *DirEntry) IsDir() bool {\n\treturn d.entry.IsDir\n}\n\n// Name implements the DirEntryAttribute Interface\nfunc (d *DirEntry) Name() string {\n\treturn d.entry.Name\n}\n\n// Size implements the DirEntryAttribute Interface and return the size of the item\nfunc (d *DirEntry) Size() uint64 {\n\tintSize, err := strconv.ParseUint(d.entry.SizeInBytes, 10, 64)\n\tif err != nil {\n\t\tlog.Error(\"Error getting direntry size\", err)\n\t\t// error, so returning 0 in the meantime\n\t\treturn 0\n\t}\n\treturn intSize\n}\n\n// Mode implements the DirEntryAttribute Interface\n// Currently if it is a file, returns all access permission 0766\n// but ideally should restrict the permission if owner is not the same as file\nfunc (d *DirEntry) Mode() os.FileMode {\n\tif d.mode != 0 {\n\t\treturn d.mode\n\t}\n\n\tif d.IsDir() {\n\t\treturn StandardDirAccessMode\n\t}\n\n\treturn StandardFileAccessMode\n}\n\nfunc (d *DirEntry) Uid() uint32 {\n\t// for now return id of currently logged in user\n\treturn uint32(os.Getuid())\n}\n\nfunc (d *DirEntry) Gid() uint32 {\n\treturn uint32(os.Getgid())\n}\n\n// Ctime implements the DirEntryAttribute Interface\n// It returns the time the directory was created\nfunc (d *DirEntry) Ctime() time.Time {\n\tt, err := time.Parse(time.RFC3339, d.entry.Created)\n\n\tif err != nil {\n\t\tlog.Error(\"Error parsing direntry created time\", err)\n\t\treturn time.Time{}\n\t}\n\n\treturn t\n}\n\n// ModTime returns the modification time\nfunc (d *DirEntry) ModTime() time.Time {\n\tt, err := time.Parse(time.RFC3339, d.entry.Updated)\n\n\tif err != nil {\n\t\tlog.Error(\"Error parsing direntry updated time\", err)\n\t\treturn time.Time{}\n\t}\n\n\treturn t\n}\n"
  },
  {
    "path": "core/fsds/files_ds.go",
    "content": "package fsds\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\n// Provides content for the 'Files' content managed by the space user\n// Requests for items in this path are dispatched to this datasource from SpaceFSDataSource\ntype filesDataSource struct {\n\tservice space.Service\n}\n\n// Maybe consider caching at the level of SpaceFSDataSource when results are returned from top level file\nfunc (f *filesDataSource) Get(ctx context.Context, path string) (*DirEntry, error) {\n\tbaseName := filepath.Base(path)\n\tif isBaseDirectory(path) || path == \"\" {\n\t\treturn NewDirEntryWithMode(domain.DirEntry{\n\t\t\tPath:    path,\n\t\t\tIsDir:   true,\n\t\t\tName:    baseName,\n\t\t\tCreated: time.Now().Format(time.RFC3339),\n\t\t\tUpdated: time.Now().Format(time.RFC3339),\n\t\t}, RestrictedDirAccessMode), nil\n\t}\n\n\tlog.Debug(\"FileDS Get\", fmt.Sprintf(\"path:%s\", path))\n\n\titemsInParent, err := f.service.ListDir(ctx, path, DefaultBucketName, true)\n\tif err != nil {\n\t\tif !isNotExistError(err) {\n\t\t\treturn nil, EntryNotFound\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\t// If space service.ListDir on path is empty, then it is a file\n\t// if it is not empty, then it is a directory\n\tif len(itemsInParent) != 0 {\n\t\t// is a directory because space directory cannot be empty (must at least contain a .keep file)\n\t\treturn NewDirEntry(domain.DirEntry{\n\t\t\tPath:    path,\n\t\t\tIsDir:   true,\n\t\t\tName:    baseName,\n\t\t\tCreated: time.Now().Format(time.RFC3339),\n\t\t\tUpdated: time.Now().Format(time.RFC3339),\n\t\t}), nil\n\t}\n\n\t// OpenFile to get Size information of file\n\t// TODO: Verify service.OpenFile() logic to ensure that multiple open file doesn't recreate multiple local copies for the same file without cleanup\n\tr, err := f.service.OpenFile(ctx, path, DefaultBucketName, \"\")\n\tif err != nil {\n\t\t//if isNotExistError(err) {\n\t\treturn nil, EntryNotFound\n\t\t//}\n\t}\n\n\tfileStat, err := os.Stat(r.Location)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t//is a file, so return file entry\n\treturn NewDirEntry(domain.DirEntry{\n\t\tPath:          path,\n\t\tIsDir:         false,\n\t\tName:          baseName,\n\t\tSizeInBytes:   fmt.Sprintf(\"%d\", fileStat.Size()),\n\t\tCreated:       time.Now().Format(time.RFC3339),\n\t\tUpdated:       time.Now().Format(time.RFC3339),\n\t\tFileExtension: filepath.Ext(path),\n\t}), nil\n}\n\nfunc (f *filesDataSource) GetChildren(ctx context.Context, path string) ([]*DirEntry, error) {\n\tlog.Debug(\"FileDS GetChildren\", fmt.Sprintf(\"path:%s\", path))\n\tdomainEntries, err := f.service.ListDir(ctx, path, DefaultBucketName, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdirEntries := make([]*DirEntry, len(domainEntries))\n\tfor i, domainEntries := range domainEntries {\n\t\tdirEntries[i] = NewDirEntry(domainEntries.DirEntry)\n\t}\n\n\treturn dirEntries, nil\n}\n\nfunc (f *filesDataSource) Open(ctx context.Context, path string) (FileReadWriterCloser, error) {\n\tlog.Debug(\"FileDS Open\", fmt.Sprintf(\"path:%s\", path))\n\topenFileInfo, err := f.service.OpenFile(ctx, path, DefaultBucketName, \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn OpenSpaceFilesHandler(f.service, openFileInfo.Location, path, DefaultBucketName), nil\n}\n\n// Create the entry at the specified path and return a DirEntry representing it.\n// The DirEntry would be used to write/copy the items necessary at the point\nfunc (f *filesDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error) {\n\tlog.Debug(\"FileDS CreateEntry\", fmt.Sprintf(\"path:%s\", path), fmt.Sprintf(\"mode:%v\", mode))\n\tentryName := filepath.Base(path)\n\tparentDir := filepath.Dir(path)\n\n\tif mode.IsDir() {\n\t\terr := f.service.CreateFolder(ctx, path, DefaultBucketName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn NewDirEntry(domain.DirEntry{\n\t\t\tPath:    path,\n\t\t\tIsDir:   true,\n\t\t\tName:    entryName,\n\t\t\tCreated: time.Now().Format(time.RFC3339),\n\t\t\tUpdated: time.Now().Format(time.RFC3339),\n\t\t}), nil\n\t}\n\n\t// create an empty file to uploaded to the specified path\n\tnewFilePath := filepath.Join(os.TempDir(), path)\n\t_ = os.MkdirAll(filepath.Dir(newFilePath), os.ModePerm)\n\terr := ioutil.WriteFile(newFilePath, []byte{}, mode)\n\tif err != nil {\n\t\tlog.Error(\"Error creating empty file\", err, \"newFilePath:\"+newFilePath)\n\t\treturn nil, err\n\t}\n\n\twaitChan, _, err := f.service.AddItems(\n\t\tctx,\n\t\t[]string{\n\t\t\tnewFilePath,\n\t\t},\n\t\tparentDir,\n\t\tDefaultBucketName,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tr := <-waitChan\n\tif r.Error != nil {\n\t\tlog.Error(\"FileDS Failed to upload file\", r.Error)\n\t\treturn nil, err\n\t}\n\n\treturn NewDirEntry(domain.DirEntry{\n\t\tPath:    path,\n\t\tIsDir:   false,\n\t\tName:    entryName,\n\t\tCreated: time.Now().Format(time.RFC3339),\n\t\tUpdated: time.Now().Format(time.RFC3339),\n\t}), nil\n}\n\n// RenameEntry for now only supports renaming of empty folders\n// Depending on user request and textile support, non-empty folders and file renames will be supported\nfunc (f *filesDataSource) RenameEntry(ctx context.Context, oldPath, newPath string) error {\n\tlog.Debug(\"FileDS RenameEntry\", \"oldPath:\"+oldPath, \"newPath:\"+newPath)\n\tentry, err := f.Get(ctx, oldPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !entry.IsDir() {\n\t\tlog.Warn(\"FileDS trying to rename an entry that is not a directory\")\n\t\treturn syscall.ENOTSUP\n\t}\n\n\tchildEntries, err := f.GetChildren(ctx, oldPath)\n\tif err != nil {\n\t\tlog.Error(\"failed to get children of old path\", err, \"oldPath:\"+oldPath)\n\t\treturn err\n\t}\n\n\tif len(childEntries) != 0 && !areAllEntriesHidden(childEntries) {\n\t\tlog.Warn(\"FileDS renaming directory that is not empty\")\n\t\t// folder is not empty, so just error out\n\t\treturn syscall.ENOTSUP\n\t\t// in the future, we should do a recursive copy to the newPath and then delete old path\n\t}\n\n\tif err = f.service.CreateFolder(ctx, newPath, DefaultBucketName); err != nil {\n\t\tlog.Error(\"failed to new path create folder\", err, \"newPath:\"+newPath)\n\t\treturn syscall.ENOTSUP\n\t}\n\n\treturn f.service.RemoveDirOrFile(ctx, oldPath, DefaultBucketName)\n}\n\nfunc areAllEntriesHidden(entries []*DirEntry) bool {\n\tfor _, entry := range entries {\n\t\tbaseName := filepath.Base(entry.Name())\n\t\tif !blackListedDirEntryNames[baseName] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (f *filesDataSource) DeleteEntry(ctx context.Context, path string) error {\n\tlog.Debug(\"FileDS DeletEntry\", \"path:\"+path)\n\treturn f.service.RemoveDirOrFile(ctx, path, DefaultBucketName)\n}\n"
  },
  {
    "path": "core/fsds/read_write_wrapper.go",
    "content": "package fsds\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\n// Wrapper around space files read and write logic.\n// On close, it pushes changes to space.Service\ntype SpaceFilesHandler struct {\n\tservice       SyncService\n\tlocalFile     *os.File\n\tlocalFilePath string\n\tremotePath    string\n\tbucketName    string\n\teditted       bool\n}\n\ntype SyncService interface {\n\tAddItemWithReader(ctx context.Context, reader io.Reader, targetPath, bucketName string) (domain.AddItemResult, error)\n}\n\nfunc OpenSpaceFilesHandler(\n\tservice SyncService,\n\tlocalFilePath,\n\tremoteFilePath,\n\tbucketName string,\n) *SpaceFilesHandler {\n\treturn &SpaceFilesHandler{\n\t\tservice:       service,\n\t\tlocalFilePath: localFilePath,\n\t\tlocalFile:     nil,\n\t\tremotePath:    remoteFilePath,\n\t\tbucketName:    bucketName,\n\t\teditted:       false,\n\t}\n}\n\nfunc (s *SpaceFilesHandler) Read(ctx context.Context, b []byte, offset int64) (int, error) {\n\tlog.Debug(\n\t\t\"Reading bytes from file handler\",\n\t\t\"path:\"+s.remotePath,\n\t\t\"bucket:\"+s.bucketName,\n\t\tfmt.Sprintf(\"offset:%d\", offset),\n\t)\n\ts.openLocalFile()\n\n\t_, err := s.localFile.Seek(offset, io.SeekStart)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn s.localFile.Read(b)\n}\n\nfunc (s *SpaceFilesHandler) Write(ctx context.Context, b []byte, offset int64) (int, error) {\n\tlog.Debug(\n\t\t\"Writing bytes to file handler\",\n\t\t\"path:\"+s.remotePath,\n\t\t\"bucket:\"+s.bucketName,\n\t\tfmt.Sprintf(\"offset:%d\", offset),\n\t)\n\ts.openLocalFile()\n\n\t_, err := s.localFile.Seek(offset, io.SeekStart)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tn, err := s.localFile.Write(b)\n\tif err == nil {\n\t\ts.editted = true\n\t}\n\treturn n, err\n}\n\nfunc (s *SpaceFilesHandler) Close(ctx context.Context) error {\n\tlog.Debug(\"Closing access to SpaceFileHandler\", \"remotePath:\"+s.remotePath, \"localPath:\"+s.localFilePath)\n\tdefer func() {\n\t\tif s.localFile != nil {\n\t\t\t// background synchronizer should handle sync on close\n\t\t\ts.localFile.Close()\n\t\t\ts.localFile = nil\n\t\t}\n\t}()\n\n\t//if s.editted && s.localFile != nil {\n\t//\t_, err := s.localFile.Seek(0, 0)\n\t//\tif err != nil {\n\t//\t\tlog.Error(\"Error seeking local file to beginning for upload\", err)\n\t//\t\treturn err\n\t//\t}\n\t//\n\t//\t_, err = s.service.AddItemWithReader(\n\t//\t\tctx,\n\t//\t\ts.localFile,\n\t//\t\ts.remotePath,\n\t//\t\ts.bucketName,\n\t//\t)\n\t//\tif err != nil {\n\t//\t\treturn err\n\t//\t}\n\t//}\n\n\treturn nil\n}\n\n// Stats for now always reads stats from local file\nfunc (s *SpaceFilesHandler) Stats(ctx context.Context) (*DirEntry, error) {\n\ts.openLocalFile()\n\tinfo, err := os.Stat(s.localFilePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewDirEntryFromFileInfo(info, s.remotePath), nil\n}\n\nfunc (s *SpaceFilesHandler) Truncate(ctx context.Context, size uint64) error {\n\ts.openLocalFile()\n\treturn s.localFile.Truncate(int64(size))\n}\n\nfunc (s *SpaceFilesHandler) openLocalFile() {\n\tif s.localFile != nil {\n\t\treturn\n\t}\n\n\ts.localFile, _ = os.OpenFile(s.localFilePath, os.O_APPEND|os.O_RDWR, os.ModeAppend)\n}\n"
  },
  {
    "path": "core/fsds/shared_with_me_ds.go",
    "content": "package fsds\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\ntype sharedFileEntry struct {\n\tentry  *DirEntry\n\tdbId   string\n\tbucket string\n}\n\n// Provides content for the 'Shared With Me' content managed by the space user\n// Requests for items in this path are dispatched to this datasource from SpaceFSDataSource\ntype sharedWithMeDataSource struct {\n\tservice     space.Service\n\tmaxDirLimit int\n\tcache       map[string]*sharedFileEntry\n}\n\n// Maybe consider caching at the level of SpaceFSDataSource when results are returned from top level file\nfunc (f *sharedWithMeDataSource) Get(ctx context.Context, path string) (*DirEntry, error) {\n\tbaseName := filepath.Base(path)\n\n\tif isBaseDirectory(path) || path == \"\" {\n\t\t// return parent directory info\n\t\treturn NewDirEntryWithMode(domain.DirEntry{\n\t\t\tPath:    path,\n\t\t\tIsDir:   true,\n\t\t\tName:    baseName,\n\t\t\tCreated: time.Now().Format(time.RFC3339),\n\t\t\tUpdated: time.Now().Format(time.RFC3339),\n\t\t}, RestrictedDirAccessMode), nil\n\t}\n\tlog.Debug(\"SharedWithMeDS Get\", fmt.Sprintf(\"path:%s\", path))\n\n\t// check cache if Item is already there\n\tentry, exists := f.cache[path]\n\tif exists {\n\t\treturn entry.entry, nil\n\t}\n\n\titemsInParent, _, err := f.service.GetSharedWithMeFiles(ctx, \"\", f.maxDirLimit)\n\tif err != nil {\n\t\tif !isNotExistError(err) {\n\t\t\treturn nil, EntryNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tf.cacheResults(itemsInParent)\n\n\t// find item matching path\n\tfor _, entry := range itemsInParent {\n\t\tif entry.Path == path {\n\t\t\treturn NewDirEntry(entry.DirEntry), nil\n\t\t}\n\t}\n\n\treturn nil, EntryNotFound\n}\n\n// GetChildren should only be called on the parent folder and will always return\nfunc (f *sharedWithMeDataSource) GetChildren(ctx context.Context, path string) ([]*DirEntry, error) {\n\tlog.Debug(\"SharedWithMeDS GetChildren\", fmt.Sprintf(\"path:%s\", path))\n\tif !isBaseDirectory(path) && path != \"\" {\n\t\t// just return empty directory since shared with me currently only supports files\n\t\treturn []*DirEntry{}, nil\n\t}\n\n\tentries, _, err := f.service.GetSharedWithMeFiles(ctx, \"\", f.maxDirLimit)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// this ensure it always refreshes the cache whenever operating system calls list directory\n\tf.cacheResults(entries)\n\n\tdirEntries := make([]*DirEntry, len(entries))\n\tfor i, entry := range entries {\n\t\tdirEntries[i] = NewDirEntry(entry.DirEntry)\n\t}\n\n\treturn dirEntries, nil\n}\n\nfunc (f *sharedWithMeDataSource) Open(ctx context.Context, path string) (FileReadWriterCloser, error) {\n\tlog.Debug(\"SharedWithMeDS Open\", fmt.Sprintf(\"path:%s\", path))\n\tentry, exists := f.cache[path]\n\tif !exists {\n\t\treturn nil, EntryNotFound\n\t}\n\n\topenFileInfo, err := f.service.OpenFile(ctx, path, entry.bucket, entry.dbId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn OpenSpaceFilesHandler(f.service, openFileInfo.Location, path, entry.bucket), nil\n}\n\n// CreateEntry is not supported for shared with me files.\nfunc (f *sharedWithMeDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error) {\n\t// not allowed so just return error\n\treturn nil, syscall.ENOTSUP\n}\n\nfunc (f *sharedWithMeDataSource) RenameEntry(ctx context.Context, oldPath, newPath string) error {\n\t// Renaming items in the shared directory is not supported\n\treturn syscall.ENOTSUP\n}\n\nfunc (f *sharedWithMeDataSource) DeleteEntry(ctx context.Context, path string) error {\n\t// Deleting items in the shared directory is not supported\n\treturn syscall.ENOTSUP\n}\n\nfunc (f *sharedWithMeDataSource) cacheResults(items []*domain.SharedDirEntry) {\n\tfor _, item := range items {\n\t\tf.cache[item.Path] = &sharedFileEntry{\n\t\t\tentry:  NewDirEntryWithMode(item.DirEntry, StandardFileAccessMode),\n\t\t\tdbId:   item.DbID,\n\t\t\tbucket: item.Bucket,\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "core/fsds/spacefs.go",
    "content": "package fsds\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space\"\n)\n\n// EntryNotFound error when a directory is not found\nvar EntryNotFound = syscall.ENOENT // errors.New(\"Directory entry not found\")\nvar baseDir = NewDirEntryWithMode(\n\tdomain.DirEntry{\n\t\tPath:  \"/\",\n\t\tIsDir: true,\n\t\tName:  \"\",\n\t},\n\tRestrictedDirAccessMode,\n)\n\n// SpaceFSDataSource is an implementation of the FSDataSource\n// It interacts with the Space Service Layer to provide data\ntype SpaceFSDataSource struct {\n\tservice    space.Service\n\ttlfSources []*TLFDataSource\n\t// temp cache to speed up node fetching interactions\n\t// TODO: handle cache invalidation\n\tentryCache map[string]*DirEntry\n}\n\nfunc NewSpaceFSDataSource(service space.Service, configOptions ...FSDataSourceConfig) *SpaceFSDataSource {\n\tconfig := dataSourceConfig{}\n\tfor _, configure := range configOptions {\n\t\tconfigure(&config)\n\t}\n\n\treturn &SpaceFSDataSource{\n\t\tservice:    service,\n\t\ttlfSources: config.tlfSources,\n\t\tentryCache: make(map[string]*DirEntry),\n\t}\n}\n\n// Get returns the DirEntry information for item at path\nfunc (d *SpaceFSDataSource) Get(ctx context.Context, path string) (*DirEntry, error) {\n\t//log.Debug(\"FSDS.Get\", \"path:\"+path)\n\tbaseName := filepath.Base(path)\n\tif blackListedDirEntryNames[baseName] {\n\t\treturn nil, EntryNotFound\n\t}\n\n\t// handle quick lookup of home directory\n\tif isBaseDirectory(path) {\n\t\treturn baseDir, nil\n\t}\n\n\t// cache get results\n\tif entry, exists := d.entryCache[path]; exists {\n\t\treturn entry, nil\n\t}\n\n\tdataSource := d.findTLFDataSource(path)\n\tif dataSource == nil {\n\t\treturn nil, EntryNotFound\n\t}\n\n\tresult, err := dataSource.Get(ctx, dataSource.ChildPath(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult.entry.Path = dataSource.ParentPath(result.entry.Path)\n\td.entryCache[path] = result\n\n\treturn result, nil\n}\n\nfunc (d *SpaceFSDataSource) findTLFDataSource(path string) *TLFDataSource {\n\tfor _, i := range d.tlfSources {\n\t\tif strings.HasPrefix(path, i.basePath) {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// GetChildren returns list of entries in a path\nfunc (d *SpaceFSDataSource) GetChildren(ctx context.Context, path string) ([]*DirEntry, error) {\n\t//log.Debug(\"FSDS.GetChildren\", \"path:\"+path)\n\tbaseName := filepath.Base(path)\n\tif blackListedDirEntryNames[baseName] {\n\t\treturn nil, EntryNotFound\n\t}\n\tif isBaseDirectory(path) {\n\t\treturn d.getTopLevelDirectories(), nil\n\t}\n\n\tdataSource := d.findTLFDataSource(path)\n\tif dataSource == nil {\n\t\treturn nil, EntryNotFound\n\t}\n\n\tresult, err := dataSource.GetChildren(ctx, dataSource.ChildPath(path))\n\n\t// format results\n\tif result != nil {\n\t\tfor _, entry := range result {\n\t\t\tentry.entry.Path = dataSource.ParentPath(entry.entry.Path)\n\t\t\td.entryCache[entry.entry.Path] = entry\n\t\t}\n\t}\n\n\treturn result, err\n}\n\n// Open is invoked to read the content of a file\nfunc (d *SpaceFSDataSource) Open(ctx context.Context, path string) (FileReadWriterCloser, error) {\n\t//log.Debug(\"FSDS.Open\", \"path:\"+path)\n\tdataSource := d.findTLFDataSource(path)\n\tif dataSource == nil {\n\t\treturn nil, EntryNotFound\n\t}\n\n\treturn dataSource.Open(ctx, dataSource.ChildPath(path))\n}\n\n// CreateEntry creates a directory or file based on the mode at the path\nfunc (d *SpaceFSDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error) {\n\t//log.Debug(\"FSDS.CreateEntry\", \"path:\"+path)\n\tdataSource := d.findTLFDataSource(path)\n\tif dataSource == nil {\n\t\treturn nil, syscall.ENOTSUP\n\t}\n\n\tresult, err := dataSource.CreateEntry(ctx, dataSource.ChildPath(path), mode)\n\tif result != nil {\n\t\tresult.entry.Path = dataSource.ParentPath(result.entry.Path)\n\t}\n\n\treturn result, err\n}\n\nfunc (d *SpaceFSDataSource) RenameEntry(ctx context.Context, oldPath, newPath string) error {\n\t//log.Debug(\"FSDS.RenameEntry\", \"oldPath:\"+oldPath, \"newPath:\"+newPath)\n\toldPathDataSource := d.findTLFDataSource(oldPath)\n\tnewPathDataSource := d.findTLFDataSource(newPath)\n\n\tif oldPathDataSource.name != newPathDataSource.name {\n\t\t// renaming can only happen within the same datasource\n\t\treturn syscall.ENOTSUP\n\t}\n\n\treturn oldPathDataSource.RenameEntry(\n\t\tctx,\n\t\toldPathDataSource.ChildPath(oldPath),\n\t\toldPathDataSource.ChildPath(newPath),\n\t)\n}\n\nfunc (d *SpaceFSDataSource) DeleteEntry(ctx context.Context, path string) error {\n\t//log.Debug(\"FSDS.DeleteEntry\", \"path:\"+path)\n\tdataSource := d.findTLFDataSource(path)\n\n\treturn dataSource.DeleteEntry(ctx, dataSource.ChildPath(path))\n}\n\n// Returns list of top level entry\nfunc (d *SpaceFSDataSource) getTopLevelDirectories() []*DirEntry {\n\tvar directories []*DirEntry\n\n\tfor _, ds := range d.tlfSources {\n\t\tdirectories = append(directories, NewDirEntryWithMode(\n\t\t\tdomain.DirEntry{\n\t\t\t\tPath:  ds.basePath,\n\t\t\t\tIsDir: true,\n\t\t\t\tName:  ds.name,\n\t\t\t\t//Created:       \"\",\n\t\t\t\t//Updated:       \"\",\n\t\t\t},\n\t\t\tRestrictedDirAccessMode,\n\t\t))\n\t}\n\treturn directories\n}\n"
  },
  {
    "path": "core/fsds/utils.go",
    "content": "package fsds\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc isBaseDirectory(path string) bool {\n\treturn path == \"/\"\n}\n\nfunc isDirPath(path string) bool {\n\treturn strings.HasSuffix(path, fmt.Sprintf(\"%c\", os.PathSeparator))\n}\n\nfunc isNotExistError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\t// Example of current error representing file not found:\n\t// error: code = Unknown desc = no link named \".localized\" under bafybeievqvkeo2ycggt4lino45pj3olv7yo2e6sybcmyphicejsvq2vimi[]\n\tif strings.Contains(err.Error(), \"no link named\") {\n\t\treturn true\n\t}\n\n\tif strings.Contains(err.Error(), \"could not resolve path\") {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "core/ipfs/dag.go",
    "content": "package ipfs\n\nimport (\n\t\"context\"\n\t\"errors\"\n\tcid \"github.com/ipfs/go-cid\"\n\tipld \"github.com/ipfs/go-ipld-format\"\n\t\"sync\"\n)\n\nvar (\n\tErrNotFound =  errors.New(\"not found\")\n)\n\ntype mapBasedDag struct {\n\tmu    sync.Mutex\n\tnodes map[string]ipld.Node\n}\n\nfunc NewDagService() *mapBasedDag {\n\treturn &mapBasedDag{nodes: make(map[string]ipld.Node)}\n}\n\nfunc (d *mapBasedDag) Get(ctx context.Context, cid cid.Cid) (ipld.Node, error) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tif n, ok := d.nodes[cid.KeyString()]; ok {\n\t\treturn n, nil\n\t}\n\treturn nil, ErrNotFound\n}\n\nfunc (d *mapBasedDag) GetMany(ctx context.Context, cids []cid.Cid) <-chan *ipld.NodeOption {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tout := make(chan *ipld.NodeOption, len(cids))\n\tfor _, c := range cids {\n\t\tif n, ok := d.nodes[c.KeyString()]; ok {\n\t\t\tout <- &ipld.NodeOption{Node: n}\n\t\t} else {\n\t\t\tout <- &ipld.NodeOption{Err: ErrNotFound}\n\t\t}\n\t}\n\tclose(out)\n\treturn out\n}\n\nfunc (d *mapBasedDag) Add(ctx context.Context, node ipld.Node) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\td.nodes[node.Cid().KeyString()] = node\n\treturn nil\n}\n\nfunc (d *mapBasedDag) AddMany(ctx context.Context, nodes []ipld.Node) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tfor _, n := range nodes {\n\t\td.nodes[n.Cid().KeyString()] = n\n\t}\n\treturn nil\n}\n\nfunc (d *mapBasedDag) Remove(ctx context.Context, c cid.Cid) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tdelete(d.nodes, c.KeyString())\n\treturn nil\n}\n\nfunc (d *mapBasedDag) RemoveMany(ctx context.Context, cids []cid.Cid) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tfor _, c := range cids {\n\t\tdelete(d.nodes, c.KeyString())\n\t}\n\treturn nil\n}"
  },
  {
    "path": "core/ipfs/ipfs.go",
    "content": "package ipfs\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/ipfs/go-cid\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/ipfs/interface-go-ipfs-core/path\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tma \"github.com/multiformats/go-multiaddr\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\tfiles \"github.com/ipfs/go-ipfs-files\"\n\thttpapi \"github.com/ipfs/go-ipfs-http-client\"\n)\n\ntype AddItemResult struct {\n\tError    error\n\tResolved path.Resolved\n}\n\ntype LinkNodesInput struct {\n\t// name of link\n\tName string\n\tPath path.Path\n}\n\ntype LinkNodesResult struct {\n\tParentPath path.Resolved\n}\n\ntype Client interface {\n\tAddItems(ctx context.Context, items []io.Reader) []AddItemResult\n\tAddItem(ctx context.Context, item io.Reader) AddItemResult\n\t// Links each of the nodes in the input under the same parent\n\tLinkNodes(ctx context.Context, nodes []LinkNodesInput) (*LinkNodesResult, error)\n\tPullItem(ctx context.Context, cid cid.Cid) (io.ReadCloser, error)\n}\n\ntype SpaceIpfsClient struct {\n\tclient *httpapi.HttpApi\n}\n\nfunc NewSpaceIpfsClient(cfg config.Config) (*SpaceIpfsClient, error) {\n\tipfsAddr := cfg.GetString(config.Ipfsaddr, \"/ip4/127.0.0.1/tcp/5001\")\n\n\tmultiaddress, err := ma.NewMultiaddr(ipfsAddr)\n\tif err != nil {\n\t\tlog.Error(\"Unable to parse IPFS Multiaddr\", err)\n\t\treturn nil, err\n\t}\n\n\tic, err := httpapi.NewApi(multiaddress)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &SpaceIpfsClient{\n\t\tclient: ic,\n\t}, nil\n}\n\nfunc (s *SpaceIpfsClient) AddItems(ctx context.Context, items []io.Reader) []AddItemResult {\n\tresults := make([]AddItemResult, len(items))\n\twg := sync.WaitGroup{}\n\n\tfor i, item := range items {\n\t\twg.Add(1)\n\t\tgo func(i int, item io.Reader) {\n\t\t\tresolved, err := s.client.Unixfs().Add(\n\t\t\t\tctx,\n\t\t\t\tfiles.NewReaderFile(item),\n\t\t\t)\n\t\t\tresults[i] = AddItemResult{\n\t\t\t\tError:    err,\n\t\t\t\tResolved: resolved,\n\t\t\t}\n\t\t\twg.Done()\n\t\t}(i, item)\n\t}\n\n\twg.Wait()\n\treturn results\n}\n\nfunc (s *SpaceIpfsClient) AddItem(ctx context.Context, item io.Reader) AddItemResult {\n\tresult := s.AddItems(ctx, []io.Reader{item})\n\treturn result[0]\n}\n\nfunc (s *SpaceIpfsClient) LinkNodes(ctx context.Context, nodes []LinkNodesInput) (*LinkNodesResult, error) {\n\tif len(nodes) == 0 {\n\t\treturn nil, errors.New(\"no nodes passed to link nodes\")\n\t}\n\tparentNode, err := s.client.Object().New(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparentPath := path.IpfsPath(parentNode.Cid())\n\tfor _, node := range nodes {\n\t\tparentPath, err = s.client.Object().AddLink(ctx, parentPath, node.Name, node.Path)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"failed to link nodes\")\n\t\t}\n\t}\n\n\treturn &LinkNodesResult{\n\t\tParentPath: parentPath,\n\t}, nil\n}\n\nfunc (s *SpaceIpfsClient) PullItem(ctx context.Context, cid cid.Cid) (io.ReadCloser, error) {\n\tnode, err := s.client.Unixfs().Get(ctx, path.IpfsPath(cid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar file files.File\n\tswitch f := node.(type) {\n\tcase files.File:\n\t\tfile = f\n\tcase files.Directory:\n\t\treturn nil, errors.New(\"unsupported cid provided\")\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported cid provided\")\n\t}\n\n\treturn file, nil\n}\n"
  },
  {
    "path": "core/ipfs/node/node.go",
    "content": "package ipfs\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"os/user\"\n\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\ticore \"github.com/ipfs/interface-go-ipfs-core\"\n\n\tma \"github.com/multiformats/go-multiaddr\"\n\n\tipfsconfig \"github.com/ipfs/go-ipfs-config\"\n\t\"github.com/ipfs/go-ipfs/commands\"\n\t\"github.com/ipfs/go-ipfs/core\"\n\t\"github.com/ipfs/go-ipfs/core/coreapi\"\n\t\"github.com/ipfs/go-ipfs/core/corehttp\"\n\t\"github.com/ipfs/go-ipfs/core/node/libp2p\"\n\t\"github.com/ipfs/go-ipfs/plugin/loader\"\n\t\"github.com/ipfs/go-ipfs/repo/fsrepo\"\n\tcoreiface \"github.com/ipfs/interface-go-ipfs-core\"\n\t\"github.com/libp2p/go-libp2p-core/peer\"\n)\n\ntype IpfsNode struct {\n\tcoreApi  coreiface.CoreAPI\n\tcoreNode *core.IpfsNode\n\tcancel   context.CancelFunc\n\n\tIsRunning bool\n\tReady     chan bool\n\tcfg       config.Config\n}\n\nfunc NewIpsNode(cfg config.Config) *IpfsNode {\n\treturn &IpfsNode{\n\t\tReady: make(chan bool),\n\t\tcfg:   cfg,\n\t}\n}\n\nfunc (node *IpfsNode) Start(ctx context.Context) error {\n\tlog.Info(\"Starting the ipfs node\")\n\n\terr := node.start()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Info(\"Running the ipfs node\")\n\n\tnode.IsRunning = true\n\tnode.Ready <- true\n\n\treturn nil\n}\n\nfunc (node *IpfsNode) WaitForReady() chan bool {\n\treturn node.Ready\n}\n\nfunc (node *IpfsNode) Stop() error {\n\treturn node.stop()\n}\n\nfunc (node *IpfsNode) Shutdown() error {\n\tclose(node.Ready)\n\treturn node.Stop()\n}\n\nfunc (node *IpfsNode) start() error {\n\tctx, cancel := context.WithCancel(context.Background())\n\tnode.cancel = cancel\n\n\tpathRoot, err := ipfsconfig.PathRoot()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trepoPath := node.cfg.GetString(config.Ipfsnodepath, pathRoot)\n\tif repoPath == \"\" {\n\t\trepoPath = pathRoot\n\t} else {\n\t\tusr, err := user.Current()\n\t\tif err != nil {\n\t\t\trepoPath = pathRoot\n\t\t} else {\n\t\t\trepoPath = filepath.Join(usr.HomeDir, repoPath)\n\t\t}\n\t}\n\n\tif err := setupPlugins(repoPath); err != nil {\n\t\treturn err\n\t}\n\n\t// init the repo\n\trepoCfg, err := ipfsconfig.Init(ioutil.Discard, 2048)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = fsrepo.Init(repoPath, repoCfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// open the repo\n\trepo, err := fsrepo.Open(repoPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// construct the node\n\tnodeOptions := &core.BuildCfg{\n\t\tOnline:  true,\n\t\tRouting: libp2p.DHTClientOption,\n\t\tRepo:    repo,\n\t}\n\n\tnode.coreNode, err = core.NewNode(ctx, nodeOptions)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnode.coreApi, err = coreapi.NewCoreAPI(node.coreNode)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\taddr := node.cfg.GetString(config.Ipfsnodeaddr, \"/ip4/127.0.0.1/tcp/5001\")\n\tif addr == \"\" {\n\t\taddr = \"/ip4/127.0.0.1/tcp/5001\"\n\t}\n\n\tvar opts = []corehttp.ServeOption{\n\t\tcorehttp.GatewayOption(true, \"/ipfs\", \"/ipns\"),\n\t\tcorehttp.WebUIOption,\n\t\tcorehttp.CommandsOption(cmdCtx(node.coreNode, repoPath)),\n\t}\n\n\tgo func() {\n\t\tif err := corehttp.ListenAndServe(node.coreNode, addr, opts...); err != nil {\n\t\t\tlog.Error(\"Error starting api: \", err)\n\t\t\treturn\n\t\t}\n\t}()\n\n\t// TODO: better place?\n\tbootstrapNodes := []string{\n\t\t\"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN\",\n\t\t\"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa\",\n\t\t\"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb\",\n\t\t\"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt\",\n\t\t\"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ\",\n\t\t\"/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ\",\n\t}\n\n\tgo connectToPeers(ctx, node.coreApi, bootstrapNodes)\n\n\treturn nil\n}\n\nfunc (node *IpfsNode) stop() error {\n\tnode.IsRunning = false\n\n\terr := node.coreNode.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnode.cancel()\n\n\treturn nil\n}\n\nfunc connectToPeers(ctx context.Context, ipfs icore.CoreAPI, peers []string) error {\n\tvar wg sync.WaitGroup\n\tpeerInfos := make(map[peer.ID]*peer.AddrInfo, len(peers))\n\tfor _, addrStr := range peers {\n\t\taddr, err := ma.NewMultiaddr(addrStr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpii, err := peer.AddrInfosFromP2pAddrs(addr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpi, ok := peerInfos[pii[0].ID]\n\t\tif !ok {\n\t\t\tpi = &peer.AddrInfo{ID: pii[0].ID}\n\t\t\tpeerInfos[pi.ID] = pi\n\t\t}\n\t\tpi.Addrs = append(pi.Addrs, pii[0].Addrs...)\n\t}\n\n\twg.Add(len(peerInfos))\n\tfor _, peerInfo := range peerInfos {\n\t\tgo func(peerInfo *peer.AddrInfo) {\n\t\t\tdefer wg.Done()\n\t\t\terr := ipfs.Swarm().Connect(ctx, *peerInfo)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}(peerInfo)\n\t}\n\twg.Wait()\n\treturn nil\n}\n\nfunc setupPlugins(externalPluginsPath string) error {\n\t// load any external plugins if available on externalPluginsPath\n\tplugins, err := loader.NewPluginLoader(filepath.Join(externalPluginsPath, \"plugins\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error loading plugins: %s\", err)\n\t}\n\n\t// load preloaded and external plugins\n\tif err := plugins.Initialize(); err != nil {\n\t\treturn fmt.Errorf(\"error initializing plugins: %s\", err)\n\t}\n\n\tif err := plugins.Inject(); err != nil {\n\t\treturn fmt.Errorf(\"error injecting plugins: %s\", err)\n\t}\n\n\treturn nil\n}\n\nfunc cmdCtx(node *core.IpfsNode, repoPath string) commands.Context {\n\treturn commands.Context{\n\t\tConfigRoot: repoPath,\n\t\tLoadConfig: func(path string) (*ipfsconfig.Config, error) {\n\t\t\treturn node.Repo.Config()\n\t\t},\n\t\tConstructNode: func() (*core.IpfsNode, error) {\n\t\t\treturn node, nil\n\t\t},\n\t\tReqLog: &commands.ReqLog{},\n\t}\n}\n"
  },
  {
    "path": "core/ipfs/utils.go",
    "content": "package ipfs\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/ipfs/go-cid\"\n\tchunker \"github.com/ipfs/go-ipfs-chunker\"\n\tipld \"github.com/ipfs/go-ipld-format\"\n\t\"github.com/ipfs/go-merkledag\"\n\t\"github.com/ipfs/go-unixfs/importer/balanced\"\n\t\"github.com/ipfs/go-unixfs/importer/helpers\"\n\t\"github.com/ipfs/go-unixfs/importer/trickle\"\n\tmh \"github.com/multiformats/go-multihash\"\n)\n\nfunc GetFileHash(r io.Reader) (string, error) {\n\thashFun := \"sha2-256\"\n\n\tprefix, err := merkledag.PrefixForCidVersion(1)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"bad CID Version: %s\", err)\n\t}\n\n\thashFunCode, ok := mh.Names[strings.ToLower(hashFun)]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unrecognized hash function: %s\", hashFun)\n\t}\n\tprefix.MhType = hashFunCode\n\tprefix.MhLength = -1\n\tprefix.Codec = cid.DagProtobuf\n\n\tdagServ := NewDagService()\n\tdbp := helpers.DagBuilderParams{\n\t\tDagserv:    dagServ,\n\t\tRawLeaves:  true,\n\t\tMaxlinks:   helpers.DefaultLinksPerBlock,\n\t\tNoCopy:     false,\n\t\tCidBuilder: &prefix,\n\t}\n\n\tchnk, err := chunker.FromString(r, \"\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdbh, err := dbp.New(chnk)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tlayout := \"trickle\"\n\tvar n ipld.Node\n\tswitch layout {\n\tcase \"trickle\":\n\t\tn, err = trickle.Layout(dbh)\n\tcase \"balanced\", \"\":\n\t\tn, err = balanced.Layout(dbh)\n\tdefault:\n\t\treturn \"\", errors.New(\"invalid Layout\")\n\t}\n\n\treturn n.Cid().String(), nil\n\n}\n\nfunc DownloadIpfsItemViaGateway(ctx context.Context, gatewayUrl string, cid cid.Cid) (io.ReadCloser, error) {\n\turl := fmt.Sprintf(\"%s/ipfs/%s\", gatewayUrl, cid.String())\n\treq, err := http.NewRequest(http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := http.Client{}\n\n\tresp, err := client.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"failed to fetch item %s: status_code %d\", cid.String(), resp.StatusCode)\n\t}\n\n\treturn resp.Body, nil\n}\n\nfunc DownloadIpfsItem(ctx context.Context, nodeUrl string, cid cid.Cid) (io.ReadCloser, error) {\n\n\t// https://docs.ipfs.io/reference/http/api/#api-v0-cat\n\turl := fmt.Sprintf(\"http://%s/api/v0/cat?arg=%s\", nodeUrl, cid.String())\n\n\treq, err := http.NewRequest(http.MethodPost, url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := http.Client{}\n\n\tresp, err := client.Do(req.WithContext(ctx))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"failed to fetch item %s: status_code %d\", cid.String(), resp.StatusCode)\n\t}\n\n\treturn resp.Body, nil\n}\n"
  },
  {
    "path": "core/ipfs/utils_test.go",
    "content": "package ipfs\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// fleek hash: bafybeiemzcxynbrrhtcpmmdtkl42molkiyfqu3j5ewp2o7izdmomptfkgi\n\nfunc TestIpfs_GetFileHash_FromStringReader(t *testing.T) {\n\tt.Skip()\n\tr := strings.NewReader(\"IPFS test data for reader\")\n\texpectedHash := \"bafybeie4zu4wu7lexqty2aubpe36dnpd6edgb5mthhtab5hyhuju7jlcgm\"\n\n\tres, err := GetFileHash(r)\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, res)\n\tassert.Equal(t, expectedHash, res)\n}\n\n// bafybeic3jetthfk7tjmewz42idwsaeek5a7myw6n46zrrxdmp5nlkc6diy\n\nfunc TestIpfs_GetFileHash_FromFile(t *testing.T) {\n\tt.Skip()\n\tr, _ := os.Open(\"test1.txt\")\n\texpectedHash := \"bafybeie4zu4wu7lexqty2aubpe36dnpd6edgb5mthhtab5hyhuju7jlcgm\"\n\n\tres, err := GetFileHash(r)\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, res)\n\tassert.Equal(t, expectedHash, res)\n}\n\n\n"
  },
  {
    "path": "core/keychain/app_token.go",
    "content": "package keychain\n\nimport (\n\t\"errors\"\n\n\t\"github.com/99designs/keyring\"\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n)\n\nconst AppTokenStoreKey = \"appToken\"\nconst MasterAppTokenStoreKey = \"masterAppToken\"\n\nvar ErrMasterTokenAlreadyExists = errors.New(\"master app token already exists\")\n\nfunc (kc *keychain) StoreAppToken(tok *permissions.AppToken) error {\n\tring, err := kc.getKeyRing()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Prevent overriding existing master key\n\tkey, _ := kc.st.Get([]byte(getMasterTokenStKey()))\n\tif key != nil && tok.IsMaster {\n\t\treturn ErrMasterTokenAlreadyExists\n\t}\n\n\t// Prevents overriding even if user logged out and logged back in (which clears the store)\n\t_, err = ring.Get(getMasterTokenStKey())\n\tif err == nil && tok.IsMaster {\n\t\treturn ErrMasterTokenAlreadyExists\n\t}\n\n\tmarshalled, err := permissions.MarshalToken(tok)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = ring.Set(keyring.Item{\n\t\tKey:   AppTokenStoreKey + \"_\" + tok.Key,\n\t\tData:  marshalled,\n\t\tLabel: \"Space App - App Token\",\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tok.IsMaster {\n\t\tif err := kc.st.Set([]byte(getMasterTokenStKey()), []byte(tok.Key)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := ring.Set(keyring.Item{\n\t\t\tKey:   getMasterTokenStKey(),\n\t\t\tData:  marshalled,\n\t\t\tLabel: \"Space App - Master App Token\",\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (kc *keychain) GetAppToken(key string) (*permissions.AppToken, error) {\n\tring, err := kc.getKeyRing()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttoken, err := ring.Get(AppTokenStoreKey + \"_\" + key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn permissions.UnmarshalToken(token.Data)\n}\n\nfunc getMasterTokenStKey() string {\n\treturn AppTokenStoreKey + \"_\" + MasterAppTokenStoreKey\n}\n"
  },
  {
    "path": "core/keychain/keychain.go",
    "content": "package keychain\n\nimport (\n\t\"crypto/ed25519\"\n\t\"crypto/sha512\"\n\t\"encoding/hex\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\n\t\"golang.org/x/crypto/pbkdf2\"\n\n\t\"errors\"\n\n\t\"github.com/99designs/keyring\"\n\tri \"github.com/FleekHQ/space-daemon/core/keychain/keyring\"\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tsym \"github.com/textileio/go-threads/crypto/symmetric\"\n)\n\nconst PrivateKeyStoreKey = \"key\"\nconst PublicKeyStoreKey = \"pub\"\n\nconst privKeyMnemonicSeparator = \"___\"\n\nvar (\n\tErrKeyPairNotFound = errors.New(\"No key pair found in the local db.\")\n)\n\ntype keychain struct {\n\tfileDir string\n\tst      store.Store\n\tring    ri.Keyring\n\tprivKey *crypto.PrivKey\n}\n\ntype Keychain interface {\n\tGenerateKeyPair() (pub []byte, priv []byte, err error)\n\tGenerateKeyFromMnemonic(...GenerateKeyFromMnemonicOpts) (mnemonic string, err error)\n\tGetStoredKeyPairInLibP2PFormat() (crypto.PrivKey, crypto.PubKey, error)\n\tGetStoredPublicKey() (crypto.PubKey, error)\n\tGetStoredMnemonic() (string, error)\n\tGetManagedThreadKey(threadKeyName string) (thread.Key, error)\n\tGenerateKeyPairWithForce() (pub []byte, priv []byte, err error)\n\tSign([]byte) ([]byte, error)\n\tImportExistingKeyPair(priv crypto.PrivKey, mnemonic string) error\n\tDeleteKeypair() error\n\tStoreAppToken(tok *permissions.AppToken) error\n\tGetAppToken(key string) (*permissions.AppToken, error)\n}\n\ntype keychainOptions struct {\n\tfileDir string\n\tstore   store.Store\n\n\t// Don't use kc.ring directly, use getKeyRing() instead\n\tring ri.Keyring\n}\n\nvar defaultKeychainOptions = keychainOptions{\n\tfileDir: store.DefaultRootDir,\n}\n\n// Helper function for setting keychain file path for Windows/Linux\nfunc WithPath(path string) Option {\n\treturn func(o *keychainOptions) {\n\t\tif path != \"\" {\n\t\t\to.fileDir = path\n\t\t}\n\t}\n}\n\nfunc WithStore(st store.Store) Option {\n\treturn func(o *keychainOptions) {\n\t\tif st != nil {\n\t\t\to.store = st\n\t\t}\n\t}\n}\n\n// Used to inject a mock keyring in tests or in case you want to use a custom keyring implementation\nfunc WithKeyring(ring ri.Keyring) Option {\n\treturn func(o *keychainOptions) {\n\t\tif ring != nil {\n\t\t\to.ring = ring\n\t\t}\n\t}\n}\n\ntype Option func(o *keychainOptions)\n\nfunc New(opts ...Option) *keychain {\n\to := defaultKeychainOptions\n\tfor _, opt := range opts {\n\t\topt(&o)\n\t}\n\n\tif o.store == nil {\n\t\tdefaultStore := store.New(store.WithPath(o.fileDir))\n\t\to.store = defaultStore\n\t}\n\n\treturn &keychain{\n\t\tfileDir: o.fileDir,\n\t\tst:      o.store,\n\t\tring:    o.ring,\n\t}\n}\n\n// Generates a public/private key pair using ed25519 algorithm.\n// It stores it in the local db and returns the key pair key.\n// If there's already a key pair stored, it returns an error.\n// Use GenerateKeyPairWithForce if you want to override existing keys\nfunc (kc *keychain) GenerateKeyPair() ([]byte, []byte, error) {\n\tif val, _ := kc.GetStoredPublicKey(); val != nil {\n\t\tnewErr := errors.New(\"Error while executing GenerateKeyPair. Key pair already exists. Use GenerateKeyPairWithForce if you want to override it.\")\n\t\treturn nil, nil, newErr\n\t}\n\n\treturn kc.generateAndStoreKeyPair(nil, \"\")\n}\n\n// Returns the stored key pair using the same signature than libp2p's GenerateEd25519Key function\nfunc (kc *keychain) GetStoredKeyPairInLibP2PFormat() (crypto.PrivKey, crypto.PubKey, error) {\n\tvar priv []byte\n\tvar err error\n\n\t_, err = kc.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif kc.privKey != nil {\n\t\treturn *kc.privKey, (*kc.privKey).GetPublic(), nil\n\t}\n\n\tif priv, _, err = kc.retrieveKeyPair(); err != nil {\n\t\tnewErr := ErrKeyPairNotFound\n\t\treturn nil, nil, newErr\n\t}\n\n\tvar unmarshalledPriv crypto.PrivKey\n\n\tif unmarshalledPriv, err = crypto.UnmarshalEd25519PrivateKey(priv); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tkc.privKey = &unmarshalledPriv\n\n\tunmarshalledPub := unmarshalledPriv.GetPublic()\n\n\treturn unmarshalledPriv, unmarshalledPub, nil\n}\n\n// Generates a public/private key pair using ed25519 algorithm.\n// It stores it in the local db and returns the key pair.\n// Warning: If there's already a key pair stored, it overrides it.\nfunc (kc *keychain) GenerateKeyPairWithForce() ([]byte, []byte, error) {\n\treturn kc.generateAndStoreKeyPair(nil, \"\")\n}\n\n// Returns the public key currently in use in LibP2P format.\n// Returns an error if there's no public key set.\n// Unlike GetStoredKeyPairInLibP2PFormat, this method does not access the keychain\nfunc (kc *keychain) GetStoredPublicKey() (crypto.PubKey, error) {\n\tring, err := kc.getKeyRing()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t_, err = ring.GetMetadata(PrivateKeyStoreKey)\n\tif err == keyring.ErrKeyNotFound {\n\t\treturn nil, ErrKeyPairNotFound\n\t}\n\n\tpubInBytes, err := kc.st.Get([]byte(PublicKeyStoreKey))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif pubInBytes == nil {\n\t\treturn nil, ErrKeyPairNotFound\n\t}\n\n\tpub, err := crypto.UnmarshalEd25519PublicKey(pubInBytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn pub, nil\n}\n\nfunc (kc *keychain) GetStoredMnemonic() (string, error) {\n\t_, mnemonic, err := kc.retrieveKeyPair()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn mnemonic, nil\n}\n\n// Stores an existing private key in the keychain\n// Warning: If there's already a key pair stored, this will override it.\nfunc (kc *keychain) ImportExistingKeyPair(priv crypto.PrivKey, mnemonic string) error {\n\tprivInBytes, err := priv.Raw()\n\tif err != nil {\n\t\treturn err\n\t}\n\tpubInBytes, err := priv.GetPublic().Raw()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Store the key pair in the db\n\tif err := kc.storeKeyPair(privInBytes, pubInBytes, mnemonic); err != nil {\n\t\treturn err\n\t}\n\n\tkc.privKey = &priv\n\n\treturn nil\n}\n\nfunc (kc *keychain) DeleteKeypair() error {\n\tring, err := kc.getKeyRing()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Note: currently ignoring error on keychain removal because it's failing randomly.\n\t// Use GenerateKeyPair with override option instead.\n\terr = ring.Remove(PrivateKeyStoreKey)\n\n\terr = kc.st.Remove([]byte(PublicKeyStoreKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tkc.privKey = nil\n\treturn nil\n}\n\nfunc (kc *keychain) generateKeyPair(seed []byte) ([]byte, []byte, error) {\n\tif seed != nil {\n\t\tpriv := ed25519.NewKeyFromSeed(seed)\n\t\tpublicKey := priv.Public()\n\t\tpub, ok := publicKey.(ed25519.PublicKey)\n\t\tif !ok {\n\t\t\treturn nil, nil, errors.New(\"Error while generating key pair from seed\")\n\t\t}\n\t\treturn pub, priv, nil\n\t}\n\t// Compute the key from a random seed\n\tpub, priv, err := ed25519.GenerateKey(nil)\n\treturn pub, priv, err\n}\n\nfunc (kc *keychain) generateAndStoreKeyPair(seed []byte, mnemonic string) ([]byte, []byte, error) {\n\t// Compute the key from a random seed\n\tpub, priv, err := kc.generateKeyPair(seed)\n\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Store the key pair in the db\n\tif err := kc.storeKeyPair(priv, pub, mnemonic); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tprivkey, err := crypto.UnmarshalEd25519PrivateKey(priv)\n\tif err != nil {\n\t\tlog.Warn(\"Unable to cache priv key\")\n\t}\n\n\tkc.privKey = &privkey\n\n\treturn pub, priv, nil\n}\n\n// Signs a message using the stored private key.\n// Returns an error if the private key cannot be found.\nfunc (kc *keychain) Sign(message []byte) ([]byte, error) {\n\tif priv, _, err := kc.retrieveKeyPair(); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\tsignedBytes := ed25519.Sign(priv, message)\n\t\treturn signedBytes, nil\n\t}\n}\n\nfunc (kc *keychain) getKeyRing() (ri.Keyring, error) {\n\tif kc.ring != nil {\n\t\treturn kc.ring, nil\n\t}\n\n\tucd, err := os.UserConfigDir()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn keyring.Open(keyring.Config{\n\t\tServiceName: \"space\",\n\n\t\t// MacOS keychain\n\t\tKeychainTrustApplication:       true,\n\t\tKeychainAccessibleWhenUnlocked: true,\n\n\t\t// KDE Wallet\n\t\tKWalletAppID:  \"space\",\n\t\tKWalletFolder: \"space\",\n\n\t\t// Windows\n\t\tWinCredPrefix: \"space\",\n\n\t\t// freedesktop.org's Secret Service\n\t\tLibSecretCollectionName: \"space\",\n\n\t\t// Pass (https://www.passwordstore.org/)\n\t\tPassPrefix: \"space\",\n\t\tPassDir:    kc.fileDir + \"/kcpw\",\n\n\t\t// Fallback encrypted file\n\t\tFileDir: path.Join(ucd, \"space\", \"keyring\"),\n\t})\n}\n\nfunc (kc *keychain) storeKeyPair(privKey []byte, pubKey []byte, mnemonic string) error {\n\tring, err := kc.getKeyRing()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprivAsHex := hex.EncodeToString(privKey)\n\tprivWithMnemonic := privAsHex + privKeyMnemonicSeparator + mnemonic\n\n\t// Store private key together with mnemonic\n\t// Priv key is stored as 0x1234...890___some mnemonic\n\t// The idea behind storing them together is that we avoid asking for keychain access twice\n\tif err := ring.Set(keyring.Item{\n\t\tKey:   PrivateKeyStoreKey,\n\t\tData:  []byte(privWithMnemonic),\n\t\tLabel: \"Space App\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\t// Store pub key outside of the key ring for quick access\n\tif err := kc.st.Set([]byte(PublicKeyStoreKey), pubKey); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (kc *keychain) retrieveKeyPair() (privKey []byte, mnemonic string, err error) {\n\tring, err := kc.getKeyRing()\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tprivKeyItem, err := ring.Get(PrivateKeyStoreKey)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// Priv key is stored as 0x1234...890___some mnemonic\n\t// Here we split it to return priv key and mnemonic separately\n\tprivKeyAsStr := string(privKeyItem.Data)\n\tprivKeyParts := strings.Split(privKeyAsStr, privKeyMnemonicSeparator)\n\tmnemonic = privKeyParts[1]\n\tprivKey, err = hex.DecodeString(privKeyParts[0])\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\treturn privKey, mnemonic, nil\n}\n\nfunc (kc *keychain) GetManagedThreadKey(threadKeyName string) (thread.Key, error) {\n\t// Check if there's a key stored before continuing\n\t_, err := kc.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn thread.Key{}, err\n\t}\n\n\tsize := 32\n\n\tpriv, _, err := kc.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn thread.Key{}, err\n\t}\n\n\tprivBytes, err := priv.Raw()\n\tif err != nil {\n\t\treturn thread.Key{}, err\n\t}\n\n\tnum := pbkdf2.Key(privBytes, []byte(\"threadKey\"+threadKeyName), 256, size, sha512.New)\n\tif err != nil {\n\t\treturn thread.Key{}, err\n\t}\n\n\ttruncated := num[:sym.KeyBytes*2]\n\n\tmanagedKey, err := thread.KeyFromBytes(truncated)\n\tif err != nil {\n\t\treturn thread.Key{}, err\n\t}\n\n\treturn managedKey, nil\n}\n"
  },
  {
    "path": "core/keychain/keyring/keyring.go",
    "content": "package keyring\n\nimport \"github.com/99designs/keyring\"\n\ntype Keyring interface {\n\tSet(keyring.Item) error\n\tGet(string) (keyring.Item, error)\n\tRemove(string) error\n\tGetMetadata(string) (keyring.Metadata, error)\n}\n"
  },
  {
    "path": "core/keychain/mnemonic.go",
    "content": "package keychain\n\nimport (\n\t\"crypto/sha512\"\n\t\"errors\"\n\n\t\"github.com/tyler-smith/go-bip39\"\n\t\"golang.org/x/crypto/pbkdf2\"\n)\n\ntype generateKeyFromMnemonicOpts struct {\n\toverride bool\n\tmnemonic string\n\tpassword string\n}\n\nvar defaultMnemonicOpts = generateKeyFromMnemonicOpts{\n\toverride: false,\n\tmnemonic: \"\",\n\tpassword: \"\",\n}\n\ntype GenerateKeyFromMnemonicOpts func(o *generateKeyFromMnemonicOpts)\n\nfunc WithMnemonic(mnemonic string) GenerateKeyFromMnemonicOpts {\n\treturn func(o *generateKeyFromMnemonicOpts) {\n\t\tif mnemonic != \"\" {\n\t\t\to.mnemonic = mnemonic\n\t\t}\n\t}\n}\n\nfunc WithPassword(password string) GenerateKeyFromMnemonicOpts {\n\treturn func(o *generateKeyFromMnemonicOpts) {\n\t\tif password != \"\" {\n\t\t\to.password = password\n\t\t}\n\t}\n}\n\nfunc WithOverride() GenerateKeyFromMnemonicOpts {\n\treturn func(o *generateKeyFromMnemonicOpts) {\n\t\to.override = true\n\t}\n}\n\n// Generates a public/private key pair using ed25519 algorithm.\n// It stores it in the local db and returns the mnemonic.\n// If Mnemonic is a blank string, it generates a random one.\n// If there's already a key pair stored, it overrides it if override is set to true. Returns an error otherwise\nfunc (kc *keychain) GenerateKeyFromMnemonic(opts ...GenerateKeyFromMnemonicOpts) (string, error) {\n\to := defaultMnemonicOpts\n\tfor _, opt := range opts {\n\t\topt(&o)\n\t}\n\tif val, err := kc.GetStoredPublicKey(); val != nil && o.override == false && err != ErrKeyPairNotFound {\n\t\tnewErr := errors.New(\"Error while executing GenerateKeyFromMnemonic. Key pair already exists.\")\n\t\treturn \"\", newErr\n\t}\n\n\tmnemonic := o.mnemonic\n\n\tif mnemonic == \"\" {\n\t\tentropy, err := bip39.NewEntropy(128)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tmnemonic, err = bip39.NewMnemonic(entropy)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\tseed, err := bip39.NewSeedWithErrorChecking(mnemonic, o.password)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// The seed returned by bip39 is fixed to size = 64 bytes.\n\t// However the seed in ed25519 needs to have size 32.\n\t// So to fix this we derive a key again based on the previous one, but with the correct size.\n\tcompressedSeed := pbkdf2.Key(seed, []byte(\"iter2\"+o.password), 512, 32, sha512.New)\n\n\t_, _, err = kc.generateAndStoreKeyPair(compressedSeed, mnemonic)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn mnemonic, nil\n}\n"
  },
  {
    "path": "core/keychain/test/keychain_test.go",
    "content": "package keychain_test\n\nimport (\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/99designs/keyring\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/tyler-smith/go-bip39\"\n)\n\nvar (\n\tmockStore   *mocks.Store\n\tmockKeyRing *mocks.Keyring\n)\n\nfunc initTestKeychain(t *testing.T) keychain.Keychain {\n\tmockStore = new(mocks.Store)\n\tmockStore.On(\"IsOpen\").Return(true)\n\n\tmockKeyRing = new(mocks.Keyring)\n\n\tkc := keychain.New(keychain.WithStore(mockStore), keychain.WithKeyring(mockKeyRing))\n\n\treturn kc\n}\n\nfunc TestKeychain_GenerateAndRestore(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tpub, priv, _ := kc.GenerateKeyPairWithForce()\n\n\tprivKeyItem := keyring.Item{\n\t\tKey:   keychain.PrivateKeyStoreKey,\n\t\tData:  []byte(hex.EncodeToString(priv) + \"___\"),\n\t\tLabel: \"Space App\",\n\t}\n\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(pub, nil)\n\tmockKeyRing.On(\"Get\", keychain.PrivateKeyStoreKey).Return(privKeyItem, nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, nil)\n\n\tlibp2pPriv, _, _ := kc.GetStoredKeyPairInLibP2PFormat()\n\n\t// Reset mock store for assertions\n\tkc = initTestKeychain(t)\n\tmockStore.AssertNotCalled(t, \"Set\", []byte(keychain.PublicKeyStoreKey), pub)\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\n\tkc.ImportExistingKeyPair(libp2pPriv, \"\")\n\n\tmockStore.AssertCalled(t, \"Set\", []byte(keychain.PublicKeyStoreKey), pub)\n\tmockKeyRing.AssertCalled(t, \"Set\", privKeyItem)\n}\n\nfunc TestKeychain_GenerateMnemonicKey(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, nil)\n\n\tval, err := kc.GenerateKeyFromMnemonic()\n\twords := strings.Split(val, \" \")\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, val)\n\tassert.Equal(t, 12, len(words))\n\tmockStore.AssertCalled(t, \"Set\", []byte(keychain.PublicKeyStoreKey), mock.Anything)\n\tmockKeyRing.AssertCalled(t, \"Set\", mock.Anything)\n}\n\nfunc TestKeychain_RestoreMnemonicKey(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, nil)\n\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\tpubFromMnemonic, _ := hex.DecodeString(\"bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\")\n\tprivAsHex := \"6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\"\n\n\tval, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))\n\tassert.Nil(t, err)\n\tassert.NotNil(t, val)\n\tassert.Equal(t, mnemonic, val)\n\tmockStore.AssertCalled(t, \"Set\", []byte(keychain.PublicKeyStoreKey), pubFromMnemonic)\n\tmockKeyRing.AssertCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.PrivateKeyStoreKey,\n\t\tData:  []byte(privAsHex + \"___\" + mnemonic),\n\t\tLabel: \"Space App\",\n\t})\n}\n\nfunc TestKeychain_RestoreMnemonicKeyOnOverrideErr(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, nil)\n\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\tpubFromMnemonic, _ := hex.DecodeString(\"a29d5030556f55f32d82b71618e97bfe976ebebc713592122b124881b4da6191\")\n\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(pubFromMnemonic, nil)\n\n\t_, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))\n\tassert.NotNil(t, err)\n\tassert.Equal(t, errors.New(\"Error while executing GenerateKeyFromMnemonic. Key pair already exists.\"), err)\n}\n\nfunc TestKeychain_RestoreMnemonicKeyExistsButNotInKeyring(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, keyring.ErrKeyNotFound)\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)\n\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\tpubFromMnemonic, _ := hex.DecodeString(\"bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\")\n\tprivAsHex := \"6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\"\n\n\tval, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))\n\tassert.Nil(t, err)\n\tassert.NotNil(t, val)\n\tassert.Equal(t, mnemonic, val)\n\tmockStore.AssertCalled(t, \"Set\", []byte(keychain.PublicKeyStoreKey), pubFromMnemonic)\n\tmockKeyRing.AssertCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.PrivateKeyStoreKey,\n\t\tData:  []byte(privAsHex + \"___\" + mnemonic),\n\t\tLabel: \"Space App\",\n\t})\n}\n\nfunc TestKeychain_RestoreMnemonicKeyMnemonicErr(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, nil)\n\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd\"\n\n\t_, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))\n\tassert.NotNil(t, err)\n\tassert.Equal(t, bip39.ErrInvalidMnemonic, err)\n}\n\nfunc TestKeychain_RestoreMnemonicKeyOnOverrideSuccess(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockKeyRing.On(\"GetMetadata\", mock.Anything).Return(keyring.Metadata{}, nil)\n\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\tpubFromMnemonic, _ := hex.DecodeString(\"bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\")\n\tprivAsHex := \"6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\"\n\n\tmockStore.On(\"Get\", []byte(keychain.PublicKeyStoreKey)).Return(pubFromMnemonic, nil)\n\n\tval, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic), keychain.WithOverride())\n\tassert.Nil(t, err)\n\tassert.NotNil(t, val)\n\tassert.Equal(t, mnemonic, val)\n\tmockStore.AssertCalled(t, \"Set\", []byte(keychain.PublicKeyStoreKey), pubFromMnemonic)\n\tmockKeyRing.AssertCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.PrivateKeyStoreKey,\n\t\tData:  []byte(privAsHex + \"___\" + mnemonic),\n\t\tLabel: \"Space App\",\n\t})\n}\n\nfunc TestKeychain_GetStoredMnemonic(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\tprivAsHex := \"6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907\"\n\n\tmockKeyRing.On(\"Get\", keychain.PrivateKeyStoreKey).Return(keyring.Item{\n\t\tKey:   keychain.PrivateKeyStoreKey,\n\t\tData:  []byte(privAsHex + \"___\" + mnemonic),\n\t\tLabel: \"Space App\",\n\t}, nil)\n\n\tmnemonic2, err := kc.GetStoredMnemonic()\n\n\tassert.Nil(t, err)\n\tassert.Equal(t, mnemonic, mnemonic2)\n}\n\nfunc TestKeychain_AppToken_StoreMaster(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Get\", []byte(keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey)).Return(nil, nil)\n\tmockKeyRing.On(\"Get\", keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey).Return(keyring.Item{}, keyring.ErrKeyNotFound)\n\tmockKeyRing.On(\"Set\", mock.Anything).Return(nil)\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\n\ttok, err := permissions.GenerateRandomToken(true, []string{})\n\tassert.NoError(t, err)\n\n\terr = kc.StoreAppToken(tok)\n\tassert.NoError(t, err)\n\n\tmarshalled, err := permissions.MarshalToken(tok)\n\tassert.NoError(t, err)\n\n\tmockKeyRing.AssertCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.AppTokenStoreKey + \"_\" + tok.Key,\n\t\tData:  marshalled,\n\t\tLabel: \"Space App - App Token\",\n\t})\n\n\tmockKeyRing.AssertCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.AppTokenStoreKey + \"_\" + keychain.MasterAppTokenStoreKey,\n\t\tData:  marshalled,\n\t\tLabel: \"Space App - Master App Token\",\n\t})\n\n\tmockStore.AssertCalled(t, \"Set\", []byte(keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey), []byte(tok.Key))\n}\n\nfunc TestKeychain_AppToken_StoreNonMaster(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\tmockStore.On(\"Get\", []byte(keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey)).Return(nil, nil)\n\tmockKeyRing.On(\"Get\", keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey).Return(keyring.Item{}, keyring.ErrKeyNotFound)\n\tmockKeyRing.On(\"Set\", mock.Anything).Once().Return(nil)\n\n\ttok, err := permissions.GenerateRandomToken(false, []string{})\n\tassert.NoError(t, err)\n\n\terr = kc.StoreAppToken(tok)\n\tassert.NoError(t, err)\n\n\tmarshalled, err := permissions.MarshalToken(tok)\n\tassert.NoError(t, err)\n\n\tmockKeyRing.AssertCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.AppTokenStoreKey + \"_\" + tok.Key,\n\t\tData:  marshalled,\n\t\tLabel: \"Space App - App Token\",\n\t})\n\n\tmockKeyRing.AssertNotCalled(t, \"Set\", keyring.Item{\n\t\tKey:   keychain.AppTokenStoreKey + \"_\" + keychain.MasterAppTokenStoreKey,\n\t\tData:  marshalled,\n\t\tLabel: \"Space App - Master App Token\",\n\t})\n}\n\nfunc TestKeychain_AppToken_StoreMasterOverride1(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\ttok, err := permissions.GenerateRandomToken(true, []string{})\n\tassert.NoError(t, err)\n\n\tmockStore.On(\"Get\", []byte(keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey)).Return([]byte(tok.Key), nil)\n\n\terr = kc.StoreAppToken(tok)\n\tassert.Error(t, err)\n}\n\nfunc TestKeychain_AppToken_StoreMasterOverride2(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\ttok, err := permissions.GenerateRandomToken(true, []string{})\n\tassert.NoError(t, err)\n\n\tmockStore.On(\"Get\", []byte(keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey)).Return(nil, nil)\n\tmockKeyRing.On(\"Get\", keychain.AppTokenStoreKey+\"_\"+keychain.MasterAppTokenStoreKey).Return(keyring.Item{}, nil)\n\n\terr = kc.StoreAppToken(tok)\n\tassert.Error(t, err)\n}\n\nfunc TestKeychain_AppToken_Get(t *testing.T) {\n\tkc := initTestKeychain(t)\n\n\ttok, err := permissions.GenerateRandomToken(false, []string{})\n\tassert.NoError(t, err)\n\n\tmarshalled, err := permissions.MarshalToken(tok)\n\tassert.NoError(t, err)\n\n\tmockKeyRing.On(\"Get\", keychain.AppTokenStoreKey+\"_\"+tok.Key).Return(keyring.Item{\n\t\tKey:   keychain.AppTokenStoreKey + \"_\" + tok.Key,\n\t\tData:  marshalled,\n\t\tLabel: \"Space App - App Token\",\n\t}, nil)\n\n\ttok2, err := kc.GetAppToken(tok.Key)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, tok, tok2)\n}\n"
  },
  {
    "path": "core/libfuse/block_size.go",
    "content": "package libfuse\n\n// fuseBlockSize is the block size used for calculating number of blocks. This\n// is to make du/df work, and does not reflect in any way the internal block\n// size (which is variable). 512 is chosen because FUSE seems to assume this\n// block size all the time, despite BlockSize is provided in Statfs or Attr\n// response or not. Bazil FUSE's documentation verifies this:\n// https://github.com/bazil/fuse/blob/371fbbdaa8987b715bdd21d6adc4c9b20155f748/fuse.go#L1320\nconst fuseBlockSize = 512\n\nfunc getNumBlocksFromSize(size uint64) uint64 {\n\tif size == 0 {\n\t\treturn 0\n\t}\n\treturn (size-1)/fuseBlockSize + 1\n}\n"
  },
  {
    "path": "core/libfuse/directory.go",
    "content": "//+build !windows\n\npackage libfuse\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"bazil.org/fuse\"\n\t\"bazil.org/fuse/fs\"\n)\n\nvar (\n\t_ fs.Node         = (*VFSDir)(nil)\n\t_ fs.NodeAccesser = (*VFSDir)(nil)\n\t_                 = fs.NodeRequestLookuper(&VFSDir{})\n\t_                 = fs.HandleReadDirAller(&VFSDir{})\n\t_                 = fs.NodeCreater(&VFSDir{})\n\t_                 = fs.NodeMkdirer(&VFSDir{})\n\t_                 = fs.NodeRenamer(&VFSDir{})\n\t_                 = fs.NodeRemover(&VFSDir{})\n)\n\n// VFSDir represents a directory in the Virtual file system\ntype VFSDir struct {\n\tvfs    *VFS // pointer to the parent file system\n\tdirOps spacefs.DirOps\n}\n\nfunc NewVFSDir(vfs *VFS, dirOps spacefs.DirOps) *VFSDir {\n\treturn &VFSDir{\n\t\tvfs:    vfs,\n\t\tdirOps: dirOps,\n\t}\n}\n\n// Attr returns fuse.Attr for the directory\nfunc (dir *VFSDir) Attr(ctx context.Context, attr *fuse.Attr) error {\n\tdirAttribute, err := dir.dirOps.Attribute(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tattr.Mode = dirAttribute.Mode()\n\tattr.Uid = dirAttribute.Uid()\n\tattr.Gid = dirAttribute.Gid()\n\n\treturn nil\n}\n\n// ReadDirAll reads all the content of a directory\n// In this mirror drive case, we just return items in the mirror path\nfunc (dir *VFSDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {\n\tdirList, err := dir.dirOps.ReadDir(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar res []fuse.Dirent\n\tfor _, dirEntry := range dirList {\n\t\tentryAttribute, err := dirEntry.Attribute(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tentry := fuse.Dirent{\n\t\t\tName: entryAttribute.Name(),\n\t\t}\n\n\t\tif entryAttribute.IsDir() {\n\t\t\tentry.Type = fuse.DT_Dir\n\t\t} else {\n\t\t\tentry.Type = fuse.DT_File\n\t\t}\n\n\t\tres = append(res, entry)\n\t}\n\n\treturn res, nil\n}\n\n// Lookup finds entry Node within a directory\n// Seems to be called when not enough information is gotten from the ReadDirAll\nfunc (dir *VFSDir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {\n\t//log.Debug(\"VFSDir.Lookup\", \"name:\"+req.Name)\n\n\tpath := dir.dirOps.Path() + req.Name\n\tentry, err := dir.vfs.fsOps.LookupPath(ctx, path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tentryAttribute, err := entry.Attribute(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif entryAttribute.IsDir() {\n\t\tdirOps, ok := entry.(spacefs.DirOps)\n\t\tif !ok {\n\t\t\t// TODO: Return a better syscall error\n\t\t\treturn nil, syscall.ENOENT\n\t\t}\n\t\treturn NewVFSDir(dir.vfs, dirOps), nil\n\t}\n\n\tfileOps, ok := entry.(spacefs.FileOps)\n\tif !ok {\n\t\t// TODO: Return a better syscall error\n\t\treturn nil, syscall.ENOENT\n\t}\n\n\treturn &VFSFile{\n\t\tvfs:     dir.vfs,\n\t\tfileOps: fileOps,\n\t}, nil\n}\n\n// Create is invoked when a new directory is to be created\n// It implements the fs.NodeCreator interface\nfunc (dir *VFSDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {\n\tpath := dir.dirOps.Path()\n\tlog.Printf(\"Creating a file/directory: %+v in path: %s\", *req, path)\n\tdirEntry, err := dir.vfs.fsOps.CreateEntry(ctx, spacefs.CreateDirEntry{\n\t\tPath: fmt.Sprintf(\"%s%c%s\", strings.TrimSuffix(path, \"/\"), '/', req.Name),\n\t\tMode: req.Mode,\n\t})\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif dirOps, ok := dirEntry.(spacefs.DirOps); ok {\n\t\treturn NewVFSDir(dir.vfs, dirOps), nil, nil\n\t}\n\n\tif fileOps, ok := dirEntry.(spacefs.FileOps); ok {\n\t\tvfsFile := NewVFSFile(dir.vfs, fileOps)\n\t\thandler, err := NewVFSFileHandler(ctx, vfsFile)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\treturn vfsFile, handler, nil\n\t}\n\n\treturn nil, nil, syscall.EACCES\n}\n\n// Mkdir implements the fs.NodeMkdirer interface\nfunc (dir *VFSDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {\n\tpath := dir.dirOps.Path()\n\tlog.Debug(fmt.Sprintf(\"Mkdir a file/directory: %+v with name %s, in path: %s\", *req, req.Name, path))\n\tdirEntry, err := dir.vfs.fsOps.CreateEntry(ctx, spacefs.CreateDirEntry{\n\t\tPath: fmt.Sprintf(\"%s%c%s\", strings.TrimSuffix(path, \"/\"), '/', req.Name),\n\t\tMode: req.Mode,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif dirOps, ok := dirEntry.(spacefs.DirOps); ok {\n\t\treturn NewVFSDir(dir.vfs, dirOps), nil\n\t}\n\n\tlog.Error(\"should not happen\", errors.New(\"created directory is not a directory\"))\n\treturn nil, fuse.ENOTSUP\n}\n\n// Rename implements the fs.NodeRenamer\n// Rename is only implemented for VFSDir and not VFSFile, because we currently don't support renaming files\n// and rename on fsOps should only work empty folders.\nfunc (dir *VFSDir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {\n\tparentPath := dir.dirOps.Path()\n\tlog.Debug(\"Renaming node\", \"oldName:\"+req.OldName, \"newName:\"+req.NewName, \"parentPath:\"+parentPath)\n\n\treturn dir.vfs.fsOps.RenameEntry(ctx, spacefs.RenameDirEntry{\n\t\tOldPath: path.Join(parentPath, req.OldName),\n\t\tNewPath: path.Join(parentPath, req.NewName),\n\t})\n}\n\n// Remove implements the fs.NodeRemover\nfunc (dir *VFSDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {\n\tparentPath := dir.dirOps.Path()\n\treturn dir.vfs.fsOps.DeleteEntry(ctx, path.Join(parentPath, req.Name))\n}\n\nfunc (dir *VFSDir) Access(ctx context.Context, req *fuse.AccessRequest) error {\n\treturn nil\n}\n"
  },
  {
    "path": "core/libfuse/files.go",
    "content": "//+build !windows\n\npackage libfuse\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"bazil.org/fuse\"\n\t\"bazil.org/fuse/fs\"\n)\n\nvar (\n\t_ fs.Node = (*VFSFile)(nil)\n\t_         = fs.NodeAccesser(&VFSFile{})\n\t_         = fs.NodeOpener(&VFSFile{})\n\t_         = fs.NodeSetattrer(&VFSFile{})\n\t_         = fs.HandleReader(&VFSFileHandler{})\n\t_         = fs.HandleWriter(&VFSFileHandler{})\n\t_         = fs.HandleReleaser(&VFSFileHandler{})\n)\n\n// VFSFile represents a file in the Virtual file system\ntype VFSFile struct {\n\tvfs     *VFS // pointer to the parent file system\n\tfileOps spacefs.FileOps\n}\n\nfunc NewVFSFile(vfs *VFS, fileOps spacefs.FileOps) *VFSFile {\n\treturn &VFSFile{\n\t\tvfs:     vfs,\n\t\tfileOps: fileOps,\n\t}\n}\n\n// Attr returns fuse.Attr for the directory or file\nfunc (vfile *VFSFile) Attr(ctx context.Context, attr *fuse.Attr) error {\n\tpath := vfile.fileOps.Path()\n\tlog.Printf(\"Getting File Attr %s\", path)\n\tfileAttribute, err := vfile.fileOps.Attribute(ctx)\n\tif err != nil {\n\t\tlog.Printf(\"ERROR Getting Open File Attr %s\", err.Error())\n\t\treturn err\n\t}\n\n\tattr.Size = fileAttribute.Size()\n\tattr.Blocks = getNumBlocksFromSize(attr.Size)\n\tattr.Mode = fileAttribute.Mode()\n\tattr.Mtime = fileAttribute.ModTime()\n\tattr.Ctime = fileAttribute.Ctime()\n\tattr.Crtime = fileAttribute.Ctime()\n\tattr.Uid = fileAttribute.Uid()\n\tattr.Gid = fileAttribute.Gid()\n\n\tlog.Printf(\"Successful File Attr %s : %+v\", path, attr)\n\n\treturn nil\n}\n\n// Access implements the fs.NodeAccesser interface for File. This is necessary\n// for macOS to correctly identify plaintext files as plaintext. If not\n// implemented, bazil-fuse returns a nil error for every call, so when macOS\n// checks for executable bit using Access (instead of Attr!), it gets a\n// success, which makes it think the file is executable, yielding a \"Unix\n// executable\" UTI.\nfunc (vfile *VFSFile) Access(ctx context.Context, r *fuse.AccessRequest) (err error) {\n\tif int(r.Uid) != os.Getuid() &&\n\t\t// Finder likes to use UID 0 for some operations. osxfuse already allows\n\t\t// ACCESS and GETXATTR requests from root to go through. This allows root\n\t\t// in ACCESS handler.\n\t\tint(r.Uid) != 0 {\n\t\t// short path: not accessible by anybody other than root or the current user\n\t\treturn syscall.EPERM\n\t}\n\n\tif r.Mask&03 == 0 {\n\t\t// Since we only check for w and x bits, we can return nil early here.\n\t\treturn nil\n\t}\n\n\t// check is executable mask enable\n\tif r.Mask&01 != 0 {\n\t\t_, err := vfile.fileOps.Attribute(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// for now always return permission error for executable calls\n\t\t// we are not supporting executable at the moment\n\t\treturn syscall.EPERM\n\t}\n\n\treturn nil\n}\n\n// Setattr implements the set attribute of fs.NodeSetattrer\nfunc (vfile *VFSFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {\n\tpath := vfile.fileOps.Path()\n\tlog.Debug(\"Setattr called\", \"path:\"+path, \"req.Valid:\"+req.Valid.String(), fmt.Sprintf(\"req:%v\", req))\n\tvalid := req.Valid\n\n\tif valid.Size() {\n\t\terr := vfile.fileOps.Truncate(ctx, req.Size)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvalid ^= fuse.SetattrSize\n\t}\n\n\treturn nil\n}\n\n// Open create a handle responsible for reading the file and also closing the file after reading\nfunc (vfile *VFSFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {\n\tlog.Printf(\"Opening content of file %s\", vfile.fileOps.Path())\n\treturn NewVFSFileHandler(ctx, vfile)\n}\n\n// VFSFileHandler manages readings and closing access to a VFSFile\ntype VFSFileHandler struct {\n\tpath         string\n\treadWriteOps spacefs.FileHandler\n}\n\nfunc NewVFSFileHandler(ctx context.Context, vfile *VFSFile) (*VFSFileHandler, error) {\n\treadWriteOps, err := vfile.fileOps.Open(ctx, spacefs.ReadMode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &VFSFileHandler{\n\t\tpath:         vfile.fileOps.Path(),\n\t\treadWriteOps: readWriteOps,\n\t}, nil\n}\n\n// Read reads the content of the reader\n// Ideally, decryption of the content of the file should be happening here\nfunc (vfh *VFSFileHandler) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {\n\tlog.Printf(\"Reading content of file %s, and size: %d\", vfh.path, req.Size)\n\tbuf := make([]byte, req.Size)\n\tn, err := vfh.readWriteOps.Read(ctx, buf, req.Offset)\n\tif err != nil {\n\t\tlog.Printf(\"Reading error: %s\", err.Error())\n\t\treturn err\n\t}\n\n\tresp.Data = buf[:n]\n\treturn nil\n}\n\n// Write writes content from request into the underlying file. Keeping track of offset and all\n// Ideally, encryption of the content of the file should be happening here\nfunc (vfh *VFSFileHandler) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {\n\tlog.Printf(\"Writing content to file %s\", vfh.path)\n\tn, err := vfh.readWriteOps.Write(ctx, req.Data, req.Offset)\n\tif err != nil {\n\t\tlog.Printf(\"Writing error: %s\", err.Error())\n\t\treturn err\n\t}\n\n\tresp.Size = n\n\treturn nil\n}\n\n// Release closes the reader on this file handler\nfunc (vfh *VFSFileHandler) Release(ctx context.Context, req *fuse.ReleaseRequest) error {\n\treturn vfh.readWriteOps.Close(ctx)\n}\n"
  },
  {
    "path": "core/libfuse/vfs.go",
    "content": "//+build !windows\n\npackage libfuse\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"bazil.org/fuse\"\n\t\"bazil.org/fuse/fs\"\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n)\n\nvar _ fs.FS = (*VFS)(nil)\n\nvar (\n\terrorNotMounted = errors.New(\"VFS not mounted yet\")\n)\n\n// VFS represent Virtual System\ntype VFS struct {\n\tctx             context.Context\n\tfsOps           spacefs.FSOps\n\tmountConnection *fuse.Conn\n\tmountPath       string\n}\n\n// NewVFileSystem creates a new Virtual FileSystem object\nfunc NewVFileSystem(ctx context.Context, fsOps spacefs.FSOps) *VFS {\n\treturn &VFS{\n\t\t// storing ctx here to be used in the Root request\n\t\t// as FUSE doesn't provide one there\n\t\tctx:             ctx,\n\t\tfsOps:           fsOps,\n\t\tmountConnection: nil,\n\t}\n}\n\n// Mount mounts the file system, if it is not already mounted\nfunc (vfs *VFS) Mount(mountPath, fsName string) error {\n\tc, err := fuse.Mount(\n\t\tmountPath,\n\t\tfuse.FSName(fsName),\n\t\tfuse.VolumeName(fsName),\n\t\tfuse.NoAppleDouble(),\n\t\t//fuse.ExclCreate(),\n\t\t//fuse.NoAppleXattr(),\n\t\tfuse.AsyncRead(),\n\t\tfuse.LocalVolume(),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvfs.mountPath = mountPath\n\tvfs.mountConnection = c\n\treturn nil\n}\n\n// IsMounted returns true if the vfs still has a valid connection to the mounted path\nfunc (vfs *VFS) IsMounted() bool {\n\treturn vfs.mountConnection != nil\n}\n\n// Serve start the FUSE server that handles requests from the mounted connection\n// This is a blocking operation\nfunc (vfs *VFS) Serve() error {\n\tif !vfs.IsMounted() {\n\t\treturn errorNotMounted\n\t}\n\n\tif err := fs.Serve(vfs.mountConnection, vfs); err != nil {\n\t\treturn err\n\t}\n\n\t// check if the mount process has an error to report\n\t<-vfs.mountConnection.Ready\n\tif err := vfs.mountConnection.MountError; err != nil {\n\t\treturn err\n\t}\n\n\t// reset mount connection\n\tvfs.mountConnection = nil\n\treturn nil\n}\n\n// UnMount closes connection\nfunc (vfs *VFS) Unmount() error {\n\tif !vfs.IsMounted() {\n\t\treturn errorNotMounted\n\t}\n\n\terr := vfs.mountConnection.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = fuse.Unmount(vfs.mountPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvfs.mountConnection = nil\n\treturn err\n}\n\n// Root complies with the Fuse Interface that returns the Root Node of our file system\nfunc (vfs *VFS) Root() (fs.Node, error) {\n\trootDirEntry, err := vfs.fsOps.Root(vfs.ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trootDir, ok := rootDirEntry.(spacefs.DirOps)\n\tif !ok {\n\t\terr = errors.New(\"root directory is not a spacefs.DirOps\")\n\t\tlog.Error(\"VFS.Root() error\", err)\n\t\treturn nil, err\n\t}\n\n\tnode := &VFSDir{\n\t\tvfs:    vfs,\n\t\tdirOps: rootDir,\n\t}\n\treturn node, nil\n}\n\nvar _ fs.FSStatfser = (*VFS)(nil)\n\n// Statfs implements the fs.FSStatfser interface and reports block and storage information stats about VFS\nfunc (vfs *VFS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error {\n\t//log.Debug(\"Request Statfs\")\n\tresp.Bsize = fuseBlockSize\n\tresp.Namelen = ^uint32(0)\n\tresp.Frsize = fuseBlockSize\n\n\t// Simulate a large amount of free space\n\tstorageSize := uint64(1 << 50) // 2^50 bytes approximately 1PiB\n\ttotalAvailableBlocks := getNumBlocksFromSize(storageSize)\n\tusedBlockSize := getNumBlocksFromSize(0)\n\n\tresp.Blocks = totalAvailableBlocks\n\tresp.Bavail = totalAvailableBlocks - usedBlockSize\n\tresp.Bfree = totalAvailableBlocks - usedBlockSize\n\treturn nil\n}\n"
  },
  {
    "path": "core/permissions/app_token.go",
    "content": "package permissions\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strings\"\n)\n\nvar invalidAppTokenErr = errors.New(\"app token is invalid\")\n\nconst tokenKeyLength = 20\nconst tokenSecretLength = 30\n\ntype AppToken struct {\n\tKey         string   `json:\"key\"`\n\tSecret      string   `json:\"secret\"`\n\tIsMaster    bool     `json:\"isMaster\"`\n\tPermissions []string `json:\"permissions\"`\n}\n\nfunc UnmarshalToken(marshalledToken []byte) (*AppToken, error) {\n\tvar result AppToken\n\terr := json.Unmarshal(marshalledToken, &result)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &result, nil\n}\n\nfunc MarshalToken(tok *AppToken) ([]byte, error) {\n\tjsonData, err := json.Marshal(tok)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn jsonData, nil\n\n}\n\nfunc GenerateRandomToken(isMaster bool, permissions []string) (*AppToken, error) {\n\tk := make([]byte, tokenKeyLength)\n\t_, err := rand.Read(k)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ts := make([]byte, tokenSecretLength)\n\t_, err = rand.Read(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &AppToken{\n\t\tKey:         base64.RawURLEncoding.EncodeToString(k),\n\t\tSecret:      base64.RawURLEncoding.EncodeToString(s),\n\t\tIsMaster:    isMaster,\n\t\tPermissions: permissions,\n\t}, nil\n}\n\nfunc (a *AppToken) GetAccessToken() string {\n\treturn a.Key + \".\" + a.Secret\n}\n\nfunc GetKeyAndSecretFromAccessToken(accessToken string) (key string, secret string, err error) {\n\ttp := strings.Split(accessToken, \".\")\n\tif len(tp) < 2 {\n\t\treturn \"\", \"\", errors.New(\"invalid token format\")\n\t}\n\n\tkey = tp[0]\n\tsecret = tp[1]\n\n\treturn\n}\n"
  },
  {
    "path": "core/permissions/app_token_test.go",
    "content": "package permissions_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPermissions_AppToken_Generation(t *testing.T) {\n\ttok, err := permissions.GenerateRandomToken(true, []string{})\n\tassert.NoError(t, err)\n\n\tmarshalled, err := permissions.MarshalToken(tok)\n\tassert.NoError(t, err)\n\tunmarshalled, err := permissions.UnmarshalToken(marshalled)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, tok, unmarshalled)\n}\n\nfunc TestPermissions_AppToken_GenerationWithPerms(t *testing.T) {\n\ttok, err := permissions.GenerateRandomToken(false, []string{\"OpenFile\", \"ListDirectories\"})\n\tassert.NoError(t, err)\n\n\tmarshalled, err := permissions.MarshalToken(tok)\n\tassert.NoError(t, err)\n\tunmarshalled, err := permissions.UnmarshalToken(marshalled)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, tok, unmarshalled)\n}\n"
  },
  {
    "path": "core/search/bleve/analyzer.go",
    "content": "package bleve\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/blevesearch/bleve/analysis\"\n\t\"github.com/blevesearch/bleve/analysis/analyzer/standard\"\n\tfilterregex \"github.com/blevesearch/bleve/analysis/char/regexp\"\n\t\"github.com/blevesearch/bleve/registry\"\n)\n\nconst CustomerAnalyzerName = \"space_search_analyzer\"\n\n/// Customer Analyzer extends the standard analyzer by registering a regexp character filter\nfunc CustomAnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) {\n\trv, err := standard.AnalyzerConstructor(config, cache)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// replace . with white space - helps to improve results on filenames\n\tpattern, err := regexp.Compile(\"\\\\.\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treplacement := []byte(\" \")\n\tregexpCharFilter := filterregex.New(pattern, replacement)\n\trv.CharFilters = append(rv.CharFilters, regexpCharFilter)\n\n\treturn rv, nil\n}\n\nfunc init() {\n\tregistry.RegisterAnalyzer(CustomerAnalyzerName, CustomAnalyzerConstructor)\n}\n"
  },
  {
    "path": "core/search/bleve/bleve.go",
    "content": "package bleve\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"os/user\"\n\t\"path/filepath\"\n\n\t\"github.com/blevesearch/bleve/mapping\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"github.com/FleekHQ/space-daemon/core/util\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\t\"github.com/blevesearch/bleve\"\n)\n\nconst DbFileName = \"filesIndex.bleve\"\n\ntype bleveSearchOption struct {\n\tdbPath string\n}\n\ntype Option func(o *bleveSearchOption)\n\n// bleveFilesSearchEngine is a files search engine that is backed by bleve\ntype bleveFilesSearchEngine struct {\n\topts bleveSearchOption\n\tidx  bleve.Index\n}\n\n// Creates a new Bleve backed search engine for files and folders\nfunc NewSearchEngine(opts ...Option) *bleveFilesSearchEngine {\n\tusr, _ := user.Current()\n\n\tsearchOptions := bleveSearchOption{\n\t\tdbPath: filepath.Join(usr.HomeDir, \".fleek-space\"),\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(&searchOptions)\n\t}\n\n\treturn &bleveFilesSearchEngine{\n\t\topts: searchOptions,\n\t}\n}\n\nfunc (b *bleveFilesSearchEngine) Start() error {\n\tif b.idx != nil {\n\t\tlog.Warn(\"Trying to open already opened search index\")\n\t\treturn nil\n\t}\n\n\tpath := filepath.Join(b.opts.dbPath, DbFileName)\n\n\tvar (\n\t\tidx bleve.Index\n\t\terr error\n\t)\n\n\tif util.DirEntryExists(path) {\n\t\tlog.Debug(\"Opening existing search index\")\n\t\tidx, err = bleve.Open(path)\n\t} else {\n\t\tlog.Debug(\"Creating and opening new search index\")\n\t\tindexMapping, err := getSearchIndexMapping()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tidx, err = bleve.New(path, indexMapping)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb.idx = idx\n\n\treturn nil\n}\n\nfunc getSearchIndexMapping() (*mapping.IndexMappingImpl, error) {\n\tindexMapping := bleve.NewIndexMapping()\n\tindexMapping.DefaultAnalyzer = CustomerAnalyzerName\n\n\tfilesMapping := bleve.NewDocumentMapping()\n\n\t// index the following fields\n\tnameFm := bleve.NewTextFieldMapping()\n\tfilesMapping.AddFieldMappingsAt(\"ItemName\", nameFm)\n\textFm := bleve.NewTextFieldMapping()\n\tfilesMapping.AddFieldMappingsAt(\"ItemExtension\", extFm)\n\tpathFm := bleve.NewTextFieldMapping()\n\tfilesMapping.AddFieldMappingsAt(\"ItemPath\", pathFm)\n\n\t// ignore indexing the following fields of IndexRecord\n\tidFm := bleve.NewTextFieldMapping()\n\tidFm.Index = false\n\tfilesMapping.AddFieldMappingsAt(\"Id\", idFm)\n\n\tbucketFm := bleve.NewTextFieldMapping()\n\tbucketFm.Index = false\n\tfilesMapping.AddFieldMappingsAt(\"BucketSlug\", bucketFm)\n\n\tdbIdFm := bleve.NewTextFieldMapping()\n\tdbIdFm.Index = false\n\tfilesMapping.AddFieldMappingsAt(\"DbId\", dbIdFm)\n\n\titemTypeFm := bleve.NewTextFieldMapping()\n\titemTypeFm.Index = false\n\tfilesMapping.AddFieldMappingsAt(\"ItemType\", itemTypeFm)\n\n\tindexMapping.AddDocumentMapping(\"files\", filesMapping)\n\tindexMapping.DefaultType = \"files\"\n\n\treturn indexMapping, nil\n}\n\nfunc (b *bleveFilesSearchEngine) InsertFileData(\n\tctx context.Context,\n\tdata *search.InsertIndexRecord,\n) (*search.IndexRecord, error) {\n\tindexId := generateIndexId(data.ItemName, data.ItemPath, data.BucketSlug, data.DbId)\n\trecord := search.IndexRecord{\n\t\tId:            indexId,\n\t\tItemName:      data.ItemName,\n\t\tItemExtension: data.ItemExtension,\n\t\tItemPath:      data.ItemPath,\n\t\tItemType:      data.ItemType,\n\t\tBucketSlug:    data.BucketSlug,\n\t\tDbId:          data.DbId,\n\t}\n\n\tif err := b.idx.Index(indexId, record); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &record, nil\n}\n\nfunc (b *bleveFilesSearchEngine) DeleteFileData(\n\tctx context.Context,\n\tdata *search.DeleteIndexRecord,\n) error {\n\tindexId := generateIndexId(data.ItemName, data.ItemPath, data.BucketSlug, data.DbId)\n\treturn b.idx.Delete(indexId)\n}\n\nfunc (b *bleveFilesSearchEngine) QueryFileData(\n\tctx context.Context,\n\tquery string,\n\tlimit int,\n) ([]*search.IndexRecord, error) {\n\tmatchQuery := bleve.NewMatchQuery(query)\n\tmatchQuery.Fuzziness = 2\n\n\tprefixQuery := bleve.NewPrefixQuery(query)\n\tinfixRegexQuery := bleve.NewRegexpQuery(fmt.Sprintf(\".*%s.*\", query)) // TODO: think of escaping invalid regex in query\n\n\tsearchQuery := bleve.NewDisjunctionQuery(matchQuery, prefixQuery, infixRegexQuery)\n\tsearchRequest := bleve.NewSearchRequest(searchQuery)\n\tsearchRequest.Size = limit\n\tsearchRequest.Fields = []string{\"*\"}\n\n\tsearchResults, err := b.idx.Search(searchRequest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trecords := make([]*search.IndexRecord, len(searchResults.Hits))\n\tfor i, hit := range searchResults.Hits {\n\t\trecords[i] = &search.IndexRecord{\n\t\t\tId:            hit.Fields[\"Id\"].(string),\n\t\t\tItemName:      hit.Fields[\"ItemName\"].(string),\n\t\t\tItemExtension: hit.Fields[\"ItemExtension\"].(string),\n\t\t\tItemPath:      hit.Fields[\"ItemPath\"].(string),\n\t\t\tItemType:      hit.Fields[\"ItemType\"].(string),\n\t\t\tBucketSlug:    hit.Fields[\"BucketSlug\"].(string),\n\t\t\tDbId:          hit.Fields[\"DbId\"].(string),\n\t\t}\n\t}\n\n\treturn records, nil\n}\n\nfunc (b *bleveFilesSearchEngine) Shutdown() error {\n\tif b.idx == nil {\n\t\treturn nil\n\t}\n\n\terr := b.idx.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb.idx = nil\n\treturn nil\n}\n\nfunc generateIndexId(name, path, bucketSlug, dbId string) string {\n\tbytes := sha256.Sum256([]byte(name + path + bucketSlug + dbId))\n\treturn fmt.Sprintf(\"%x\", bytes)\n}\n"
  },
  {
    "path": "core/search/bleve/bleve_test.go",
    "content": "package bleve\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\t\"gotest.tools/assert\"\n)\n\nfunc setupEngine(t *testing.T) (*bleveFilesSearchEngine, context.Context) {\n\tdbPath, err := ioutil.TempDir(\"\", \"testDb-*\")\n\tassert.NilError(t, err, \"failed to create db path\")\n\n\tengine := NewSearchEngine(WithDBPath(dbPath))\n\tassert.NilError(t, engine.Start(), \"database failed to initialize\")\n\n\tcleanup := func() {\n\t\t_ = engine.Shutdown()\n\t\t_ = os.RemoveAll(dbPath)\n\t}\n\n\tt.Cleanup(cleanup)\n\n\treturn engine, context.Background()\n}\n\nfunc TestEngineStartAndShutdown(t *testing.T) {\n\tdbPath, err := ioutil.TempDir(\"\", \"testDb-*\")\n\tassert.NilError(t, err, \"failed to create db path\")\n\n\tengine := NewSearchEngine(WithDBPath(dbPath))\n\tassert.NilError(t, engine.Start(), \"database failed to initialize\")\n\tassert.NilError(t, engine.Shutdown(), \"search engine failed to shutdown\")\n\n\t// try re-opening the same engine once more\n\tengine = NewSearchEngine(WithDBPath(dbPath))\n\tassert.NilError(t, engine.Start(), \"failed to re-open existing search index\")\n\tassert.NilError(t, engine.Shutdown(), \"failed to shutdown existing search index\")\n}\n\nfunc TestFilesSearchEngine_Insert_And_Query(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"second-content.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\tqueryResult, err := engine.QueryFileData(ctx, \"pdf\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 1, len(queryResult), \"not enough results returned from query\")\n\n\tassert.Equal(t, \"new content.pdf\", queryResult[0].ItemName, \"search query result incorrect\")\n}\n\nfunc TestInserting_DuplicateRecords_Count_As_Single(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\t// try inserting duplicate records\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\t// validate only a single record exists\n\tqueryResult, err := engine.QueryFileData(ctx, \"new content.pdf\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 1, len(queryResult), \"only single result should be returned\")\n\n\tassert.Equal(t, \"new content.pdf\", queryResult[0].ItemName, \"search query result incorrect\")\n}\n\nfunc TestFilesSearchEngine_Delete_And_Query(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"second-content.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\terr := engine.DeleteFileData(ctx, &search.DeleteIndexRecord{\n\t\tItemName:   \"new content.pdf\",\n\t\tItemPath:   \"/new\",\n\t\tBucketSlug: \"personal\",\n\t})\n\tassert.NilError(t, err, \"deleting file data failed\")\n\n\tqueryResult, err := engine.QueryFileData(ctx, \"content\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 1, len(queryResult), \"expected only single result\")\n\n\t// only second content should exist in search engine\n\tassert.Equal(t, \"second-content.txt\", queryResult[0].ItemName, \"search query result incorrect\")\n}\n\nfunc TestPrefixFileSearchWorks(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"hello1.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"hello2.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\tqueryResult, err := engine.QueryFileData(ctx, \"he\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 2, len(queryResult), \"query result not expected length\")\n\n}\n\nfunc TestInfixFileSearchWorks(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"hello1.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"hello2.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\tqueryResult, err := engine.QueryFileData(ctx, \"el\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 2, len(queryResult), \"query result not expected length\")\n\n}\n\nfunc insertRecord(\n\tt *testing.T,\n\tctx context.Context,\n\tengine search.FilesSearchEngine,\n\trecord *search.InsertIndexRecord,\n) {\n\t_, err := engine.InsertFileData(ctx, record)\n\tassert.NilError(t, err, \"failed to insert file data\")\n}\n"
  },
  {
    "path": "core/search/bleve/options.go",
    "content": "package bleve\n\nfunc WithDBPath(path string) Option {\n\treturn func(o *bleveSearchOption) {\n\t\to.dbPath = path\n\t}\n}\n"
  },
  {
    "path": "core/search/engines.go",
    "content": "package search\n\nimport (\n\t\"context\"\n)\n\n// Represents Search Engines for File and Folders\n// Can be used for indexing and querying of File/Folders\ntype FilesSearchEngine interface {\n\tStart() error\n\tInsertFileData(ctx context.Context, data *InsertIndexRecord) (*IndexRecord, error)\n\tDeleteFileData(ctx context.Context, data *DeleteIndexRecord) error\n\tQueryFileData(ctx context.Context, query string, limit int) ([]*IndexRecord, error)\n}\n"
  },
  {
    "path": "core/search/model.go",
    "content": "package search\n\ntype IndexRecord struct {\n\tId            string\n\tItemName      string\n\tItemExtension string\n\tItemPath      string\n\tItemType      string\n\t// Metadata here\n\tBucketSlug string\n\tDbId       string\n}\n\ntype InsertIndexRecord struct {\n\tItemName      string\n\tItemExtension string\n\tItemPath      string\n\tItemType      string\n\tBucketSlug    string\n\tDbId          string\n}\n\ntype DeleteIndexRecord struct {\n\tItemName   string\n\tItemPath   string\n\tBucketSlug string\n\tDbId       string // DbId is only required for shared content\n}\n"
  },
  {
    "path": "core/search/sqlite/model.go",
    "content": "package sqlite\n\nimport \"gorm.io/gorm\"\n\ntype SearchIndexRecord struct {\n\tgorm.Model\n\tItemName      string `gorm:\"index:idx_name_path_bucket,unique\"`\n\tItemExtension string `gorm:\"size:10\"`\n\tItemPath      string `gorm:\"index:idx_name_path_bucket,unique\"`\n\tItemType      string\n\tBucketSlug    string `gorm:\"index:idx_name_path_bucket,unique\"`\n\tDbId          string `gorm:\"index\"`\n}\n"
  },
  {
    "path": "core/search/sqlite/options.go",
    "content": "package sqlite\n\nimport \"gorm.io/gorm/logger\"\n\nfunc WithDBPath(path string) Option {\n\treturn func(o *sqliteSearchOption) {\n\t\to.dbPath = path\n\t}\n}\n\nfunc WithLogLevel(level logger.LogLevel) Option {\n\treturn func(o *sqliteSearchOption) {\n\t\to.logLevel = level\n\t}\n}\n"
  },
  {
    "path": "core/search/sqlite/sqlite.go",
    "content": "package sqlite\n\nimport (\n\t\"context\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"gorm.io/gorm/logger\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\n\t\"github.com/pkg/errors\"\n\t\"gorm.io/driver/sqlite\"\n\t\"gorm.io/gorm\"\n)\n\nconst DbFileName = \"filesIndex.db\"\n\ntype sqliteSearchOption struct {\n\tdbPath   string\n\tlogLevel logger.LogLevel\n}\n\ntype Option func(o *sqliteSearchOption)\n\n// sqliteFilesSearchEngine is a files search engine that is backed by sqlite\ntype sqliteFilesSearchEngine struct {\n\tdb   *gorm.DB\n\topts sqliteSearchOption\n}\n\n// Creates a new SQLite backed search engine for files and folders\nfunc NewSearchEngine(opts ...Option) *sqliteFilesSearchEngine {\n\tusr, _ := user.Current()\n\n\tsearchOptions := sqliteSearchOption{\n\t\tdbPath: filepath.Join(usr.HomeDir, \".fleek-space\"),\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(&searchOptions)\n\t}\n\n\treturn &sqliteFilesSearchEngine{\n\t\tdb:   nil,\n\t\topts: searchOptions,\n\t}\n}\n\nfunc (s *sqliteFilesSearchEngine) Start() error {\n\tdsn := filepath.Join(s.opts.dbPath, DbFileName)\n\n\tif db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{\n\t\tLogger: logger.Default.LogMode(s.opts.logLevel),\n\t}); err != nil {\n\t\treturn errors.Wrap(err, \"failed to open database\")\n\t} else {\n\t\ts.db = db\n\t}\n\n\treturn s.db.AutoMigrate(&SearchIndexRecord{})\n}\n\nfunc (s *sqliteFilesSearchEngine) InsertFileData(ctx context.Context, data *search.InsertIndexRecord) (*search.IndexRecord, error) {\n\trecord := SearchIndexRecord{\n\t\tItemName:      data.ItemName,\n\t\tItemExtension: data.ItemExtension,\n\t\tItemPath:      data.ItemPath,\n\t\tItemType:      data.ItemPath,\n\t\tBucketSlug:    data.BucketSlug,\n\t\tDbId:          data.DbId,\n\t}\n\tresult := s.db.Create(&record)\n\n\tif result.Error != nil {\n\t\tif strings.Contains(result.Error.Error(), \"UNIQUE constraint failed\") {\n\t\t\treturn nil, errors.New(\"a similar file has already been inserted\")\n\t\t}\n\t\treturn nil, result.Error\n\t}\n\n\treturn modelToIndexRecord(&record), nil\n}\n\nfunc (s *sqliteFilesSearchEngine) DeleteFileData(ctx context.Context, data *search.DeleteIndexRecord) error {\n\tstmt := s.db.Where(\n\t\t\"item_name = ? AND item_path = ? AND bucket_slug = ?\",\n\t\tdata.ItemName,\n\t\tdata.ItemPath,\n\t\tdata.BucketSlug,\n\t)\n\tif data.DbId != \"\" {\n\t\tstmt = stmt.Where(\"dbId = ?\", data.DbId)\n\t}\n\n\tresult := stmt.Delete(&SearchIndexRecord{})\n\n\treturn result.Error\n}\n\nfunc (s *sqliteFilesSearchEngine) QueryFileData(ctx context.Context, query string, limit int) ([]*search.IndexRecord, error) {\n\tvar records []*SearchIndexRecord\n\tresult := s.db.Where(\n\t\t\"LOWER(item_name) LIKE ? OR LOWER(item_extension) = ?\",\n\t\t\"%\"+strings.ToLower(query)+\"%\",\n\t\tstrings.ToLower(query),\n\t).Limit(limit).Find(&records)\n\n\tif result.Error != nil {\n\t\treturn nil, result.Error\n\t}\n\n\tsearchResults := make([]*search.IndexRecord, len(records))\n\tfor i, record := range records {\n\t\tsearchResults[i] = modelToIndexRecord(record)\n\t}\n\n\treturn searchResults, nil\n}\n\nfunc (s *sqliteFilesSearchEngine) Shutdown() error {\n\tdb, err := s.db.DB()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn db.Close()\n}\n\nfunc modelToIndexRecord(model *SearchIndexRecord) *search.IndexRecord {\n\treturn &search.IndexRecord{\n\t\tId:            strconv.Itoa(int(model.ID)),\n\t\tItemName:      model.ItemName,\n\t\tItemExtension: model.ItemExtension,\n\t\tItemPath:      model.ItemPath,\n\t\tItemType:      model.ItemType,\n\t\tBucketSlug:    model.BucketSlug,\n\t\tDbId:          model.DbId,\n\t}\n}\n"
  },
  {
    "path": "core/search/sqlite/sqlite_test.go",
    "content": "package sqlite\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\n\t\"gotest.tools/assert\"\n)\n\nfunc setupEngine(t *testing.T) (*sqliteFilesSearchEngine, context.Context) {\n\tdbPath, err := ioutil.TempDir(\"\", \"testDb-*\")\n\tassert.NilError(t, err, \"failed to create db path\")\n\n\tengine := NewSearchEngine(WithDBPath(dbPath))\n\tassert.NilError(t, engine.Start(), \"database failed to initialize\")\n\n\tcleanup := func() {\n\t\t_ = engine.Shutdown()\n\t\t_ = os.RemoveAll(dbPath)\n\t}\n\n\tt.Cleanup(cleanup)\n\n\treturn engine, context.Background()\n}\n\nfunc TestSqliteFilesSearchEngine_Insert_And_Query(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"second-content.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\tqueryResult, err := engine.QueryFileData(ctx, \"pdf\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 1, len(queryResult), \"not enough results returned from query\")\n\n\tassert.Equal(t, \"new content.pdf\", queryResult[0].ItemName, \"search query result incorrect\")\n}\n\nfunc TestInserting_DuplicateRecords_Fail(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\t// try inserting duplicate records should fail\n\t_, err := engine.InsertFileData(ctx, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\tassert.Error(t, err, \"a similar file has already been inserted\")\n}\n\nfunc TestSqliteFilesSearchEngine_Delete_And_Query(t *testing.T) {\n\tengine, ctx := setupEngine(t)\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"new content.pdf\",\n\t\tItemExtension: \"pdf\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\tinsertRecord(t, ctx, engine, &search.InsertIndexRecord{\n\t\tItemName:      \"second-content.txt\",\n\t\tItemExtension: \"txt\",\n\t\tItemPath:      \"/new\",\n\t\tItemType:      \"FILE\",\n\t\tBucketSlug:    \"personal\",\n\t\tDbId:          \"\",\n\t})\n\n\terr := engine.DeleteFileData(ctx, &search.DeleteIndexRecord{\n\t\tItemName:   \"new content.pdf\",\n\t\tItemPath:   \"/new\",\n\t\tBucketSlug: \"personal\",\n\t})\n\tassert.NilError(t, err, \"deleting file data failed\")\n\n\tqueryResult, err := engine.QueryFileData(ctx, \"content\", 20)\n\tassert.NilError(t, err, \"failed to query file data\")\n\tassert.Equal(t, 1, len(queryResult), \"too much result returned\")\n\n\t// only second content should exist in search engine\n\tassert.Equal(t, \"second-content.txt\", queryResult[0].ItemName, \"search query result incorrect\")\n}\n\nfunc insertRecord(\n\tt *testing.T,\n\tctx context.Context,\n\tengine search.FilesSearchEngine,\n\trecord *search.InsertIndexRecord,\n) {\n\t_, err := engine.InsertFileData(ctx, record)\n\tassert.NilError(t, err, \"failed to insert file data\")\n}\n"
  },
  {
    "path": "core/space/domain/domain.go",
    "content": "package domain\n\nimport \"fmt\"\n\ntype AppConfig struct {\n\tPort                 int\n\tAppPath              string\n\tTextileHubTarget     string\n\tTextileThreadsTarget string\n}\n\ntype DirEntry struct {\n\tPath          string\n\tIsDir         bool\n\tName          string\n\tSizeInBytes   string\n\tCreated       string\n\tUpdated       string\n\tFileExtension string\n\tMembers       []Member\n}\n\ntype ThreadInfo struct {\n\tAddresses []string\n\tKey       string\n}\n\ntype FileInfo struct {\n\tDirEntry\n\tIpfsHash          string\n\tBackedUp          bool\n\tLocallyAvailable  bool\n\tBackupInProgress  bool\n\tRestoreInProgress bool\n}\n\ntype OpenFileInfo struct {\n\tLocation string\n}\n\ntype KeyPair struct {\n\tPublicKey  string\n\tPrivateKey string\n}\n\ntype AddItemResult struct {\n\tSourcePath string\n\tBucketPath string\n\tBytes      int64\n\tError      error\n}\n\ntype AddItemsResponse struct {\n\tTotalFiles int64\n\tTotalBytes int64\n\tError      error\n}\n\ntype Member struct {\n\tAddress   string `json:\"address\"`\n\tPublicKey string `json:\"publicKey\"`\n}\n\ntype AddWatchFile struct {\n\tDbId       string `json:\"dbId\"`\n\tLocalPath  string `json:\"local_path\"`\n\tBucketPath string `json:\"bucket_path\"`\n\tBucketKey  string `json:\"bucket_key\"`\n\tBucketSlug string `json:\"bucket_slug\"`\n\tIsRemote   bool   `json:\"isRemote\"`\n\tCid        string `json:\"cid\"`\n}\n\ntype Identity struct {\n\tAddress   string `json:\"address\"`\n\tPublicKey string `json:\"publicKey\"`\n\tUsername  string `json:\"username\"`\n}\n\ntype APIError struct {\n\tMessage string `json:\"message\"`\n}\n\ntype FileSharingInfo struct {\n\tBucket            string\n\tSharedFileCid     string\n\tSharedFileKey     string\n\tSpaceDownloadLink string\n}\n\ntype NotificationTypes int\n\nconst (\n\tUNKNOWN NotificationTypes = iota\n\tINVITATION\n\tUSAGEALERT\n\tINVITATION_REPLY\n\tREVOKED_INVITATION\n)\n\ntype FullPath struct {\n\tDbId      string `json:\"dbId\"`\n\tBucketKey string `json:\"bucketKey\"`\n\tBucket    string `json:\"bucket\"`\n\tPath      string `json:\"path\"`\n}\n\ntype InvitationStatus int\n\nconst (\n\tPENDING  InvitationStatus = 0\n\tACCEPTED InvitationStatus = 1\n\tREJECTED InvitationStatus = 2\n)\n\ntype Invitation struct {\n\tInviterPublicKey string           `json:\"inviterPublicKey\"`\n\tInviteePublicKey string           `json:\"inviteePublicKey\"`\n\tInvitationID     string           `json:\"invitationID\"`\n\tStatus           InvitationStatus `json:\"status\"`\n\tItemPaths        []FullPath       `json:\"itemPaths\"`\n\tKeys             [][]byte         `json:\"keys\"`\n}\n\ntype InvitationReply struct {\n\tInvitationID string `json:\"invitationID\"`\n}\n\n// Represents when an inviter unshared access to previously shared files in ItemPaths\ntype RevokedInvitation struct {\n\tInviterPublicKey string     `json:\"inviterPublicKey\"`\n\tInviteePublicKey string     `json:\"inviteePublicKey\"`\n\tItemPaths        []FullPath `json:\"itemPaths\"`\n\tKeys             [][]byte   `json:\"keys\"`\n}\n\ntype UsageAlert struct {\n\tUsed    int64  `json:\"used\"`\n\tLimit   int64  `json:\"limit\"`\n\tMessage string `json:\"message\"`\n}\n\ntype MessageBody struct {\n\tType NotificationTypes `json:\"type\"`\n\tBody []byte            `json:\"body\"`\n}\n\ntype Notification struct {\n\tID               string            `json:\"id\"`\n\tSubject          string            `json:\"subject\"`\n\tBody             string            `json:\"body\"`\n\tNotificationType NotificationTypes `json:\"notificationType\"`\n\tCreatedAt        int64             `json:\"createdAt\"`\n\tReadAt           int64             `json:\"readAt\"`\n\t// QUESTION: is there a way to enforce that only one of the below is present\n\tInvitationValue        Invitation        `json:\"invitationValue\"`\n\tUsageAlertValue        UsageAlert        `json:\"usageAlertValue\"`\n\tInvitationAcceptValue  InvitationReply   `json:\"invitationAcceptValue\"`\n\tRevokedInvitationValue RevokedInvitation `json:\"revokedInvitationValue\"`\n\tRelatedObject          interface{}       `json:\"relatedObject\"`\n}\n\ntype APISessionTokens struct {\n\tHubToken      string\n\tServicesToken string\n}\n\ntype MirrorFile struct {\n\tPath              string\n\tBucketSlug        string\n\tBackup            bool\n\tShared            bool\n\tBackupInProgress  bool\n\tRestoreInProgress bool\n}\n\ntype SharedDirEntry struct {\n\tDbID         string\n\tBucket       string\n\tIsPublicLink bool\n\tFileInfo\n\tMembers  []Member // XXX: it is duplicated from FileInfo\n\tSharedBy string\n}\n\ntype SearchFileEntry struct {\n\tFileInfo\n\tBucket string\n\tDbID   string\n}\n\ntype KeyBackupType int\n\nconst (\n\tPASSWORD KeyBackupType = 0\n\tGOOGLE   KeyBackupType = 1\n\tTWITTER  KeyBackupType = 2\n\tEMAIL    KeyBackupType = 3\n)\n\nfunc (b KeyBackupType) String() string {\n\tswitch b {\n\tcase 0:\n\t\treturn \"password\"\n\tcase 1:\n\t\treturn \"google\"\n\tcase 2:\n\t\treturn \"twitter\"\n\tcase 3:\n\t\treturn \"email\"\n\tdefault:\n\t\treturn fmt.Sprintf(\"%d\", int(b))\n\t}\n}\n\n// SharedFilesRoleAction represents action to be performed on the role\ntype SharedFilesRoleAction int\n\nconst (\n\tDeleteRoleAction SharedFilesRoleAction = iota\n\tReadWriteRoleAction\n)\n"
  },
  {
    "path": "core/space/fuse/controller.go",
    "content": "package fuse\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/fuse/installer\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\n// Controller is the space domain controller for managing the VFS.\n// It is used by the grpc server and app/daemon generally\ntype Controller struct {\n\tcfg       config.Config\n\tvfs       VFS\n\tstore     store.Store\n\tinstall   installer.FuseInstaller\n\tisServed  bool\n\tmountLock sync.RWMutex\n\tmountPath string\n}\n\nvar DefaultFuseDriveName = \"Space\"\n\nfunc NewController(\n\tctx context.Context,\n\tcfg config.Config,\n\tstore store.Store,\n\tsfs *spacefs.SpaceFS,\n\tinstall installer.FuseInstaller,\n) *Controller {\n\tvfs := initVFS(ctx, sfs)\n\n\treturn &Controller{\n\t\tcfg:       cfg,\n\t\tstore:     store,\n\t\tvfs:       vfs,\n\t\tinstall:   install,\n\t\tisServed:  false,\n\t\tmountLock: sync.RWMutex{},\n\t}\n}\n\n// ShouldMount check the store and config to determine if the VFS drive was previously mounted\nfunc (s *Controller) ShouldMount() bool {\n\tif s.cfg.GetString(config.MountFuseDrive, \"false\") == \"true\" {\n\t\treturn true\n\t}\n\n\tmountFuseDrive, err := s.store.Get([]byte(config.MountFuseDrive))\n\tif err == nil {\n\t\tlog.Debug(\"Persisted mountFuseDrive\", fmt.Sprintf(\"state=%s\", string(mountFuseDrive)))\n\t\treturn string(mountFuseDrive) == \"true\"\n\t} else {\n\t\tlog.Debug(\"No persisted mountFuseDrive state found\")\n\t}\n\n\treturn false\n}\n\n// Mount mounts the vfs drive and immediately serves the handler.\n// It starts the Fuse Server in the background\nfunc (s *Controller) Mount() error {\n\ts.mountLock.Lock()\n\tdefer s.mountLock.Unlock()\n\n\tif s.vfs.IsMounted() {\n\t\treturn nil\n\t}\n\n\tmountPath, err := getMountPath(s.cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.mountPath = mountPath\n\n\terr = s.vfs.Mount(\n\t\tmountPath,\n\t\ts.cfg.GetString(config.FuseDriveName, DefaultFuseDriveName),\n\t)\n\n\tif err != nil {\n\t\tif !strings.Contains(err.Error(), \"exit status 64\") {\n\t\t\treturn err\n\t\t}\n\n\t\t// a drive mount error, so we try unmounting first and retry mounting\n\t\t_ = s.vfs.Unmount()\n\t\ts.removeMountedPath()\n\t\terr = s.vfs.Mount(\n\t\t\tmountPath,\n\t\t\ts.cfg.GetString(config.FuseDriveName, DefaultFuseDriveName),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// persist mount state to store to trigger remount on restart\n\tif err := s.store.Set([]byte(config.MountFuseDrive), []byte(\"true\")); err != nil {\n\t\treturn err\n\t}\n\n\ts.serve()\n\treturn nil\n}\n\nfunc (s *Controller) GetMountPath() string {\n\tif !s.IsMounted() {\n\t\treturn \"\"\n\t}\n\n\tpath, _ := getMountPath(s.cfg)\n\treturn path\n}\n\nfunc (s *Controller) serve() {\n\tif s.isServed {\n\t\treturn\n\t}\n\n\tgo func() {\n\t\ts.isServed = true\n\t\tdefer func() {\n\t\t\ts.isServed = false\n\t\t}()\n\n\t\t// this blocks and unblocks when vfs.Unmount() is called\n\t\t// or some external thing happens like user unmounting the drive\n\t\terr := s.vfs.Serve()\n\t\tif err != nil {\n\t\t\tlog.Error(\"error ending fuse server\", err)\n\t\t}\n\t\tlog.Info(\"FUSE Controller server ended\")\n\t}()\n}\n\nfunc (s *Controller) IsMounted() bool {\n\ts.mountLock.RLock()\n\tdefer s.mountLock.RUnlock()\n\treturn s.vfs.IsMounted()\n}\n\nfunc (s *Controller) Unmount() error {\n\ts.mountLock.Lock()\n\tdefer s.mountLock.Unlock()\n\tif !s.vfs.IsMounted() {\n\t\treturn nil\n\t}\n\n\t// persist unmount state to store to prevent remount on restart\n\tif err := s.store.Set([]byte(config.MountFuseDrive), []byte(\"false\")); err != nil {\n\t\treturn err\n\t}\n\n\terr := s.vfs.Unmount()\n\n\treturn err\n}\n\nfunc (s *Controller) removeMountedPath() {\n\tif s.mountPath != \"\" {\n\t\t// try unmounting via os\n\t\terr := exec.Command(\"umount\", s.mountPath).Run()\n\t\tlog.Error(\"Failed to run unmount command\", err)\n\t\terr = os.RemoveAll(s.mountPath)\n\t\tlog.Error(\"Failed to delete mount directory on unmount\", err)\n\t}\n}\n\nfunc (s *Controller) Shutdown() error {\n\treturn s.Unmount()\n}\n"
  },
  {
    "path": "core/space/fuse/fs.go",
    "content": "package fuse\n\n// VFS represents the handler for virtually mounted drives.\n// it is implemented using FUSE for linux and macOS\n// and will use dokany for windows\ntype VFS interface {\n\tMount(mountPath, fsName string) error\n\tIsMounted() bool\n\t// Serve should be a blocking call and return only on unmount or shutdown\n\tServe() error\n\tUnmount() error\n}\n"
  },
  {
    "path": "core/space/fuse/installer/installer_darwin.go",
    "content": "package installer\n\nimport (\n\t\"context\"\n\t\"os/exec\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/keybase/go-kext\"\n)\n\ntype State int64\n\nconst (\n\tDefault State = iota\n\tDownloading\n\tInstalling\n\tError\n)\n\ntype macFuseInstaller struct {\n\tstate State\n}\n\nfunc NewFuseInstaller() *macFuseInstaller {\n\treturn &macFuseInstaller{\n\t\tstate: Default,\n\t}\n}\n\nfunc (d *macFuseInstaller) IsInstalled(ctx context.Context) (bool, error) {\n\tinfo, err := kext.LoadInfo(\"com.github.osxfuse.filesystems.osxfuse\")\n\tif err != nil {\n\t\tlog.Error(\"unable to determine state of extension\", err)\n\t\treturn false, err\n\t}\n\n\treturn info != nil, nil\n}\n\n// Install assumes that the Fuse .pkg installer exists in a particular directory\nfunc (d *macFuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {\n\t// ideally, this should download the fuse pkg and call the installer\n\n\t// first starting with providing a path for it, will change to download as this is a security risk\n\td.state = Installing\n\tpath, ok := args[\"path\"].(string)\n\tif !ok {\n\t\treturn errors.New(\"'path' is missing from install arguments\")\n\t}\n\n\tinstallerPath, err := exec.LookPath(\"installer\")\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"pkg installer not present\")\n\t}\n\n\tcmd := exec.Command(installerPath, \"-pkg\", path, \"-target\", \"/\")\n\tout, err := cmd.CombinedOutput()\n\tlog.Debug(\"Install command output: \" + string(out))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// load the kernel extension\n\treturn d.loadKernel()\n}\n\nfunc (d *macFuseInstaller) loadKernel() error {\n\tlog.Debug(\"Loading OSXFUSE Kernel\")\n\tcmd := exec.Command(\"/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse\")\n\toutput, err := cmd.CombinedOutput()\n\tlog.Debug(\"Kernel Loading Output: \" + string(output))\n\treturn err\n}\n"
  },
  {
    "path": "core/space/fuse/installer/installer_darwin_test.go",
    "content": "package installer\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// NOTE: This is more of an integration test and is commented out by default till functional test-suite is ready\nfunc TestMacFuseInstaller(t *testing.T) {\n\tctx := context.Background()\n\tinstaller := NewFuseInstaller()\n\n\tinstalled, err := installer.IsInstalled(ctx)\n\tassert.NoError(t, err)\n\tassert.Equal(t, false, installed, \"fuse should not be installed by default\")\n}\n"
  },
  {
    "path": "core/space/fuse/installer/installer_linux.go",
    "content": "package installer\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\ntype linuxFuseInstaller struct {\n}\n\nfunc NewFuseInstaller() *linuxFuseInstaller {\n\treturn &linuxFuseInstaller{}\n}\n\nfunc (d *linuxFuseInstaller) IsInstalled(ctx context.Context) (bool, error) {\n\treturn true, nil // assume fuse is installed on recent linux builds\n}\n\nfunc (d *linuxFuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {\n\treturn errors.New(\"not supported\")\n}\n"
  },
  {
    "path": "core/space/fuse/installer/installer_windows.go",
    "content": "package installer\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\ntype windowsFuseInstaller struct {\n}\n\nfunc NewFuseInstaller() *windowsFuseInstaller {\n\treturn &windowsFuseInstaller{}\n}\n\nfunc (d *windowsFuseInstaller) IsInstalled(ctx context.Context) (bool, error) {\n\treturn false, nil\n}\n\nfunc (d *windowsFuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {\n\treturn errors.New(\"not supported\")\n}\n"
  },
  {
    "path": "core/space/fuse/installer/interface.go",
    "content": "package installer\n\nimport \"context\"\n\ntype FuseInstaller interface {\n\tIsInstalled(ctx context.Context) (bool, error)\n\tInstall(ctx context.Context, args map[string]interface{}) error\n\t// TODO: UnInstall(ctx context.Context)\n}\n"
  },
  {
    "path": "core/space/fuse/mount.go",
    "content": "//+build !windows\n\npackage fuse\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\ts \"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/libfuse\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/mitchellh/go-homedir\"\n)\n\nfunc pathExists(path string) bool {\n\t_, err := os.Stat(path)\n\treturn os.IsExist(err)\n}\n\nfunc getMountPath(cfg config.Config) (string, error) {\n\tmountPath := cfg.GetString(config.FuseMountPath, \"~/\"+DefaultFuseDriveName)\n\tif home, err := homedir.Dir(); err == nil {\n\t\t// If the mount directory contains ~, we replace it with the actual home directory\n\t\tmountPath = s.TrimRight(\n\t\t\ts.Replace(mountPath, \"~\", home, -1),\n\t\t\t\"/\",\n\t\t)\n\t}\n\n\t// checks to ensure we are not mounting on an already existing path\n\tif pathExists(mountPath) {\n\t\t// loop through 10 suffixes till we find on that exists\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tnewPath := fmt.Sprintf(\"%s%d\", mountPath, i)\n\t\t\tif !pathExists(newPath) {\n\t\t\t\tmountPath = newPath\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn mountPath, nil\n}\n\nfunc initVFS(ctx context.Context, sfs spacefs.FSOps) VFS {\n\treturn libfuse.NewVFileSystem(ctx, sfs)\n}\n"
  },
  {
    "path": "core/space/fuse/mount_windows.go",
    "content": "package fuse\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n)\n\nvar errNotImplemented = errors.New(\"fuse not implemented for windows\")\n\nfunc pathExists(path string) bool {\n\treturn false\n}\n\nfunc getMountPath(cfg config.Config) (string, error) {\n\treturn \"\", errNotImplemented\n}\n\nfunc initVFS(ctx context.Context, sfs spacefs.FSOps) VFS {\n\treturn &dummyVFS{}\n}\n\n// dummyVFS acts a placeholder vfs for windows pending the actual implementation\ntype dummyVFS struct{}\n\nfunc (d dummyVFS) Mount(mountPath, fsName string) error {\n\treturn errNotImplemented\n}\n\nfunc (d dummyVFS) IsMounted() bool {\n\treturn false\n}\n\nfunc (d dummyVFS) Serve() error {\n\treturn errNotImplemented\n}\n\nfunc (d dummyVFS) Unmount() error {\n\treturn errNotImplemented\n}\n"
  },
  {
    "path": "core/space/fuse/state.go",
    "content": "package fuse\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\ntype State string\n\nconst (\n\tUNSUPPORTED   State = \"UNSUPPORTED\"\n\tNOT_INSTALLED State = \"NOT_INSTALLED\"\n\tUNMOUNTED     State = \"UNMOUNTED\"\n\tMOUNTED       State = \"MOUNTED\"\n\tERROR         State = \"ERROR\"\n)\n\nvar supportedOs = map[string]bool{\n\t\"linux\":  true,\n\t\"darwin\": true,\n}\n\nfunc (s *Controller) GetFuseState(ctx context.Context) (State, error) {\n\tif !supportedOs[runtime.GOOS] {\n\t\treturn UNSUPPORTED, nil\n\t}\n\n\tif s.IsMounted() {\n\t\treturn MOUNTED, nil\n\t}\n\n\t// try and get if it is installed\n\tinstalled, err := s.install.IsInstalled(ctx)\n\tif err != nil {\n\t\tlog.Error(\"unable to determine state of extension\", err)\n\t\treturn ERROR, err\n\t}\n\n\tif !installed {\n\t\treturn NOT_INSTALLED, err\n\t}\n\n\treturn UNMOUNTED, nil\n}\n"
  },
  {
    "path": "core/space/fuse/state_test.go",
    "content": "// +build linux darwin\n\npackage fuse\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spacefs\"\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\tfusemocks \"github.com/FleekHQ/space-daemon/mocks/fuse\"\n)\n\ntype testCtx struct {\n\tcfg       *mocks.Config\n\tst        *mocks.Store\n\tfsds      *fusemocks.FSDataSource\n\tinstaller *fusemocks.FuseInstaller\n}\n\nfunc initTestCtx() (context.Context, *testCtx, *Controller) {\n\ttctx := &testCtx{\n\t\tcfg:       new(mocks.Config),\n\t\tst:        new(mocks.Store),\n\t\tfsds:      new(fusemocks.FSDataSource),\n\t\tinstaller: new(fusemocks.FuseInstaller),\n\t}\n\n\tctx := context.Background()\n\tfs := spacefs.New(tctx.fsds)\n\n\tcontroller := NewController(ctx, tctx.cfg, tctx.st, fs, tctx.installer)\n\treturn ctx, tctx, controller\n}\n\nfunc TestController_GetFuseState_ShouldDefaultTo_Not_Installed(t *testing.T) {\n\tctx, test, controller := initTestCtx()\n\n\ttest.installer.On(\"IsInstalled\", mock.Anything).Return(false, nil)\n\n\tstate, err := controller.GetFuseState(ctx)\n\tassert.NoError(t, err, \"error on GetFuseState()\")\n\n\tassert.Equal(t, NOT_INSTALLED, state, \"unexpected state gotten\")\n}\n\n// Note: This is more of an integration test than unit test, but should run cleanly across multiple threads\nfunc TestController_GetFuseState_ShouldBe_Unmounted_When_Installed(t *testing.T) {\n\tctx, test, controller := initTestCtx()\n\n\ttest.installer.On(\"IsInstalled\", mock.Anything).Return(true, nil)\n\n\tstate, err := controller.GetFuseState(ctx)\n\tassert.NoError(t, err, \"error on GetFuseState()\")\n\n\tassert.Equal(t, UNMOUNTED, state, \"unexpected state gotten\")\n}\n"
  },
  {
    "path": "core/space/services/fs_utils.go",
    "content": "package services\n\nimport (\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nfunc PathExists(path string) bool {\n\tif _, err := os.Stat(path); err == nil {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc IsPathDir(path string) bool {\n\tfi, err := os.Stat(path)\n\tif err != nil {\n\t\tlog.Error(\"path error check isPathDir\", err)\n\t\treturn false\n\t}\n\tmode := fi.Mode()\n\n\treturn mode.IsDir()\n}\n\nfunc RemoveDuplicates(elements []string) []string {\n\t// Use map to record duplicates as we find them.\n\tencountered := map[string]bool{}\n\tresult := []string{}\n\n\tfor v := range elements {\n\t\tif encountered[elements[v]] == true {\n\t\t\t// Do not add duplicate.\n\t\t} else {\n\t\t\t// Record this element as an encountered element.\n\t\t\tencountered[elements[v]] = true\n\t\t\t// Append to result slice.\n\t\t\tresult = append(result, elements[v])\n\t\t}\n\t}\n\t// Return the new slice.\n\treturn result\n}\n\n// Reader that also counts the amount of Bytes read from the wrappeed reader\ntype CountingReader struct {\n\treader    io.Reader\n\tBytesRead int64\n}\n\nfunc NewCountingReader(reader io.Reader) *CountingReader {\n\treturn &CountingReader{\n\t\treader:    reader,\n\t\tBytesRead: 0,\n\t}\n}\n\nfunc (r *CountingReader) Read(b []byte) (int, error) {\n\tn, err := r.reader.Read(b)\n\tr.BytesRead += int64(n)\n\treturn n, err\n}\n"
  },
  {
    "path": "core/space/services/services.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/core/vault\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\tnode \"github.com/FleekHQ/space-daemon/core/ipfs/node\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n)\n\n// Implementation for space.Service\ntype Space struct {\n\tstore    store.Store\n\tcfg      config.Config\n\tenv      env.SpaceEnv\n\ttc       textile.Client\n\tsync     Syncer\n\tkeychain keychain.Keychain\n\tvault    vault.Vault\n\thub      hub.HubAuth\n\tipfsNode *node.IpfsNode\n\tbuckd    textile.Buckd\n\taeg      *errgroup.Group\n}\n\ntype Syncer interface {\n\tAddFileWatch(addFileInfo domain.AddWatchFile) error\n\tGetOpenFilePath(bucketSlug, bucketPath, dbID, cid string) (string, bool)\n}\n\ntype AddFileWatchFunc = func(addFileInfo domain.AddWatchFile) error\n\nfunc (s *Space) RegisterSyncer(sync Syncer) {\n\ts.sync = sync\n}\n\nfunc (s *Space) GetConfig(ctx context.Context) domain.AppConfig {\n\treturn domain.AppConfig{\n\t\tPort:                 s.cfg.GetInt(config.SpaceServerPort, \"-1\"),\n\t\tAppPath:              s.env.WorkingFolder(),\n\t\tTextileHubTarget:     s.cfg.GetString(config.TextileHubTarget, \"\"),\n\t\tTextileThreadsTarget: s.cfg.GetString(config.TextileThreadsTarget, \"\"),\n\t}\n\n}\n\nfunc NewSpace(\n\tst store.Store,\n\ttc textile.Client,\n\tsyncer Syncer,\n\tcfg config.Config,\n\tenv env.SpaceEnv,\n\tkc keychain.Keychain,\n\tv vault.Vault,\n\th hub.HubAuth,\n) *Space {\n\treturn &Space{\n\t\tstore:    st,\n\t\tcfg:      cfg,\n\t\tenv:      env,\n\t\ttc:       tc,\n\t\tsync:     syncer,\n\t\tkeychain: kc,\n\t\tvault:    v,\n\t\thub:      h,\n\t}\n}\n\nvar textileClientInitTimeout = time.Second * 60\nvar textileClientHubTimeout = time.Second * 60 * 3\n\n// Waits for textile client to be initialized before returning.\nfunc (s *Space) waitForTextileInit(ctx context.Context) error {\n\tif s.tc.IsInitialized() {\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase <-time.After(textileClientInitTimeout):\n\t\treturn errors.New(\"textile client not initialized in expected time\")\n\tcase <-s.tc.WaitForInitialized():\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n}\n\n// Waits for textile client to be healthy (initialized and connected to hub) before returning.\n// If it exceeds the max amount of retries, it returns an error.\nfunc (s *Space) waitForTextileHub(ctx context.Context) error {\n\tif s.tc.IsHealthy() {\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase err := <-s.tc.WaitForHealthy():\n\t\t// This returns error if there were 3 failed attempts to connect\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\tcase <-time.After(textileClientHubTimeout):\n\t\treturn errors.New(\"textile client not initialized in expected time\")\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n}\n"
  },
  {
    "path": "core/space/services/services_app_token.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n)\n\nfunc (s *Space) InitializeMasterAppToken(ctx context.Context) (*permissions.AppToken, error) {\n\tnewAppToken, err := permissions.GenerateRandomToken(true, []string{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newAppToken, s.keychain.StoreAppToken(newAppToken)\n}\n"
  },
  {
    "path": "core/space/services/services_central_server.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\n// Return session token for central services authenticated access\nfunc (s *Space) GetAPISessionTokens(ctx context.Context) (*domain.APISessionTokens, error) {\n\ttokens, err := s.hub.GetTokensWithCache(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &domain.APISessionTokens{\n\t\tHubToken:      tokens.HubToken,\n\t\tServicesToken: tokens.AppToken,\n\t}, nil\n}\n"
  },
  {
    "path": "core/space/services/services_fs.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nvar bucketNotFoundErr = errors.New(\"Could not find bucket\")\n\n// Creates a bucket\nfunc (s *Space) CreateBucket(ctx context.Context, slug string) (textile.Bucket, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb, err := s.tc.CreateBucket(ctx, slug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b, nil\n}\n\n// Returns a list of buckets the current user has access to\nfunc (s *Space) ListBuckets(ctx context.Context) ([]textile.Bucket, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbuckets, err := s.tc.ListBuckets(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buckets, nil\n}\n\nfunc (s *Space) ShareBucket(ctx context.Context, slug string) (*domain.ThreadInfo, error) {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tr, err := s.tc.ShareBucket(ctx, slug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\taddrs := make([]string, 0)\n\n\tfor _, addr := range r.Addrs {\n\t\taddrs = append(addrs, addr.String())\n\t}\n\n\tti := &domain.ThreadInfo{\n\t\tAddresses: addrs,\n\t\tKey:       r.Key.String(),\n\t}\n\n\treturn ti, nil\n}\n\nfunc (s *Space) JoinBucket(ctx context.Context, slug string, threadinfo *domain.ThreadInfo) (bool, error) {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tr, err := s.tc.JoinBucket(ctx, slug, threadinfo)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn r, nil\n}\n\nfunc (s *Space) ToggleBucketBackup(ctx context.Context, bucketSlug string, bucketBackup bool) error {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = s.tc.ToggleBucketBackup(ctx, bucketSlug, bucketBackup)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = s.tc.GetBucket(ctx, bucketSlug, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) BucketBackupRestore(ctx context.Context, bucketSlug string) error {\n\tif err := s.waitForTextileHub(ctx); err != nil {\n\t\treturn err\n\t}\n\tif err := s.tc.BucketBackupRestore(ctx, bucketSlug); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) getBucketForRemoteFile(ctx context.Context, bucketName, dbID, path string) (textile.Bucket, error) {\n\tinput := &textile.GetBucketForRemoteFileInput{\n\t\tBucket: bucketName,\n\t\tDbID:   dbID,\n\t\tPath:   path,\n\t}\n\tb, err := s.tc.GetBucket(ctx, bucketName, input)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif b == nil {\n\t\treturn nil, bucketNotFoundErr\n\t}\n\n\treturn b, nil\n}\n\n// Returns the bucket given the name, and if the name is \"\" returns the default bucket\nfunc (s *Space) getBucketWithFallback(ctx context.Context, bucketName string) (textile.Bucket, error) {\n\tvar b textile.Bucket\n\tvar err error\n\n\tif bucketName == \"\" {\n\t\tb, err = s.tc.GetDefaultBucket(ctx)\n\t} else {\n\t\tb, err = s.tc.GetBucket(ctx, bucketName, nil)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif b == nil {\n\t\treturn nil, bucketNotFoundErr\n\t}\n\n\treturn b, nil\n}\n\nfunc (s *Space) listDirAtPath(\n\tctx context.Context,\n\tb textile.Bucket,\n\tpath string,\n\tlistSubfolderContent bool,\n\tlistMembers bool,\n) ([]domain.FileInfo, error) {\n\tdir, err := b.ListDirectory(ctx, path)\n\tif err != nil {\n\t\tlog.Error(\"Error in ListDir\", err)\n\t\treturn nil, err\n\t}\n\n\trelPathRegex := regexp.MustCompile(`\\/ip(f|n)s\\/[^\\/]*(?P<relPath>\\/.*)`)\n\n\tmirrorfilepaths := make([]string, 0)\n\tfor _, item := range dir.Item.Items {\n\t\tmirrorfilepaths = append(mirrorfilepaths, item.Path)\n\t}\n\n\tmirror_files, err := s.tc.GetModel().FindMirrorFileByPaths(ctx, mirrorfilepaths)\n\tif err != nil {\n\t\tlog.Error(\"Error fetching mirror files\", err)\n\t\treturn nil, err\n\t}\n\n\tentries := make([]domain.FileInfo, 0)\n\tfor _, item := range dir.Item.Items {\n\t\tif utils.IsMetaFileName(item.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tpaths := relPathRegex.FindStringSubmatch(item.Path)\n\t\tvar relPath string\n\t\tif len(paths) > 2 {\n\t\t\trelPath = relPathRegex.FindStringSubmatch(item.Path)[2]\n\t\t} else {\n\t\t\trelPath = item.Path\n\t\t}\n\n\t\tmembers := []domain.Member{}\n\n\t\tif listMembers {\n\t\t\tmembers, err = s.tc.GetPathAccessRoles(ctx, b, item.Path)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tbackedup := false\n\t\tbackupInProgress := false\n\t\trestoreInProgress := false\n\t\tif mirror_files[item.Path] != nil {\n\t\t\tbackedup = mirror_files[item.Path].Backup\n\t\t\tbackupInProgress = mirror_files[item.Path].BackupInProgress\n\t\t\trestoreInProgress = mirror_files[item.Path].RestoreInProgress\n\t\t}\n\n\t\tlocallyAvailable := false\n\t\tif item.IsDir {\n\t\t\tlocallyAvailable = true\n\t\t} else if e, _ := b.FileExists(ctx, item.Path); e == true {\n\t\t\tlocallyAvailable = true\n\t\t}\n\n\t\tentry := domain.FileInfo{\n\t\t\tDirEntry: domain.DirEntry{\n\t\t\t\tPath:          relPath,\n\t\t\t\tIsDir:         item.IsDir,\n\t\t\t\tName:          item.Name,\n\t\t\t\tSizeInBytes:   strconv.FormatInt(item.Size, 10),\n\t\t\t\tFileExtension: strings.Replace(filepath.Ext(item.Name), \".\", \"\", -1),\n\t\t\t\t// FIXME: real created at needed\n\t\t\t\tCreated: time.Unix(0, item.Metadata.UpdatedAt).Format(time.RFC3339),\n\t\t\t\tUpdated: time.Unix(0, item.Metadata.UpdatedAt).Format(time.RFC3339),\n\t\t\t\tMembers: members,\n\t\t\t},\n\t\t\tIpfsHash:          item.Cid,\n\t\t\tBackedUp:          backedup,\n\t\t\tLocallyAvailable:  locallyAvailable,\n\t\t\tBackupInProgress:  backupInProgress,\n\t\t\tRestoreInProgress: restoreInProgress,\n\t\t}\n\t\tentries = append(entries, entry)\n\n\t\tif item.IsDir && listSubfolderContent {\n\t\t\tnewEntries, err := s.listDirAtPath(ctx, b, path+\"/\"+item.Name, true, listMembers)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tentries = append(entries, newEntries...)\n\t\t}\n\t}\n\n\treturn entries, nil\n}\n\n// ListDir returns children entries at path in a bucket\nfunc (s *Space) ListDir(ctx context.Context, path string, bucketName string, listMembers bool) ([]domain.FileInfo, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb, err := s.getBucketWithFallback(ctx, bucketName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif b == nil {\n\t\treturn nil, errors.New(\"Could not find buckets\")\n\t}\n\n\treturn s.listDirAtPath(ctx, b, path, false, listMembers)\n}\n\n// ListDirs lists all children entries at path in a bucket\n// Unlike ListDir, it includes all subfolders children recursively\nfunc (s *Space) ListDirs(ctx context.Context, path string, bucketName string, listMembers bool) ([]domain.FileInfo, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb, err := s.getBucketWithFallback(ctx, bucketName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn s.listDirAtPath(ctx, b, path, true, listMembers)\n}\n\n// Copies a file inside a bucket into a temp, unencrypted version of the file in the local file system\n// Include dbID if opening a shared file. Use dbID = \"\" otherwise.\nfunc (s *Space) OpenFile(ctx context.Context, path, bucketName, dbID string) (domain.OpenFileInfo, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\n\tisRemote := dbID != \"\"\n\tvar filePath string\n\tvar b textile.Bucket\n\t// check if file exists in sync\n\tif isRemote {\n\t\tb, err = s.getBucketForRemoteFile(ctx, bucketName, dbID, path)\n\t} else {\n\t\tb, err = s.getBucketWithFallback(ctx, bucketName)\n\t}\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\tlistdir, err := b.ListDirectory(ctx, path)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\tcid := listdir.Item.Cid\n\tif filePath, exists := s.sync.GetOpenFilePath(b.Slug(), path, dbID, cid); exists {\n\t\t// sanity check in case file was deleted or moved\n\t\tif PathExists(filePath) {\n\t\t\t// return file handle\n\t\t\treturn domain.OpenFileInfo{\n\t\t\t\tLocation: filePath,\n\t\t\t}, nil\n\t\t}\n\t}\n\n\t// else, open new file on FS\n\tfilePath, err = s.openFileOnFs(ctx, path, b, isRemote, dbID, cid)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\n\t// return file handle\n\treturn domain.OpenFileInfo{\n\t\tLocation: filePath,\n\t}, nil\n}\n\n// TruncateData removes all data from local machine\nfunc (s *Space) TruncateData(ctx context.Context) error {\n\t// not doing anything with store because it's\n\t// handled in DeleteKeyPair\n\n\t// note: this might not clear storage\n\t// so need to verify and update later\n\terr := s.tc.DeleteAccount(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) openFileOnFs(ctx context.Context, path string, b textile.Bucket, isRemote bool, dbID, cid string) (string, error) {\n\t// write file copy to temp folder\n\ttmpFile, err := s.createTempFileForPath(ctx, path)\n\tif err != nil {\n\t\tlog.Error(\"cannot create temp file while executing OpenFile\", err)\n\t\treturn \"\", err\n\t}\n\tdefer tmpFile.Close()\n\n\t// look for path in textile\n\terr = b.GetFile(ctx, path, tmpFile)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error retrieving file from bucket %s in path %s\", b.Key(), path), err)\n\t\treturn \"\", err\n\t}\n\n\t// register temp file in watcher\n\taddWatchFile := domain.AddWatchFile{\n\t\tDbId:       dbID,\n\t\tLocalPath:  tmpFile.Name(),\n\t\tBucketPath: path,\n\t\tBucketKey:  b.Key(),\n\t\tBucketSlug: b.Slug(),\n\t\tIsRemote:   isRemote,\n\t\tCid:        cid,\n\t}\n\n\terr = s.sync.AddFileWatch(addWatchFile)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error adding file to watch path %s from bucket %s in bucketpath %s\", tmpFile.Name(), b.Key(), path), err)\n\t\treturn \"\", err\n\t}\n\treturn tmpFile.Name(), nil\n}\n\n// createTempFileForPath creates a temporary file using the path specified relative to the AppPath\n// configured when running the daemon. If inTempDir is true, then it is created relative\n// to the operating systems temp dir.\nfunc (s *Space) createTempFileForPath(ctx context.Context, path string) (*os.File, error) {\n\t_, fileName := filepath.Split(path)\n\n\t// NOTE: the pattern of the file ensures that it retains extension. e.g (rand num) + filename/path\n\treturn ioutil.TempFile(\"\", \"*-\"+fileName)\n}\n\nfunc (s *Space) CreateFolder(ctx context.Context, path string, bucketName string) error {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb, err := s.getBucketWithFallback(ctx, bucketName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := s.createFolder(ctx, path, b); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) createFolder(ctx context.Context, path string, b textile.Bucket) (string, error) {\n\t// NOTE: may need to change signature of createFolder if we need to return this info\n\t_, root, err := b.CreateDirectory(ctx, path)\n\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error creating folder in bucket %s with path %s\", b.Key(), path), err)\n\t\treturn \"\", err\n\t}\n\n\treturn root.String(), nil\n}\n\nfunc (s *Space) AddItems(ctx context.Context, sourcePaths []string, targetPath string, bucketName string) (<-chan domain.AddItemResult, domain.AddItemsResponse, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, domain.AddItemsResponse{}, err\n\t}\n\n\t// check if all sourcePaths exist, else return err\n\tfor _, sourcePath := range sourcePaths {\n\t\tif !PathExists(sourcePath) {\n\t\t\treturn nil, domain.AddItemsResponse{}, errors.New(fmt.Sprintf(\"path not found at %s\", sourcePath))\n\t\t}\n\t}\n\n\tb, err := s.getBucketWithFallback(ctx, bucketName)\n\tif err != nil {\n\t\treturn nil, domain.AddItemsResponse{}, err\n\t}\n\tresults := make(chan domain.AddItemResult)\n\n\ttotalsRes, err := getTotals(RemoveDuplicates(sourcePaths))\n\tif err != nil {\n\t\treturn nil, domain.AddItemsResponse{}, err\n\t}\n\tgo func() {\n\t\ts.addItems(ctx, RemoveDuplicates(sourcePaths), targetPath, b, results)\n\t\tclose(results)\n\t}()\n\n\treturn results, totalsRes, nil\n}\n\n// AddItemWithReader uploads content of the reader to the targetPath on the bucket specified\n//\n// Note: the AddItemResult returns an empty SourcePath\nfunc (s *Space) AddItemWithReader(\n\tctx context.Context,\n\treader io.Reader,\n\ttargetPath, bucketName string,\n) (domain.AddItemResult, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn domain.AddItemResult{}, err\n\t}\n\n\tb, err := s.getBucketWithFallback(ctx, bucketName)\n\tif err != nil {\n\t\treturn domain.AddItemResult{}, err\n\t}\n\n\tcountingReader := NewCountingReader(reader)\n\t_, root, err := b.UploadFile(ctx, targetPath, countingReader)\n\tif err != nil {\n\t\treturn domain.AddItemResult{}, err\n\t}\n\n\treturn domain.AddItemResult{\n\t\tBucketPath: root.String(),\n\t\tBytes:      countingReader.BytesRead,\n\t}, nil\n}\n\n// get totals for addItems operation\nfunc getTotals(sourcePaths []string) (domain.AddItemsResponse, error) {\n\tvar wg sync.WaitGroup\n\twg.Add(len(sourcePaths))\n\tfilesRes := make(chan domain.AddItemsResponse)\n\tresults := make([]domain.AddItemsResponse, 0)\n\tfor _, sourcePath := range sourcePaths {\n\t\tgo func(pathInFs string) {\n\t\t\tdefer wg.Done()\n\t\t\tif IsPathDir(pathInFs) {\n\t\t\t\t// counting folder as a file in total with 0 bytes\n\t\t\t\tfilesRes <- domain.AddItemsResponse{\n\t\t\t\t\tTotalFiles: 1,\n\t\t\t\t\tTotalBytes: 0,\n\t\t\t\t}\n\t\t\t\t// get recursive\n\t\t\t\tvar folderSubPaths []string\n\t\t\t\tfiles, err := ioutil.ReadDir(pathInFs)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Error(fmt.Sprintf(\"error reading folder path %s \", pathInFs), err)\n\t\t\t\t\tfilesRes <- domain.AddItemsResponse{\n\t\t\t\t\t\tError: err,\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor _, file := range files {\n\t\t\t\t\tsubPath := pathInFs + \"/\" + file.Name()\n\t\t\t\t\tif subPath != pathInFs {\n\t\t\t\t\t\tfolderSubPaths = append(folderSubPaths, subPath)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfolderSubPathsRes, err := getTotals(folderSubPaths)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfilesRes <- domain.AddItemsResponse{\n\t\t\t\t\t\tError: err,\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfilesRes <- folderSubPathsRes\n\t\t\t} else {\n\t\t\t\t// get totals bytes\n\t\t\t\tfi, err := os.Stat(pathInFs)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Error(fmt.Sprintf(\"error getting file size %s \", pathInFs), err)\n\t\t\t\t\tfilesRes <- domain.AddItemsResponse{\n\t\t\t\t\t\tError: err,\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// get the size\n\t\t\t\tfilesRes <- domain.AddItemsResponse{\n\t\t\t\t\tTotalFiles: 1,\n\t\t\t\t\tTotalBytes: fi.Size(),\n\t\t\t\t}\n\t\t\t}\n\t\t}(sourcePath)\n\t}\n\n\tresultsDone := make(chan struct{})\n\tvar collectErr error\n\ttotalResult := domain.AddItemsResponse{}\n\n\tgo func() {\n\t\t// collect results\n\t\tfor chRes := range filesRes {\n\t\t\tif chRes.Error != nil {\n\t\t\t\tcollectErr = chRes.Error\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresults = append(results, chRes)\n\t\t}\n\n\t\tfor _, res := range results {\n\t\t\ttotalResult.TotalBytes += res.TotalBytes\n\t\t\ttotalResult.TotalFiles += res.TotalFiles\n\t\t}\n\t\tresultsDone <- struct{}{}\n\t}()\n\n\twg.Wait()\n\t// closing channel to close results handling goroutine\n\tclose(filesRes)\n\t// wait for all results to finish\n\t<-resultsDone\n\n\tif collectErr != nil {\n\t\treturn totalResult, collectErr\n\t}\n\n\treturn totalResult, nil\n}\n\nfunc (s *Space) addItems(ctx context.Context, sourcePaths []string, targetPath string, b textile.Bucket, results chan<- domain.AddItemResult) error {\n\t// NOTE: sequential upload of files and folders\n\tfor _, sourcePath := range sourcePaths {\n\t\tif IsPathDir(sourcePath) {\n\t\t\ts.handleAddItemFolder(ctx, sourcePath, targetPath, b, results)\n\t\t} else {\n\t\t\t// add files\n\t\t\tr, err := s.addFile(ctx, sourcePath, targetPath, b)\n\t\t\tif err != nil {\n\t\t\t\tresults <- domain.AddItemResult{\n\t\t\t\t\tSourcePath: sourcePath,\n\t\t\t\t\tError:      err,\n\t\t\t\t}\n\t\t\t\t// next iteration\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresults <- domain.AddItemResult{\n\t\t\t\tSourcePath: sourcePath,\n\t\t\t\tBucketPath: r.BucketPath,\n\t\t\t\tBytes:      r.Bytes,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) handleAddItemFolder(ctx context.Context, sourcePath string, targetPath string, b textile.Bucket, results chan<- domain.AddItemResult) {\n\t// create folder\n\t_, folderName := filepath.Split(sourcePath)\n\ttargetBucketFolder := targetPath + \"/\" + folderName\n\tfolderBucketPath, err := s.createFolder(ctx, targetBucketFolder, b)\n\tif err != nil {\n\t\tresults <- domain.AddItemResult{\n\t\t\tSourcePath: sourcePath,\n\t\t\tError:      err,\n\t\t}\n\t\treturn\n\t}\n\n\tresults <- domain.AddItemResult{\n\t\tSourcePath: sourcePath,\n\t\tBucketPath: folderBucketPath,\n\t}\n\terr = s.addFolderRec(sourcePath, targetBucketFolder, ctx, b, results)\n\tif err != nil {\n\t\tresults <- domain.AddItemResult{\n\t\t\tSourcePath: sourcePath,\n\t\t\tError:      err,\n\t\t}\n\t\treturn\n\t}\n}\n\nfunc (s *Space) addFolderRec(sourcePath string, targetPath string, ctx context.Context, b textile.Bucket, results chan<- domain.AddItemResult) error {\n\tvar folderSubPaths []string\n\n\t// NOTE: only reading each folder one level deep since this function is recursive\n\t// if we use Walk we would need to track source paths across recursive calls to avoid duplicates\n\tfiles, err := ioutil.ReadDir(sourcePath)\n\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error reading folder path %s \", sourcePath), err)\n\t\treturn err\n\t}\n\n\tfor _, file := range files {\n\t\tif file.Name() != sourcePath {\n\t\t\tfolderSubPaths = append(folderSubPaths, sourcePath+\"/\"+file.Name())\n\t\t}\n\t}\n\n\t// recursive call to addItems\n\treturn s.addItems(ctx, folderSubPaths, targetPath, b, results)\n}\n\n// Working with a file\nfunc (s *Space) addFile(ctx context.Context, sourcePath string, targetPath string, b textile.Bucket) (domain.AddItemResult, error) {\n\t// get sourcePath to io.Reader\n\tf, err := os.Open(sourcePath)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error opening path %s\", sourcePath), err)\n\t\treturn domain.AddItemResult{}, err\n\t}\n\n\tdefer f.Close()\n\n\t_, fileName := filepath.Split(sourcePath)\n\n\tvar targetPathBucket string\n\tif targetPath == \"\" || targetPath == \"/\" {\n\t\ttargetPathBucket = fileName\n\t} else {\n\t\ttargetPathBucket = targetPath + \"/\" + fileName\n\t}\n\n\t// NOTE: could modify addFile to return back more info for processing\n\t_, root, err := b.UploadFile(ctx, targetPathBucket, f)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"error creating targetPath %s in bucket %s\", targetPathBucket, b.Key()), err)\n\t\treturn domain.AddItemResult{}, err\n\t}\n\n\tfi, err := f.Stat()\n\tvar fileSize int64 = 0\n\tif err == nil {\n\t\tfileSize = fi.Size()\n\t}\n\treturn domain.AddItemResult{\n\t\tSourcePath: sourcePath,\n\t\tBucketPath: root.String(),\n\t\tBytes:      fileSize,\n\t}, err\n}\n\n// Removes a file or directory from a bucket\n// Note: If removing a file a user has been shared, call the RemoveMember method instead, as this works only for local buckets.\nfunc (s *Space) RemoveDirOrFile(ctx context.Context, path, bucketName string) error {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb, err := s.getBucketWithFallback(ctx, bucketName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = b.DeleteDirOrFile(ctx, path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/space/services/services_identity.go",
    "content": "package services\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\ntype createIdentityRequest struct {\n\tPublicKey string `json:\"publicKey\"`\n\tUsername  string `json:\"username\"`\n}\n\nfunc parseIdentity(resp *http.Response) (*domain.Identity, error) {\n\tbody, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode < 200 || resp.StatusCode >= 400 {\n\t\tvar returnedErr domain.APIError\n\t\terr = json.Unmarshal(body, &returnedErr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif returnedErr.Message != \"\" {\n\t\t\treturn nil, errors.New(returnedErr.Message)\n\t\t}\n\n\t\treturn nil, errors.New(\"Unexpected API error\")\n\t}\n\n\tvar newIdentity domain.Identity\n\terr = json.Unmarshal(body, &newIdentity)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &newIdentity, nil\n\n}\n\n// Creates an identity in Space cloud services. Returns the created identity or an error if any.\nfunc (s *Space) CreateIdentity(ctx context.Context, username string) (*domain.Identity, error) {\n\tpub, err := s.keychain.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpublicKeyBytes, err := pub.Raw()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpublicKeyHex := hex.EncodeToString(publicKeyBytes)\n\n\tidentity := &createIdentityRequest{\n\t\tPublicKey: publicKeyHex,\n\t\tUsername:  username,\n\t}\n\tidentityJSON, err := json.Marshal(identity)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tapiURL := s.cfg.GetString(config.SpaceServicesAPIURL, \"\")\n\tresp, err := http.Post(\n\t\tapiURL+\"/identities\",\n\t\t\"application/json\",\n\t\tbytes.NewBuffer(identityJSON),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\treturn parseIdentity(resp)\n}\n\n// Gets an identity from Space cloud services given a username\nfunc (s *Space) GetIdentityByUsername(ctx context.Context, username string) (*domain.Identity, error) {\n\tapiURL := s.cfg.GetString(config.SpaceServicesAPIURL, \"\")\n\tresp, err := http.Get(apiURL + \"/identities/username/\" + username)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\treturn parseIdentity(resp)\n}\n"
  },
  {
    "path": "core/space/services/services_keypair.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n)\n\n// Generates a key pair and returns a mnemonic for recovering that key later on\nfunc (s *Space) GenerateKeyPair(ctx context.Context, useForce bool) (string, error) {\n\tvar mnemonic string\n\tvar err error\n\tif useForce {\n\t\tmnemonic, err = s.keychain.GenerateKeyFromMnemonic(keychain.WithOverride())\n\t} else {\n\t\tmnemonic, err = s.keychain.GenerateKeyFromMnemonic()\n\t}\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn mnemonic, nil\n}\n\nfunc (s *Space) RestoreKeyPairFromMnemonic(ctx context.Context, mnemonic string) error {\n\t_, err := s.keychain.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic), keychain.WithOverride())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.tc.RestoreDB(ctx); err != nil {\n\t\ts.keychain.DeleteKeypair()\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) GetPublicKey(ctx context.Context) (string, error) {\n\tpub, err := s.keychain.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpublicKeyBytes, err := pub.Raw()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpublicKeyHex := hex.EncodeToString(publicKeyBytes)\n\n\treturn publicKeyHex, nil\n}\n\nfunc (s *Space) GetHubAuthToken(ctx context.Context) (string, error) {\n\ttokens, err := s.hub.GetTokensWithCache(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn tokens.HubToken, nil\n}\n\nfunc (s *Space) GetMnemonic(ctx context.Context) (string, error) {\n\tmnemonic, err := s.keychain.GetStoredMnemonic()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif mnemonic == \"\" {\n\t\treturn \"\", errors.New(\"No mnemonic seed stored in the keychain\")\n\t}\n\n\treturn mnemonic, nil\n}\n\nfunc (s *Space) DeleteKeypair(ctx context.Context) error {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Tell the textile client to stop operations\n\tif err := s.tc.RemoveKeys(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.keychain.DeleteKeypair(); err != nil {\n\t\treturn err\n\t}\n\n\t// Clear badger store\n\tif err := s.store.DropAll(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/space/services/services_notifs.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\nconst notificationsLastSeenAtStoreKey = \"notificationsLastSeenAt\"\n\nfunc (s *Space) GetNotifications(ctx context.Context, seek string, limit int) ([]*domain.Notification, error) {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tr, err := s.tc.GetMailAsNotifications(ctx, seek, limit)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r, nil\n}\n\nfunc (s *Space) SetNotificationsLastSeenAt(timestamp int64) error {\n\tt := strconv.FormatInt(timestamp, 10)\n\terr := s.store.Set([]byte(notificationsLastSeenAtStoreKey), []byte(t))\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (s *Space) GetNotificationsLastSeenAt() (int64, error) {\n\tts, err := s.store.Get([]byte(notificationsLastSeenAtStoreKey))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\ti, err := strconv.ParseInt(string(ts), 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn i, nil\n}\n"
  },
  {
    "path": "core/space/services/services_search.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\nfunc (s *Space) SearchFiles(ctx context.Context, query string) ([]domain.SearchFileEntry, error) {\n\tsearchResult, err := s.tc.GetModel().QuerySearchIndex(ctx, query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresultEntries := make([]domain.SearchFileEntry, len(searchResult))\n\n\tfor i, result := range searchResult {\n\t\tresultEntries[i] = domain.SearchFileEntry{\n\t\t\tFileInfo: domain.FileInfo{\n\t\t\t\tDirEntry: domain.DirEntry{\n\t\t\t\t\tPath:          strings.TrimPrefix(result.ItemPath, fmt.Sprintf(\"%c\", os.PathSeparator)),\n\t\t\t\t\tIsDir:         result.ItemType == string(model.DirectoryItem),\n\t\t\t\t\tName:          result.ItemName,\n\t\t\t\t\tFileExtension: result.ItemExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\tBucket: result.BucketSlug,\n\t\t\tDbID:   result.DbId,\n\t\t}\n\t}\n\n\treturn resultEntries, nil\n}\n"
  },
  {
    "path": "core/space/services/services_sharing.go",
    "content": "package services\n\nimport (\n\t\"archive/zip\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/opentracing/opentracing-go\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tt \"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/textileio/dcrypto\"\n)\n\nfunc (s *Space) GenerateFileSharingLink(\n\tctx context.Context,\n\tencryptionPassword string,\n\tpath string,\n\tbucketName string,\n\tdbID string,\n) (domain.FileSharingInfo, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"Space.GenerateFileSharingLink\")\n\tdefer span.Finish()\n\n\t_, fileName := filepath.Split(path)\n\n\tvar bucket t.Bucket\n\tvar err error\n\n\tif dbID != \"\" {\n\t\tbucket, err = s.getBucketForRemoteFile(ctx, bucketName, dbID, path)\n\t} else {\n\t\tbucket, err = s.getBucketWithFallback(ctx, bucketName)\n\t}\n\tif err != nil {\n\t\treturn domain.FileSharingInfo{}, err\n\t}\n\n\tencryptedFile, err := s.encryptBucketFile(ctx, encryptionPassword, path, bucket)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"file encryption failed\")\n\t}\n\n\t_, err = encryptedFile.Seek(0, 0)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"file encryption failed\")\n\t}\n\n\tlog.Debug(\"Uploading shared file\")\n\treturn s.uploadSharedFileToIpfs(\n\t\tctx,\n\t\tencryptionPassword,\n\t\tencryptedFile,\n\t\tfileName,\n\t\tbucketName,\n\t)\n}\n\nfunc (s *Space) encryptBucketFile(\n\tctx context.Context,\n\tpassword string,\n\tbucketPath string,\n\tbucket t.Bucket,\n) (*os.File, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"Space.encryptBucketFile\")\n\tdefer span.Finish()\n\n\t// tempFile is written from textile before encryption\n\ttempFile, err := s.createTempFileForPath(ctx, bucketPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\ttempFile.Close()\n\t\t_ = os.Remove(tempFile.Name())\n\t}()\n\n\t// encrypted file is the final encrypted file\n\tencryptedFile, err := s.createTempFileForPath(ctx, bucketPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = bucket.GetFile(ctx, bucketPath, tempFile)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"file encryption failed\")\n\t}\n\t_, err = tempFile.Seek(0, 0)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"file encryption failed\")\n\t}\n\tencryptedReader, err := dcrypto.NewEncrypterWithPassword(tempFile, []byte(password))\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"file encryption failed\")\n\t}\n\n\tlog.Debug(\"Copying encrypted file to disk\")\n\t_, err = io.Copy(encryptedFile, encryptedReader)\n\treturn encryptedFile, err\n}\n\n// uploads the shared file to ipfs through users public bucket in hub\nfunc (s *Space) uploadSharedFileToIpfs(\n\tctx context.Context,\n\tpassword string,\n\tsharedContent io.Reader,\n\tfileName string,\n\tbucketName string,\n) (domain.FileSharingInfo, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"Space.uploadSharedFileToIpfs\")\n\tdefer span.Finish()\n\n\tb, err := s.tc.GetPublicShareBucket(ctx)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"failed to get public files bucket\")\n\t}\n\n\ttimestamp := time.Now().UnixNano()\n\tuploadResult, _, err := b.UploadFile(ctx, fmt.Sprintf(\"%s-%d\", fileName, timestamp), sharedContent)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"publishing shared file failed\")\n\t}\n\n\tencryptedFileHash := uploadResult.Cid().String()\n\n\turlQuery := url.Values{}\n\turlQuery.Add(\"fname\", fileName)\n\turlQuery.Add(\"hash\", encryptedFileHash)\n\n\treturn domain.FileSharingInfo{\n\t\tBucket:        bucketName,\n\t\tSharedFileCid: encryptedFileHash,\n\t\tSharedFileKey: password,\n\t\tSpaceDownloadLink: fmt.Sprintf(\n\t\t\t\"%s/files/share?%s\",\n\t\t\ts.cfg.GetString(config.SpaceStorageSiteUrl, \"https://app.space.storage\"),\n\t\t\turlQuery.Encode(),\n\t\t),\n\t}, nil\n}\n\n// GenerateFilesSharingLink zips multiple files together\nfunc (s *Space) GenerateFilesSharingLink(\n\tctx context.Context,\n\tencryptionPassword string,\n\tpaths []string,\n\tbucketName, dbID string,\n) (domain.FileSharingInfo, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"Space.GenerateFilesSharingLink\")\n\tdefer span.Finish()\n\n\tif len(paths) == 0 {\n\t\treturn EmptyFileSharingInfo, errors.New(\"no file passed to share link\")\n\t}\n\tif len(paths) == 1 {\n\t\treturn s.GenerateFileSharingLink(ctx, encryptionPassword, paths[0], bucketName, dbID)\n\t}\n\n\tvar bucket t.Bucket\n\tvar err error\n\n\tif dbID != \"\" {\n\t\t// Safe to use the first path to get the bucket as all shared files should be under the same dbID\n\t\tbucket, err = s.getBucketForRemoteFile(ctx, bucketName, dbID, paths[0])\n\t} else {\n\t\tbucket, err = s.getBucketWithFallback(ctx, bucketName)\n\t}\n\tif err != nil {\n\t\treturn domain.FileSharingInfo{}, err\n\t}\n\n\t// create zip file output\n\tfilename := generateFilesSharingZip()\n\t// tempFile is written from textile before encryption\n\ttempFile, err := s.createTempFileForPath(ctx, filename)\n\tif err != nil {\n\t\treturn domain.FileSharingInfo{}, err\n\t}\n\tdefer func() {\n\t\ttempFile.Close()\n\t\t_ = os.Remove(tempFile.Name())\n\t}()\n\n\tencryptedFile, err := s.createTempFileForPath(ctx, filename)\n\tif err != nil {\n\t\treturn domain.FileSharingInfo{}, err\n\t}\n\tdefer encryptedFile.Close()\n\n\tzipper := zip.NewWriter(tempFile)\n\t// write each file to zip\n\tfor _, path := range paths {\n\t\t_, fileName := filepath.Split(path)\n\t\twriter, err := zipper.Create(fileName)\n\t\tif err != nil {\n\t\t\treturn EmptyFileSharingInfo, errors.Wrap(err, fmt.Sprintf(\"failed to compress item: %s\", path))\n\t\t}\n\n\t\terr = bucket.GetFile(ctx, path, writer)\n\t\tif err != nil {\n\t\t\treturn EmptyFileSharingInfo, errors.Wrap(err, fmt.Sprintf(\"failed to compress item: %s\", path))\n\t\t}\n\t}\n\n\terr = zipper.Close()\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"creating compressed file failed\")\n\t}\n\n\t_, err = tempFile.Seek(0, 0)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"file encryption failed\")\n\t}\n\tencryptedReader, err := dcrypto.NewEncrypterWithPassword(tempFile, []byte(encryptionPassword))\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"file encryption failed\")\n\t}\n\n\t_, err = io.Copy(encryptedFile, encryptedReader)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, err\n\t}\n\n\t_, err = encryptedFile.Seek(0, 0)\n\tif err != nil {\n\t\treturn EmptyFileSharingInfo, errors.Wrap(err, \"encryption failed\")\n\t}\n\n\treturn s.uploadSharedFileToIpfs(\n\t\tctx,\n\t\tencryptionPassword,\n\t\tencryptedFile,\n\t\tfilename,\n\t\tbucketName,\n\t)\n}\n\n// OpenSharedFile fetched the ipfs file and decrypts it with the key. Then returns the decrypted\n// files location. NOTE: This only opens public link shared files and not those shared via direct invites.\nfunc (s *Space) OpenSharedFile(ctx context.Context, hash, password, filename string) (domain.OpenFileInfo, error) {\n\tparsedCid, err := cid.Parse(hash)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\n\terr = s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\n\tif password == \"\" {\n\t\t// try to fetch password from shared files\n\t\t_, password, err = s.tc.GetPublicReceivedFile(ctx, hash, true)\n\t\tif err != nil {\n\t\t\treturn domain.OpenFileInfo{}, errors.Wrap(err, \"password is required to open this file\")\n\t\t}\n\t}\n\n\tencryptedFile, err := s.tc.DownloadPublicItem(ctx, parsedCid)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\tdefer encryptedFile.Close()\n\n\tdecryptedFile, err := s.createTempFileForPath(ctx, filename)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, err\n\t}\n\tdefer decryptedFile.Close()\n\n\treader, err := dcrypto.NewDecrypterWithPassword(encryptedFile, []byte(password))\n\tif err != nil {\n\t\tlog.Error(\"initializing decrypter failed\", err)\n\t\treturn domain.OpenFileInfo{}, errors.New(\"incorrect password\")\n\t}\n\n\tdecryptedFileSize, err := io.Copy(decryptedFile, reader)\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, errors.Wrap(err, \"decryption failed\")\n\t}\n\n\t// Add accessed file to shared with me list\n\t_, err = s.tc.AcceptSharedFileLink(ctx, hash, password, filename, strconv.FormatInt(decryptedFileSize, 10))\n\tif err != nil {\n\t\treturn domain.OpenFileInfo{}, errors.Wrap(err, \"accepting shared link failed\")\n\t}\n\n\treturn domain.OpenFileInfo{\n\t\tLocation: decryptedFile.Name(),\n\t}, nil\n}\n\nfunc (s *Space) ShareFilesViaPublicKey(ctx context.Context, paths []domain.FullPath, pubkeys []crypto.PubKey) error {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tenhancedPaths, enckeys, err := s.resolveFullPaths(ctx, paths)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor i, path := range enhancedPaths {\n\t\t_, err = s.tc.GetModel().CreateSentFileViaInvitation(ctx, path, \"\", enckeys[i])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\terr = s.tc.ManageShareFilesViaPublicKey(ctx, enhancedPaths, pubkeys, enckeys, domain.ReadWriteRoleAction)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, pk := range pubkeys {\n\t\tinviter, err := s.keychain.GetStoredPublicKey()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tinviterRaw, err := inviter.Raw()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpkRaw, err := pk.Raw()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\td := &domain.Invitation{\n\t\t\tInviterPublicKey: hex.EncodeToString(inviterRaw),\n\t\t\tInviteePublicKey: hex.EncodeToString(pkRaw),\n\t\t\tItemPaths:        enhancedPaths,\n\t\t\tKeys:             enckeys,\n\t\t}\n\n\t\ti, err := json.Marshal(d)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tb := &domain.MessageBody{\n\t\t\tType: domain.INVITATION,\n\t\t\tBody: i,\n\t\t}\n\n\t\tj, err := json.Marshal(b)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = s.tc.SendMessage(ctx, pk, j)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *Space) resolveFullPaths(ctx context.Context, paths []domain.FullPath) ([]domain.FullPath, [][]byte, error) {\n\tm := s.tc.GetModel()\n\n\tenhancedPaths := make([]domain.FullPath, len(paths))\n\tenckeys := make([][]byte, len(paths))\n\tfor i, path := range paths {\n\t\tep := domain.FullPath{\n\t\t\tDbId:      path.DbId,\n\t\t\tBucket:    path.Bucket,\n\t\t\tPath:      path.Path,\n\t\t\tBucketKey: path.BucketKey,\n\t\t}\n\n\t\t// this handles personal bucket since for shared-with-me files\n\t\t// the dbid will be preset\n\t\tif ep.DbId == \"\" {\n\t\t\tb, err := s.tc.GetDefaultBucket(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\tbs, err := m.FindBucket(ctx, b.Slug())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\tep.DbId = bs.RemoteDbID\n\t\t}\n\n\t\tif ep.Bucket == \"\" || ep.Bucket == t.GetDefaultBucketSlug() {\n\t\t\tb, err := s.tc.GetDefaultBucket(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tbs, err := m.FindBucket(ctx, b.GetData().Name)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tep.Bucket = t.GetDefaultMirrorBucketSlug()\n\t\t\tep.BucketKey = bs.RemoteBucketKey\n\t\t\tenckeys[i] = bs.EncryptionKey\n\t\t} else {\n\t\t\tr, err := m.FindReceivedFile(ctx, path.DbId, path.Bucket, path.Path)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tep.Bucket = r.Bucket\n\t\t\tep.BucketKey = r.BucketKey\n\t\t\tenckeys[i] = r.EncryptionKey\n\t\t}\n\n\t\tenhancedPaths[i] = ep\n\t}\n\n\treturn enhancedPaths, enckeys, nil\n}\n\nfunc (s *Space) UnshareFilesViaPublicKey(ctx context.Context, paths []domain.FullPath, pubkeys []crypto.PubKey) error {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tenhancedPaths, enckeys, err := s.resolveFullPaths(ctx, paths)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = s.tc.ManageShareFilesViaPublicKey(ctx, enhancedPaths, pubkeys, enckeys, domain.DeleteRoleAction)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn s.sendPathsRevokedInvitation(ctx, pubkeys, enhancedPaths, enckeys)\n}\n\nfunc (s *Space) sendPathsRevokedInvitation(\n\tctx context.Context,\n\tpubkeys []crypto.PubKey,\n\tenhancedPaths []domain.FullPath,\n\tkeys [][]byte,\n) error {\n\tfor _, pk := range pubkeys {\n\t\tuninviter, err := s.keychain.GetStoredPublicKey()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trawUniviter, err := uninviter.Raw()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpkRaw, err := pk.Raw()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\td := &domain.RevokedInvitation{\n\t\t\tInviterPublicKey: hex.EncodeToString(rawUniviter),\n\t\t\tInviteePublicKey: hex.EncodeToString(pkRaw),\n\t\t\tItemPaths:        enhancedPaths,\n\t\t\tKeys:             keys,\n\t\t}\n\n\t\ti, err := json.Marshal(d)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tb := &domain.MessageBody{\n\t\t\tType: domain.REVOKED_INVITATION,\n\t\t\tBody: i,\n\t\t}\n\n\t\tj, err := json.Marshal(b)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = s.tc.SendMessage(ctx, pk, j)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nvar errInvitationNotFound = errors.New(\"invitation not found\")\nvar errFailedToNotifyInviter = errors.New(\"failed to notify inviter of invitation status\")\n\n// HandleSharedFilesInvitation accepts or rejects an invitation based on the invitation id\nfunc (s *Space) HandleSharedFilesInvitation(ctx context.Context, invitationId string, accept bool) error {\n\terr := s.waitForTextileHub(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tn, err := s.tc.GetMailAsNotifications(ctx, invitationId, 1)\n\tif err != nil {\n\t\tlog.Error(\"failed to get invitation\", err)\n\t\treturn errInvitationNotFound\n\t}\n\n\tif len(n) == 0 {\n\t\tlog.Debug(\"shared file invitation not found\", \"invitationId:\"+invitationId)\n\t\treturn errInvitationNotFound\n\t}\n\n\tinvitation, err := extractInvitation(n[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif accept {\n\t\tinvitation, err = s.tc.AcceptSharedFilesInvitation(ctx, invitation)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// notify inviter,  it was accepted\n\t\tinvitersPk, err := decodePublicKey(err, invitation.InviterPublicKey)\n\t\tif err != nil {\n\t\t\tlog.Error(\"should not happen, but inviters public key is invalid\", err)\n\t\t\treturn errFailedToNotifyInviter\n\t\t}\n\n\t\tmessageBody, err := json.Marshal(&invitation)\n\t\tif err != nil {\n\t\t\tlog.Error(\"error encoding invitation response body\", err)\n\t\t\treturn errFailedToNotifyInviter\n\t\t}\n\n\t\tmessage, err := json.Marshal(&domain.MessageBody{\n\t\t\tType: domain.INVITATION_REPLY,\n\t\t\tBody: messageBody,\n\t\t})\n\n\t\tif err != nil {\n\t\t\tlog.Error(\"error encoding invitation response\", err)\n\t\t\treturn errFailedToNotifyInviter\n\t\t}\n\n\t\t_, err = s.tc.SendMessage(ctx, invitersPk, message)\n\t} else {\n\t\tinvitation, err = s.tc.RejectSharedFilesInvitation(ctx, invitation)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn err\n}\n\nfunc (s *Space) AddRecentlySharedPublicKeys(ctx context.Context, pubkeys []crypto.PubKey) error {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar ps string\n\n\tfor _, pk := range pubkeys {\n\t\tb, err := pk.Raw()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tps = hex.EncodeToString(b)\n\n\t\t// TODO: transaction\n\t\t_, err = s.tc.GetModel().CreateSharedPublicKey(ctx, ps)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *Space) RecentlySharedPublicKeys(ctx context.Context) ([]crypto.PubKey, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := []crypto.PubKey{}\n\n\tkeys, err := s.tc.GetModel().ListSharedPublicKeys(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, schema := range keys {\n\t\tb, err := hex.DecodeString(schema.PublicKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp, err := crypto.UnmarshalEd25519PublicKey([]byte(b))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tret = append(ret, p)\n\t}\n\n\treturn ret, nil\n}\n\n// Returns a list of shared files the user has received and accepted\nfunc (s *Space) GetSharedWithMeFiles(ctx context.Context, seek string, limit int) ([]*domain.SharedDirEntry, string, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\titems, offset, err := s.tc.GetReceivedFiles(ctx, true, seek, limit)\n\n\treturn items, offset, err\n}\n\n// Returns a list of shared files the user has shared\nfunc (s *Space) GetSharedByMeFiles(ctx context.Context, seek string, limit int) ([]*domain.SharedDirEntry, string, error) {\n\terr := s.waitForTextileInit(ctx)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\titems, offset, err := s.tc.GetSentFiles(ctx, seek, limit)\n\n\treturn items, offset, err\n}\n"
  },
  {
    "path": "core/space/services/services_vault.go",
    "content": "package services\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/backup\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/vault\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n)\n\nconst separator = \"___\"\n\n// Creates an obfuscated local file that contains everything needed to restore the state from this or another device\nfunc (s *Space) CreateLocalKeysBackup(ctx context.Context, path string) error {\n\tpriv, _, err := s.keychain.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprivInBytes, err := priv.Raw()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb := &backup.Backup{\n\t\tPrivateKey: hex.EncodeToString(privInBytes),\n\t}\n\n\tif err := backup.MarshalBackup(path, b); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Restores the state by receiving the path to a local backup\n// Warning: This will delete any local state before restoring the backup\nfunc (s *Space) RecoverKeysByLocalBackup(ctx context.Context, path string) error {\n\t// Retrieve the backup\n\tb, err := backup.UnmarshalBackup(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprivInBytes, err := hex.DecodeString(b.PrivateKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Restore keychain\n\tpriv, err := crypto.UnmarshalEd25519PrivateKey(privInBytes)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := s.keychain.ImportExistingKeyPair(priv, \"\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.tc.RestoreDB(ctx); err != nil {\n\t\ts.keychain.DeleteKeypair()\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Uses vault service to fetch and decrypt a keypair set\nfunc (s *Space) RecoverKeysByPassphrase(ctx context.Context, uuid string, pass string, backupType domain.KeyBackupType) error {\n\titems, err := s.vault.Retrieve(uuid, pass, backupType)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(items) == 0 {\n\t\treturn errors.New(\"Retrieved vault does not contain keys\")\n\t}\n\n\t// TODO: Generalize to N keys\n\tprivAndMnemonic := strings.Split(items[0].Value, separator)\n\tprivInBytes, err := hex.DecodeString(privAndMnemonic[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tunmarshalledPriv, err := crypto.UnmarshalEd25519PrivateKey(privInBytes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.keychain.ImportExistingKeyPair(unmarshalledPriv, privAndMnemonic[1]); err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.tc.RestoreDB(ctx); err != nil {\n\t\ts.keychain.DeleteKeypair()\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Uses the vault service to securely store the current keypair\nfunc (s *Space) BackupKeysByPassphrase(ctx context.Context, uuid string, pass string, backupType domain.KeyBackupType) error {\n\ttokens, err := s.GetAPISessionTokens(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpriv, _, err := s.keychain.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprivInBytes, err := priv.Raw()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmnemonic, err := s.keychain.GetStoredMnemonic()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TODO: Generalize to item array once we support multiple keys\n\titem := vault.VaultItem{\n\t\tItemType: vault.PrivateKeyWithMnemonic,\n\t\tValue:    hex.EncodeToString(privInBytes) + separator + mnemonic,\n\t}\n\n\titems := []vault.VaultItem{item}\n\n\tif _, err := s.vault.Store(uuid, pass, backupType, tokens.ServicesToken, items); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Tests a passphrase without storing anything to check if the passphrase is correct\nfunc (s *Space) TestPassphrase(ctx context.Context, uuid string, pass string) error {\n\titems, err := s.vault.Retrieve(uuid, pass, domain.PASSWORD)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(items) == 0 {\n\t\treturn errors.New(\"Retrieved vault does not contain keys\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/space/services/sharing_utils.go",
    "content": "package services\n\nimport (\n\t\"encoding/hex\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tcrypto \"github.com/libp2p/go-libp2p-crypto\"\n)\n\nvar EmptyFileSharingInfo = domain.FileSharingInfo{}\n\nfunc generateFilesSharingZip() string {\n\t//return fmt.Sprintf(\"space_shared_files-%d.zip\", time.Now().UnixNano())\n\treturn \"space_shared_files.zip\"\n}\n\nfunc extractInvitation(notification *domain.Notification) (domain.Invitation, error) {\n\tif notification.NotificationType != domain.INVITATION {\n\t\treturn domain.Invitation{}, errInvitationNotFound\n\t}\n\n\tnotification.InvitationValue.InvitationID = notification.ID\n\treturn notification.InvitationValue, nil\n}\n\n// NOTE: This assumes that the public key string is ed25519 hex encoded string\nfunc decodePublicKey(err error, pkString string) (crypto.PubKey, error) {\n\tpkBytes, err := hex.DecodeString(pkString)\n\tif err != nil {\n\t\treturn nil, errors.New(\"invalid encoding for public key\")\n\t}\n\n\tpk, err := crypto.UnmarshalEd25519PublicKey(pkBytes)\n\tif err != nil {\n\t\treturn nil, errors.New(\"invalid public key format\")\n\t}\n\treturn pk, nil\n}\n"
  },
  {
    "path": "core/space/space.go",
    "content": "package space\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/core/vault\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/services\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n)\n\n// Service Layer should not depend on gRPC dependencies\ntype Service interface {\n\tRegisterSyncer(sync services.Syncer)\n\tOpenFile(ctx context.Context, path, bucketName, dbID string) (domain.OpenFileInfo, error)\n\tGetConfig(ctx context.Context) domain.AppConfig\n\tListDirs(ctx context.Context, path string, bucketName string, listMembers bool) ([]domain.FileInfo, error)\n\tListDir(ctx context.Context, path string, bucketName string, listMembers bool) ([]domain.FileInfo, error)\n\tGenerateKeyPair(ctx context.Context, useForce bool) (mnemonic string, err error)\n\tDeleteKeypair(ctx context.Context) error\n\tGetMnemonic(ctx context.Context) (mnemonic string, err error)\n\tRestoreKeyPairFromMnemonic(ctx context.Context, mnemonic string) error\n\tRecoverKeysByPassphrase(ctx context.Context, uuid string, pass string, backupType domain.KeyBackupType) error\n\tBackupKeysByPassphrase(ctx context.Context, uuid string, pass string, backupType domain.KeyBackupType) error\n\tTestPassphrase(ctx context.Context, uuid string, pass string) error\n\tGetPublicKey(ctx context.Context) (string, error)\n\tGetHubAuthToken(ctx context.Context) (string, error)\n\tCreateFolder(ctx context.Context, path string, bucketName string) error\n\tCreateBucket(ctx context.Context, slug string) (textile.Bucket, error)\n\tListBuckets(ctx context.Context) ([]textile.Bucket, error)\n\tAddItems(ctx context.Context, sourcePaths []string, targetPath string, bucketName string) (<-chan domain.AddItemResult, domain.AddItemsResponse, error)\n\tAddItemWithReader(ctx context.Context, reader io.Reader, targetPath, bucketName string) (domain.AddItemResult, error)\n\tCreateIdentity(ctx context.Context, username string) (*domain.Identity, error)\n\tGetIdentityByUsername(ctx context.Context, username string) (*domain.Identity, error)\n\tGenerateFileSharingLink(ctx context.Context, encryptionPassword, path, bucketName, dbID string) (domain.FileSharingInfo, error)\n\tGenerateFilesSharingLink(ctx context.Context, encryptionPassword string, paths []string, bucketName, dbID string) (domain.FileSharingInfo, error)\n\tOpenSharedFile(ctx context.Context, cid, password, filename string) (domain.OpenFileInfo, error)\n\tShareBucket(ctx context.Context, slug string) (*domain.ThreadInfo, error)\n\tJoinBucket(ctx context.Context, slug string, threadinfo *domain.ThreadInfo) (bool, error)\n\tCreateLocalKeysBackup(ctx context.Context, pathToKeyBackup string) error\n\tRecoverKeysByLocalBackup(ctx context.Context, pathToKeyBackup string) error\n\tGetNotifications(ctx context.Context, seek string, limit int) ([]*domain.Notification, error)\n\tToggleBucketBackup(ctx context.Context, bucketSlug string, bucketBackup bool) error\n\tBucketBackupRestore(ctx context.Context, bucketSlug string) error\n\tShareFilesViaPublicKey(ctx context.Context, paths []domain.FullPath, pubkeys []crypto.PubKey) error\n\tUnshareFilesViaPublicKey(ctx context.Context, paths []domain.FullPath, pks []crypto.PubKey) error\n\tHandleSharedFilesInvitation(ctx context.Context, invitationId string, accept bool) error\n\tGetAPISessionTokens(ctx context.Context) (*domain.APISessionTokens, error)\n\tAddRecentlySharedPublicKeys(ctx context.Context, pubkeys []crypto.PubKey) error\n\tRecentlySharedPublicKeys(ctx context.Context) ([]crypto.PubKey, error)\n\tGetSharedWithMeFiles(ctx context.Context, seek string, limit int) ([]*domain.SharedDirEntry, string, error)\n\tGetSharedByMeFiles(ctx context.Context, seek string, limit int) ([]*domain.SharedDirEntry, string, error)\n\tSetNotificationsLastSeenAt(timestamp int64) error\n\tGetNotificationsLastSeenAt() (int64, error)\n\tTruncateData(ctx context.Context) error\n\tSearchFiles(ctx context.Context, query string) ([]domain.SearchFileEntry, error)\n\tInitializeMasterAppToken(ctx context.Context) (*permissions.AppToken, error)\n\tRemoveDirOrFile(ctx context.Context, path, bucketName string) error\n}\n\ntype serviceOptions struct {\n\tcfg config.Config\n\tenv env.SpaceEnv\n}\n\nvar defaultOptions = serviceOptions{}\n\ntype ServiceOption func(o *serviceOptions)\n\nfunc NewService(\n\tstore store.Store,\n\ttc textile.Client,\n\tsync services.Syncer,\n\tcfg config.Config,\n\tkc keychain.Keychain,\n\tv vault.Vault,\n\th hub.HubAuth,\n\topts ...ServiceOption,\n) (Service, error) {\n\tif !store.IsOpen() {\n\t\treturn nil, errors.New(\"service expects an opened store to work\")\n\t}\n\to := defaultOptions\n\tfor _, opt := range opts {\n\t\topt(&o)\n\t}\n\tif o.env == nil {\n\t\to.env = env.New()\n\t}\n\n\tsv := services.NewSpace(store, tc, sync, cfg, o.env, kc, v, h)\n\n\treturn sv, nil\n}\n\nfunc WithEnv(env env.SpaceEnv) ServiceOption {\n\treturn func(o *serviceOptions) {\n\t\tif env != nil {\n\t\t\to.env = env\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "core/space/space_test.go",
    "content": "package space\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/textileio/dcrypto\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/stretchr/testify/mock\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/services\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/core/vault\"\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\t\"github.com/stretchr/testify/assert\"\n\tbuckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n)\n\nvar (\n\tcfg            *mocks.Config\n\tst             *mocks.Store\n\ttextileClient  *mocks.Client\n\tmockPath       *mocks.Path\n\tmockBucket     *mocks.Bucket\n\tmockEnv        *mocks.SpaceEnv\n\tmockSync       *mocks.Syncer\n\tmockKeychain   *mocks.Keychain\n\tmockVault      *mocks.Vault\n\tmockHub        *mocks.HubAuth\n\tmockModel      *mocks.Model\n\tmockPubKey     crypto.PubKey\n\tmockPrivKey    crypto.PrivKey\n\tmockPubKeyHex  string\n\tmockPrivKeyHex string\n)\n\ntype TearDown func()\n\ntype GetTestDir func() *testDir\n\nfunc closeAndDelete(f *os.File) {\n\tf.Close()\n\tos.Remove(f.Name())\n}\n\ntype testDir struct {\n\tdir       string\n\tfileNames []string\n}\n\nfunc initTestService(t *testing.T) (*services.Space, GetTestDir, TearDown) {\n\tst = new(mocks.Store)\n\tcfg = new(mocks.Config)\n\ttextileClient = new(mocks.Client)\n\tmockPath = new(mocks.Path)\n\tmockBucket = new(mocks.Bucket)\n\tmockEnv = new(mocks.SpaceEnv)\n\tmockSync = new(mocks.Syncer)\n\tmockKeychain = new(mocks.Keychain)\n\tmockVault = new(mocks.Vault)\n\tmockHub = new(mocks.HubAuth)\n\tmockModel = new(mocks.Model)\n\tvar dir string\n\tvar err error\n\tif dir, err = ioutil.TempDir(\"\", \"space-test-folders\"); err != nil {\n\t\tt.Fatalf(\"error creating temp dir for tests %s\", err.Error())\n\t}\n\n\tlog.Println(\"temp dir\", dir)\n\n\ttmpFile1, err := os.Create(dir + \"/test1.txt\")\n\tif err != nil {\n\t\tt.Fatalf(\"error creating temp file for tests %s\", err.Error())\n\t}\n\ttmpFile2, err := os.Create(dir + \"/test2.pdf\")\n\tif err != nil {\n\t\tt.Fatalf(\"error creating temp file for tests %s\", err.Error())\n\t}\n\n\ttmpFiles := []string{tmpFile1.Name(), tmpFile2.Name()}\n\n\tgetTestDir := func() *testDir {\n\t\treturn &testDir{\n\t\t\tdir:       dir,\n\t\t\tfileNames: tmpFiles,\n\t\t}\n\t}\n\n\ttearDown := func() {\n\t\tcloseAndDelete(tmpFile1)\n\t\tcloseAndDelete(tmpFile2)\n\t\tos.RemoveAll(dir)\n\t}\n\n\tmockPubKeyHex = \"67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"\n\tmockPrivKeyHex = \"dd55f8921f90fdf31c6ef9ad86bd90605602fd7d32dc8ea66ab72deb6a82821c67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"\n\n\tpubKeyBytes, _ := hex.DecodeString(mockPubKeyHex)\n\tprivKeyBytes, _ := hex.DecodeString(mockPrivKeyHex)\n\tmockPubKey, _ = crypto.UnmarshalEd25519PublicKey(pubKeyBytes)\n\tmockPrivKey, _ = crypto.UnmarshalEd25519PrivateKey(privKeyBytes)\n\n\t// NOTE: if we need to test without the store open we must override on each test\n\tst.On(\"IsOpen\").Return(true)\n\n\tsv, err := NewService(st, textileClient, mockSync, cfg, mockKeychain, mockVault, mockHub, WithEnv(mockEnv))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\treturn sv.(*services.Space), getTestDir, tearDown\n}\n\nfunc TestNewService(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tassert.NotNil(t, sv)\n}\n\nfunc TestService_CreateBucket(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tslug := \"testbucketslug\"\n\tkey := \"testkey\"\n\tpath := \"testpath\"\n\td1 := int64(1593405100)\n\td2 := int64(1593405100)\n\n\tmb := &bucket.BucketData{\n\t\tKey:       key,\n\t\tName:      slug,\n\t\tPath:      path,\n\t\tCreatedAt: d1,\n\t\tUpdatedAt: d2,\n\t}\n\n\ttextileClient.On(\"CreateBucket\", mock.Anything, mock.Anything).Return(mockBucket, nil)\n\ttextileClient.On(\"IsInitialized\").Return(true)\n\n\tmockBucket.On(\n\t\t\"GetData\",\n\t\tmock.Anything,\n\t).Return(*mb, nil)\n\n\tres, err := sv.CreateBucket(context.Background(), \"slug\")\n\n\tassert.Nil(t, err)\n\tassert.NotEmpty(t, res)\n\tassert.Equal(t, key, res.GetData().Key)\n\tassert.Equal(t, slug, res.GetData().Name)\n\tassert.Equal(t, path, res.GetData().Path)\n\tassert.Equal(t, d1, res.GetData().CreatedAt)\n\tassert.Equal(t, d2, res.GetData().UpdatedAt)\n}\n\nfunc TestService_ListDirs(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tbucketPath := \"/ipfs/bafybeian44ntmjjfjbqt4dlkq4fiuhfzcxfunzuuzhbb7xkrnsdjb2sjha\"\n\n\tmockDirItems := &bucket.DirEntries{\n\t\tItem: &buckets_pb.PathItem{\n\t\t\tItems: []*buckets_pb.PathItem{\n\t\t\t\t{\n\t\t\t\t\tPath:  bucketPath + \"/.textileseed\",\n\t\t\t\t\tName:  \".textileseed\",\n\t\t\t\t\tIsDir: false,\n\t\t\t\t\tSize:  16,\n\t\t\t\t\tCid:   \"bafkreia4q63he72sgzrn64kpa2uu5it7utmqkdby6t3xck6umy77x7p2a1\",\n\t\t\t\t\tMetadata: &buckets_pb.Metadata{\n\t\t\t\t\t\tUpdatedAt: time.Now().Unix(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPath:  bucketPath + \"/somedir\",\n\t\t\t\t\tName:  \"somedir\",\n\t\t\t\t\tIsDir: true,\n\t\t\t\t\tSize:  0,\n\t\t\t\t\tCid:   \"\",\n\t\t\t\t\tMetadata: &buckets_pb.Metadata{\n\t\t\t\t\t\tUpdatedAt: time.Now().Unix(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPath:  bucketPath + \"/example.txt\",\n\t\t\t\t\tName:  \"example.txt\",\n\t\t\t\t\tIsDir: false,\n\t\t\t\t\tSize:  16,\n\t\t\t\t\tCid:   \"bafkreia4q63he72sgzrn64kpa2uu5it7utmqkdby6t3xck6umy77x7p2ae\",\n\t\t\t\t\tMetadata: &buckets_pb.Metadata{\n\t\t\t\t\t\tUpdatedAt: time.Now().Unix(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmockDirItemsSubfolder := &bucket.DirEntries{\n\t\tItem: &buckets_pb.PathItem{\n\t\t\tItems: []*buckets_pb.PathItem{\n\t\t\t\t{\n\t\t\t\t\tPath:  bucketPath + \"/somedir/example.txt\",\n\t\t\t\t\tName:  \"example.txt\",\n\t\t\t\t\tIsDir: false,\n\t\t\t\t\tSize:  16,\n\t\t\t\t\tCid:   \"bafkreia4q63he72sgzrn64kpa2uu5it7utmqkdby6t3xck6umy77x7p2ae\",\n\t\t\t\t\tMetadata: &buckets_pb.Metadata{\n\t\t\t\t\t\tUpdatedAt: time.Now().Unix(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttextileClient.On(\"GetDefaultBucket\", mock.Anything).Return(mockBucket, nil)\n\ttextileClient.On(\"IsInitialized\").Return(true)\n\tmockBucket.On(\n\t\t\"ListDirectory\",\n\t\tmock.Anything,\n\t\t\"\",\n\t).Return(mockDirItems, nil)\n\n\tmockBucket.On(\n\t\t\"FileExists\",\n\t\tmock.Anything,\n\t\tmock.Anything,\n\t).Return(true, nil)\n\n\tmockBucket.On(\n\t\t\"ListDirectory\",\n\t\tmock.Anything,\n\t\t\"/somedir\",\n\t).Return(mockDirItemsSubfolder, nil)\n\n\tmockBucket.On(\n\t\t\"Slug\",\n\t).Return(\n\t\t\"meow\",\n\t)\n\n\tmockMirrorFiles := make(map[string]*model.MirrorFileSchema)\n\n\tmockMirrorFiles[bucketPath+\"/.textileseed\"] = &model.MirrorFileSchema{\n\t\tBackup: true,\n\t}\n\n\tmockMirrorFiles[bucketPath+\"/somedir\"] = &model.MirrorFileSchema{\n\t\tBackup: true,\n\t}\n\n\tmockMirrorFiles[bucketPath+\"/example.txt\"] = &model.MirrorFileSchema{\n\t\tBackup: true,\n\t}\n\n\tmockMirrorFiles[bucketPath+\"/somedir/example.txt\"] = &model.MirrorFileSchema{\n\t\tBackup: true,\n\t}\n\n\tmockModel.On(\"FindMirrorFileByPaths\", mock.Anything, mock.Anything).Return(mockMirrorFiles, nil)\n\n\ttextileClient.On(\"GetModel\").Return(mockModel)\n\n\ttextileClient.On(\n\t\t\"GetPathAccessRoles\",\n\t\tmock.Anything,\n\t\tmock.Anything,\n\t\tmock.Anything,\n\t).Return(\n\t\t[]domain.Member{},\n\t\tnil,\n\t)\n\n\tres, err := sv.ListDirs(context.Background(), \"\", \"\", true)\n\n\tassert.Nil(t, err)\n\tassert.NotEmpty(t, res)\n\t// .textileseed shouldn't be part of the reply\n\tassert.Len(t, res, 3)\n\tif res[0].IsDir {\n\t\t// check for dir\n\t\tassert.True(t, res[0].IsDir)\n\t\tassert.Equal(t, \"\", res[0].FileExtension)\n\t}\n\n\tassert.False(t, res[1].IsDir)\n\tassert.Equal(t, \"example.txt\", res[1].Name)\n\tassert.Equal(t, \"txt\", res[1].FileExtension)\n\tassert.Equal(t, \"bafkreia4q63he72sgzrn64kpa2uu5it7utmqkdby6t3xck6umy77x7p2ae\", res[1].IpfsHash)\n\tassert.Equal(t, \"/somedir/example.txt\", res[1].Path)\n\n\tassert.False(t, res[2].IsDir)\n\tassert.Equal(t, \"example.txt\", res[2].Name)\n\tassert.Equal(t, \"txt\", res[2].FileExtension)\n\tassert.Equal(t, \"bafkreia4q63he72sgzrn64kpa2uu5it7utmqkdby6t3xck6umy77x7p2ae\", res[2].IpfsHash)\n\tassert.Equal(t, \"/example.txt\", res[2].Path)\n\n\t// assert mocks\n\tcfg.AssertExpectations(t)\n}\n\n// NOTE: update this test when it supports multiple buckets\nfunc TestService_OpenFile(t *testing.T) {\n\tsv, getDir, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\ttestKey := \"bucketKey\"\n\ttestPath := \"/ipfs/bafybeievdakous3kamdgy6yxtmkvmibmro23kgf7xrduvwrxrlryzvu3sm/file.txt\"\n\ttestFileName := \"file.txt\"\n\n\t// setup mocks\n\tmockEnv.On(\"WorkingFolder\").Return(\n\t\tgetDir().dir,\n\t)\n\n\tmockSync.On(\"GetOpenFilePath\", testKey, testPath, mock.Anything, mock.Anything).Return(\n\t\t\"\",\n\t\tfalse,\n\t)\n\n\tmockSync.On(\"AddFileWatch\", mock.Anything).Return(\n\t\tnil,\n\t)\n\n\ttextileClient.On(\"GetDefaultBucket\", mock.Anything).Return(mockBucket, nil)\n\ttextileClient.On(\"IsInitialized\").Return(true)\n\tmockBucket.On(\n\t\t\"GetFile\",\n\t\tmock.Anything,\n\t\ttestPath,\n\t\tmock.Anything,\n\t).Return(nil)\n\n\tmockBucket.On(\n\t\t\"Key\",\n\t).Return(testKey)\n\n\tmockBucket.On(\n\t\t\"Slug\",\n\t).Return(testKey)\n\n\tmockBucket.On(\n\t\t\"ListDirectory\", mock.Anything, mock.Anything,\n\t).Return(&bucket.DirEntries{\n\t\tItem: &buckets_pb.PathItem{\n\t\t\tCid: \"\",\n\t\t},\n\t}, nil)\n\n\ttestThreadID, err := utils.ParseDbIDFromString(\"AFKRGLCIX5CQWA2244J3GBH4ERF2MLNPJWVU72BPU2BGB5OOZH5PR7Q=\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tmockBucket.On(\n\t\t\"GetThreadID\",\n\t\tmock.Anything,\n\t).Return(\n\t\ttestThreadID,\n\t\tnil,\n\t)\n\n\tres, err := sv.OpenFile(context.Background(), testPath, \"\", \"\")\n\n\tassert.Nil(t, err)\n\tassert.NotEmpty(t, res)\n\tassert.FileExists(t, res.Location)\n\tassert.Contains(t, res.Location, os.TempDir())\n\tassert.True(t, strings.HasSuffix(res.Location, testFileName))\n\t// assert mocks\n\tcfg.AssertExpectations(t)\n\ttextileClient.AssertExpectations(t)\n}\n\nfunc TestService_AddItems_FilesOnly(t *testing.T) {\n\tsv, getTempDir, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup tests\n\ttestKey := \"bucketKey\"\n\tbucketPath := \"/tests\"\n\ttestSourcePaths := getTempDir().fileNames\n\n\ttextileClient.On(\"GetDefaultBucket\", mock.Anything).Return(mockBucket, nil)\n\ttextileClient.On(\"IsInitialized\").Return(true)\n\n\tmockBucket.On(\n\t\t\"Key\",\n\t).Return(testKey)\n\n\tmockBucket.On(\n\t\t\"Slug\",\n\t).Return(\"personal\")\n\n\tmockPath.On(\"String\").Return(\"hash\")\n\n\tfor _, f := range testSourcePaths {\n\t\t_, fileName := filepath.Split(f)\n\t\tmockBucket.On(\n\t\t\t\"UploadFile\",\n\t\t\tmock.Anything,\n\t\t\tbucketPath+\"/\"+fileName,\n\t\t\tmock.Anything,\n\t\t).Return(nil, mockPath, nil)\n\t}\n\n\tch, res, err := sv.AddItems(context.Background(), testSourcePaths, bucketPath, \"\")\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, ch)\n\tassert.NotEmpty(t, res)\n\tassert.Equal(t, int64(len(getTempDir().fileNames)), res.TotalFiles)\n\n\tcount := 0\n\tfor res := range ch {\n\t\tcount++\n\t\tassert.NotNil(t, res)\n\t\tassert.Nil(t, res.Error)\n\t\tassert.NotEmpty(t, res.BucketPath)\n\t\tassert.NotEmpty(t, res.SourcePath)\n\t}\n\n\tassert.Equal(t, count, len(testSourcePaths))\n\t// assert mocks\n\ttextileClient.AssertExpectations(t)\n\tmockBucket.AssertNumberOfCalls(t, \"UploadFile\", len(testSourcePaths))\n}\n\nfunc TestService_AddItems_Folder(t *testing.T) {\n\tsv, getTempDir, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup tests\n\ttestKey := \"bucketKey\"\n\tbucketPath := \"/tests\"\n\ttestSourcePaths := []string{getTempDir().dir}\n\n\t_, folderName := filepath.Split(getTempDir().dir)\n\n\ttargetBucketPath := bucketPath + \"/\" + folderName\n\n\ttextileClient.On(\"GetDefaultBucket\", mock.Anything).Return(mockBucket, nil)\n\ttextileClient.On(\"IsInitialized\").Return(true)\n\n\tmockBucket.On(\n\t\t\"Key\",\n\t).Return(testKey)\n\n\tmockPath.On(\"String\").Return(\"hash\")\n\n\tmockBucket.On(\n\t\t\"CreateDirectory\",\n\t\tmock.Anything,\n\t\ttargetBucketPath,\n\t).Return(nil, mockPath, nil)\n\n\tfor _, f := range getTempDir().fileNames {\n\t\t_, fileName := filepath.Split(f)\n\t\tmockBucket.On(\n\t\t\t\"UploadFile\",\n\t\t\tmock.Anything,\n\t\t\ttargetBucketPath+\"/\"+fileName,\n\t\t\tmock.Anything,\n\t\t).Return(nil, mockPath, nil)\n\t}\n\n\tmockBucket.On(\n\t\t\"Slug\",\n\t).Return(\"personal\")\n\n\tch, res, err := sv.AddItems(context.Background(), testSourcePaths, bucketPath, \"\")\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, ch)\n\tassert.NotEmpty(t, res)\n\tassert.Equal(t, int64(len(getTempDir().fileNames)+1), res.TotalFiles)\n\n\tcount := 0\n\tfor res := range ch {\n\t\tcount++\n\t\tassert.NotNil(t, res)\n\t\tassert.Nil(t, res.Error)\n\t\tassert.NotEmpty(t, res.BucketPath)\n\t\tassert.NotEmpty(t, res.SourcePath)\n\t}\n\n\tassert.Equal(t, count, len(testSourcePaths)+len(getTempDir().fileNames))\n\t// assert mocks\n\ttextileClient.AssertExpectations(t)\n\tmockBucket.AssertNumberOfCalls(t, \"UploadFile\", len(getTempDir().fileNames))\n\tmockBucket.AssertNumberOfCalls(t, \"CreateDirectory\", 1)\n}\n\nfunc TestService_AddItems_OnError(t *testing.T) {\n\tsv, getTempDir, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup tests\n\ttestKey := \"bucketKey\"\n\tbucketPath := \"/tests\"\n\ttestSourcePaths := getTempDir().fileNames\n\n\ttextileClient.On(\"GetDefaultBucket\", mock.Anything).Return(mockBucket, nil)\n\ttextileClient.On(\"IsInitialized\").Return(true)\n\n\tmockBucket.On(\n\t\t\"Key\",\n\t).Return(testKey)\n\n\tmockPath.On(\"String\").Return(\"hash\")\n\n\tbucketError := errors.New(\"bucket failed\")\n\n\tmockBucket.On(\n\t\t\"UploadFile\",\n\t\tmock.Anything,\n\t\tmock.Anything,\n\t\tmock.Anything,\n\t).Return(nil, nil, bucketError)\n\n\tch, _, err := sv.AddItems(context.Background(), testSourcePaths, bucketPath, \"\")\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, ch)\n\n\tcount := 0\n\tfor res := range ch {\n\t\tcount++\n\t\tassert.NotNil(t, res)\n\t\tassert.NotNil(t, res.Error)\n\t\tassert.NotEmpty(t, res.SourcePath)\n\t\tassert.Empty(t, res.BucketPath)\n\t}\n\n\tassert.Equal(t, count, len(testSourcePaths))\n\t// assert mocks\n\ttextileClient.AssertExpectations(t)\n\tmockBucket.AssertNumberOfCalls(t, \"UploadFile\", len(getTempDir().fileNames))\n}\n\nfunc TestService_CreateIdentity(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tcreateIdentityMock := func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = w.Write([]byte(`{ \"address\": \"0xd606f05a2a980f58737aa913553c8d6eac8b\", \"username\": \"dmerrill\", \"publicKey\": \"67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"}`))\n\t}\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/identities\", createIdentityMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\n\tserver := serverMock()\n\tdefer server.Close()\n\tcfg.On(\"GetString\", mock.Anything, mock.Anything).Return(\n\t\t// \"https://td4uiovozc.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t)\n\n\ttestUsername := \"dmerrill\"\n\n\tmockKeychain.On(\n\t\t\"GetStoredPublicKey\",\n\t).Return(mockPubKey, nil)\n\n\tidentity, err := sv.CreateIdentity(context.Background(), testUsername)\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, identity)\n\tassert.Equal(t, identity.PublicKey, mockPubKeyHex)\n\tassert.Equal(t, identity.Username, testUsername)\n}\n\nfunc TestService_CreateIdentity_OnError(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tcreateIdentityMock := func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t_, _ = w.Write([]byte(`{ \"message\": \"Validation Error: An identity with the given username already exists\"}`))\n\t}\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/identities\", createIdentityMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\n\tserver := serverMock()\n\tdefer server.Close()\n\tcfg.On(\"GetString\", mock.Anything, mock.Anything).Return(\n\t\t// \"https://td4uiovozc.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t)\n\n\ttestUsername := \"dmerrill\"\n\n\tmockKeychain.On(\n\t\t\"GetStoredPublicKey\",\n\t).Return(mockPubKey, nil)\n\n\tidentity, err := sv.CreateIdentity(context.Background(), testUsername)\n\n\tassert.Nil(t, identity)\n\tassert.NotNil(t, err)\n\tassert.Equal(t, err, errors.New(\"Validation Error: An identity with the given username already exists\"))\n}\n\nfunc TestService_GetIdentityByUsername(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tcreateIdentityMock := func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = w.Write([]byte(`{ \"address\": \"0xd606f05a2a980f58737aa913553c8d6eac8b\", \"username\": \"dmerrill\", \"publicKey\": \"67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"}`))\n\t}\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/identities/username/dmerrill\", createIdentityMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\n\tserver := serverMock()\n\tdefer server.Close()\n\tcfg.On(\"GetString\", mock.Anything, mock.Anything).Return(\n\t\t// \"https://td4uiovozc.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t)\n\n\ttestUsername := \"dmerrill\"\n\n\tidentity, err := sv.GetIdentityByUsername(context.Background(), testUsername)\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, identity)\n\tassert.NotNil(t, identity.Address)\n\tassert.NotNil(t, identity.PublicKey)\n\tassert.Equal(t, identity.Username, testUsername)\n}\n\nfunc TestService_GetIdentityByUsername_OnError(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tcreateIdentityMock := func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t_, _ = w.Write([]byte(`{ \"message\": \"Not Found Error: Identity with username dmerrill1 not found.\" }`))\n\t}\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/identities/username/dmerrill1\", createIdentityMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\n\tserver := serverMock()\n\tdefer server.Close()\n\tcfg.On(\"GetString\", mock.Anything, mock.Anything).Return(\n\t\t// \"https://td4uiovozc.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t)\n\n\ttestUsername := \"dmerrill1\"\n\n\tidentity, err := sv.GetIdentityByUsername(context.Background(), testUsername)\n\n\tassert.Nil(t, identity)\n\tassert.NotNil(t, err)\n\tassert.Equal(t, err, errors.New(\"Not Found Error: Identity with username dmerrill1 not found.\"))\n}\n\nfunc TestService_GetPublicKey(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tmockKeychain.On(\n\t\t\"GetStoredPublicKey\",\n\t).Return(mockPubKey, nil)\n\n\tpub, err := sv.GetPublicKey(context.Background())\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, pub)\n\tassert.Equal(t, pub, mockPubKeyHex)\n}\n\nfunc TestService_BackupAndRestore(t *testing.T) {\n\tsv, getTestDir, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\ttestDir := getTestDir()\n\n\tmockKeychain.On(\n\t\t\"GetStoredKeyPairInLibP2PFormat\",\n\t).Return(mockPrivKey, mockPubKey, nil)\n\n\tctx := context.Background()\n\n\tpath := testDir.fileNames[0]\n\n\terr := sv.CreateLocalKeysBackup(ctx, path)\n\n\tbackup, _ := ioutil.ReadFile(path)\n\n\tassert.Nil(t, err)\n\tassert.NotNil(t, backup)\n\n\tmockKeychain.On(\"ImportExistingKeyPair\", mock.Anything, mock.Anything).Return(nil)\n\ttextileClient.On(\"RestoreDB\", mock.Anything).Return(nil)\n\n\terr = sv.RecoverKeysByLocalBackup(ctx, path)\n\n\tassert.Nil(t, err)\n\tmockKeychain.AssertCalled(t, \"ImportExistingKeyPair\", mockPrivKey, \"\")\n}\n\nfunc TestService_VaultBackup(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tpass := \"strawberry123\"\n\tuuid := \"c907e7ef-7b36-4ab1-8a56-f788d7526a2c\"\n\tbackupType := domain.PASSWORD\n\tctx := context.Background()\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\n\tmockKeychain.On(\n\t\t\"GetStoredKeyPairInLibP2PFormat\",\n\t).Return(mockPrivKey, mockPubKey, nil)\n\n\tmockKeychain.On(\"GetStoredMnemonic\").Return(mnemonic, nil)\n\n\tmockVault.On(\"Store\", uuid, pass, backupType, mock.Anything, mock.Anything).Return(nil, nil)\n\n\tmockHub.On(\"GetTokensWithCache\", mock.Anything).Return(&hub.AuthTokens{\n\t\tAppToken: \"\",\n\t\tHubToken: \"\",\n\t\tKey:      \"\",\n\t\tMsg:      \"\",\n\t\tSig:      \"\",\n\t}, nil)\n\n\terr := sv.BackupKeysByPassphrase(ctx, uuid, pass, backupType)\n\tassert.Nil(t, err)\n\tmockVault.AssertCalled(t, \"Store\", uuid, pass, backupType, mock.Anything, mock.Anything)\n}\n\nfunc TestService_VaultRestore(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\tpass := \"strawberry123\"\n\tuuid := \"c907e7ef-7b36-4ab1-8a56-f788d7526a2c\"\n\tctx := context.Background()\n\tmnemonic := \"clog chalk blame black uncover frame before decide tuition maple crowd uncle\"\n\n\tmockItem := vault.VaultItem{\n\t\tItemType: vault.PrivateKeyWithMnemonic,\n\t\tValue:    mockPrivKeyHex + \"___\" + mnemonic,\n\t}\n\n\tmockItems := []vault.VaultItem{mockItem}\n\n\tmockVault.On(\"Retrieve\", uuid, pass, domain.PASSWORD).Return(mockItems, nil)\n\n\tmockKeychain.On(\"ImportExistingKeyPair\", mock.Anything, mock.Anything).Return(nil)\n\n\ttextileClient.On(\"RestoreDB\", mock.Anything).Return(nil)\n\n\terr := sv.RecoverKeysByPassphrase(ctx, uuid, pass, domain.PASSWORD)\n\tassert.Nil(t, err)\n\tmockKeychain.AssertCalled(t, \"ImportExistingKeyPair\", mockPrivKey, mnemonic)\n}\n\nfunc TestService_UnshareFilesViaPublicKey_Works(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\tctx := context.Background()\n\n\ttextileClient.On(\"IsHealthy\").Return(true)\n\ttextileClient.On(\"GetModel\").Return(mockModel)\n\ttextileClient.On(\n\t\t\"ManageShareFilesViaPublicKey\",\n\t\tctx,\n\t\t[]domain.FullPath{},\n\t\t[]crypto.PubKey{},\n\t\t[][]byte{},\n\t\tdomain.DeleteRoleAction,\n\t).Return(nil)\n\n\terr := sv.UnshareFilesViaPublicKey(ctx, []domain.FullPath{}, []crypto.PubKey{})\n\tassert.Nil(t, err)\n}\n\nfunc TestService_UnshareFilesViaPublicKey_Fails_IFTextileIsNotInitialized(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\tctx := context.Background()\n\texpectedErr := errors.New(\"textile is not initialized\")\n\terrChan := make(chan error, 1)\n\terrChan <- expectedErr\n\n\ttextileClient.On(\"WaitForHealthy\").Return(errChan)\n\ttextileClient.On(\"IsHealthy\").Return(false)\n\n\terr := sv.UnshareFilesViaPublicKey(ctx, []domain.FullPath{}, []crypto.PubKey{})\n\tassert.EqualError(t, err, expectedErr.Error())\n}\n\nfunc TestService_HandleSharedFilesInvitation_FailIfInvitationNotFound(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tctx := context.Background()\n\tdefer tearDown()\n\n\ttextileClient.On(\"IsHealthy\").Return(true)\n\ttextileClient.On(\"GetMailAsNotifications\", mock.Anything, \"\", 1).\n\t\tReturn(nil, errors.New(\"failed fetching\"))\n\n\terr := sv.HandleSharedFilesInvitation(ctx, \"\", true)\n\tassert.EqualError(t, err, \"invitation not found\")\n}\n\nfunc TestService_HandleSharedFilesInvitation_Accepts_Correctly(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup\n\tctx := context.Background()\n\tinvitationId := \"random-invitation-uuid\"\n\tacceptInvite := true\n\texpectedInvitation := domain.Invitation{\n\t\tInviterPublicKey: \"b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde\",\n\t\tStatus:           domain.PENDING,\n\t\tItemPaths: []domain.FullPath{\n\t\t\t{\n\t\t\t\tDbId:   \"random-db-id\",\n\t\t\t\tBucket: \"personal\",\n\t\t\t\tPath:   \"/\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttextileClient.On(\"IsHealthy\").Return(true)\n\ttextileClient.On(\"GetMailAsNotifications\", mock.Anything, invitationId, 1).\n\t\tReturn([]*domain.Notification{\n\t\t\t{\n\t\t\t\tNotificationType: domain.INVITATION,\n\t\t\t\tInvitationValue:  expectedInvitation,\n\t\t\t},\n\t\t}, nil)\n\n\ttextileClient.On(\"AcceptSharedFilesInvitation\", mock.Anything, expectedInvitation).\n\t\tReturn(expectedInvitation, nil)\n\n\ttextileClient.On(\"SendMessage\", mock.Anything, mock.Anything, mock.Anything).\n\t\tReturn(nil, nil)\n\n\t// execute\n\terr := sv.HandleSharedFilesInvitation(ctx, invitationId, acceptInvite)\n\tassert.NoError(t, err, \"HandleSharedFilesInvitation failed\")\n}\n\nfunc TestService_HandleSharedFilesInvitation_Rejects_Correctly(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup\n\tctx := context.Background()\n\tinvitationId := \"random-invitation-uuid\"\n\tacceptInvite := false\n\texpectedInvitation := domain.Invitation{\n\t\tInviterPublicKey: \"b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde\",\n\t\tStatus:           domain.PENDING,\n\t\tItemPaths: []domain.FullPath{\n\t\t\t{\n\t\t\t\tDbId:   \"random-db-id\",\n\t\t\t\tBucket: \"personal\",\n\t\t\t\tPath:   \"/\",\n\t\t\t},\n\t\t},\n\t}\n\n\ttextileClient.On(\"IsHealthy\").Return(true)\n\ttextileClient.On(\"GetMailAsNotifications\", mock.Anything, invitationId, 1).\n\t\tReturn([]*domain.Notification{\n\t\t\t{\n\t\t\t\tNotificationType: domain.INVITATION,\n\t\t\t\tInvitationValue:  expectedInvitation,\n\t\t\t},\n\t\t}, nil)\n\n\ttextileClient.On(\"RejectSharedFilesInvitation\", mock.Anything, expectedInvitation).\n\t\tReturn(expectedInvitation, nil)\n\n\ttextileClient.On(\"SendMessage\", mock.Anything, mock.Anything, mock.Anything).\n\t\tReturn(nil, nil)\n\n\t// execute\n\terr := sv.HandleSharedFilesInvitation(ctx, invitationId, acceptInvite)\n\tassert.NoError(t, err, \"HandleSharedFilesInvitation failed\")\n}\n\nfunc TestService_OpenSharedFile_ShouldFail_When_PasswordCannotBeFetched(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup\n\tctx := context.Background()\n\ttestFilename := \"image.jpg\"\n\ttestHash := \"bafkreidhby4wyrc3cr6hfsg54x6nequylzdhn254nep7z3g7adfkyddlcy\"\n\temptyPassword := \"\"\n\ttextileClient.On(\"IsHealthy\").Return(true)\n\ttextileClient.On(\"GetPublicReceivedFile\", mock.Anything, testHash, true).\n\t\tReturn(nil, \"\", errors.New(\"not found\"))\n\n\t// test\n\t_, err := sv.OpenSharedFile(ctx, testHash, emptyPassword, testFilename)\n\n\t// validate\n\tassert.Error(t, err, \"OpenSharedFile should fail for non existent password\")\n\tassert.Contains(t, err.Error(), \"password is required to open this file\", \"OpenSharedFile should fail\")\n}\n\nfunc TestService_OpenSharedFile_Should_AddOpenedFileToSharedWithMeList(t *testing.T) {\n\tsv, _, tearDown := initTestService(t)\n\tdefer tearDown()\n\n\t// setup\n\tctx := context.Background()\n\ttestFilename := \"letter.txt\"\n\texpectedFileContent := \"This is a love letter to the dweb. Be great\"\n\ttestHash := \"bafkreidhby4wyrc3cr6hfsg54x6nequylzdhn254nep7z3g7adfkyddlcy\"\n\ttestPassword := \"super-secret\"\n\temptyPassword := \"\"\n\ttextileClient.On(\"IsHealthy\").Return(true)\n\ttextileClient.On(\"GetPublicReceivedFile\", mock.Anything, testHash, true).\n\t\tReturn(&domain.SharedDirEntry{}, testPassword, nil)\n\ttextileClient.On(\"DownloadPublicItem\", mock.Anything, mock.Anything).\n\t\tReturn(encryptString(expectedFileContent, testPassword), nil)\n\ttextileClient.On(\"AcceptSharedFileLink\", mock.Anything, testHash, testPassword, testFilename, fmt.Sprintf(\"%d\", len(expectedFileContent))).\n\t\tReturn(&domain.SharedDirEntry{}, nil)\n\n\t// test (using empty password, so testPassword would be fetch from textileClient)\n\tresult, err := sv.OpenSharedFile(ctx, testHash, emptyPassword, testFilename)\n\n\t// validate\n\tassert.NoError(t, err, \"OpenSharedFile should not fail\")\n\tactualFileContent, err := ioutil.ReadFile(result.Location)\n\tassert.NoError(t, err, \"Failed to read decrypted file\")\n\tassert.Equal(t, expectedFileContent, string(actualFileContent))\n}\n\nfunc encryptString(content, password string) io.ReadCloser {\n\treader, err := dcrypto.NewEncrypterWithPassword(strings.NewReader(content), []byte(password))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn ioutil.NopCloser(reader)\n}\n"
  },
  {
    "path": "core/spacefs/fs.go",
    "content": "package spacefs\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\n\t\"github.com/FleekHQ/space-daemon/core/fsds\"\n)\n\n// SpaceFS is represents the filesystem that FUSE Interacts with\n// It implements the FSOps interface\n// And is responsible for managing file access, encryption and decryption\ntype SpaceFS struct {\n\tstore fsds.FSDataSource\n}\n\nvar _ = FSOps(&SpaceFS{})\n\n// New initializes a SpaceFS instance using store as it source of informatioin\nfunc New(store fsds.FSDataSource) *SpaceFS {\n\treturn &SpaceFS{\n\t\tstore: store,\n\t}\n}\n\n// Root implements the FSOps Root function\n// It returns the root directory of the file\nfunc (fs *SpaceFS) Root(ctx context.Context) (DirEntryOps, error) {\n\tentry, err := fs.store.Get(ctx, \"/\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &SpaceDirectory{\n\t\tfs:    fs,\n\t\tentry: entry,\n\t}, nil\n}\n\n// LookupPath implements the FsOps interface for looking up information\n// in a directory\nfunc (fs *SpaceFS) LookupPath(ctx context.Context, path string) (DirEntryOps, error) {\n\tentry, err := fs.store.Get(ctx, path)\n\n\tif err != nil {\n\t\treturn nil, syscall.ENOENT\n\t}\n\tif entry.IsDir() {\n\t\treturn &SpaceDirectory{\n\t\t\tfs:    fs,\n\t\t\tentry: entry,\n\t\t}, nil\n\t}\n\n\treturn &SpaceFile{\n\t\tfs:    fs,\n\t\tentry: entry,\n\t}, nil\n}\n\nfunc (fs *SpaceFS) CreateEntry(ctx context.Context, req CreateDirEntry) (DirEntryOps, error) {\n\tentry, err := fs.store.CreateEntry(ctx, req.Path, req.Mode)\n\n\tif err != nil {\n\t\treturn nil, syscall.ENOENT\n\t}\n\tif entry.IsDir() {\n\t\treturn &SpaceDirectory{\n\t\t\tfs:    fs,\n\t\t\tentry: entry,\n\t\t}, nil\n\t}\n\n\treturn &SpaceFile{\n\t\tfs:    fs,\n\t\tentry: entry,\n\t}, nil\n}\n\n// RenameEntry should rename the directory entry from old to new\nfunc (fs *SpaceFS) RenameEntry(ctx context.Context, req RenameDirEntry) error {\n\treturn fs.store.RenameEntry(ctx, req.OldPath, req.NewPath)\n}\n\n// DeleteEntry should delete the item at the path\nfunc (fs *SpaceFS) DeleteEntry(ctx context.Context, path string) error {\n\treturn fs.store.DeleteEntry(ctx, path)\n}\n\n// Open a file at specified path\nfunc (fs *SpaceFS) Open(ctx context.Context, path string, mode FileHandlerMode) (FileHandler, error) {\n\tresult, err := fs.store.Open(ctx, path)\n\treturn result, err\n}\n\n// SpaceDirectory is a directory managed by space\ntype SpaceDirectory struct {\n\tfs    *SpaceFS\n\tentry *fsds.DirEntry\n}\n\nvar _ = DirEntryOps(&SpaceDirectory{})\nvar _ = DirOps(&SpaceDirectory{})\n\n// Path implements DirEntryOps Path() and return the path of the directory\nfunc (dir *SpaceDirectory) Path() string {\n\treturn dir.entry.Path()\n}\n\n// Attribute implements DirEntryOps Attribute() and fetches the metadata of the directory\nfunc (dir *SpaceDirectory) Attribute(ctx context.Context) (DirEntryAttribute, error) {\n\treturn dir.entry, nil\n}\n\n// ReadDir implements DirOps ReadDir and returns the list of entries in a directory\nfunc (dir *SpaceDirectory) ReadDir(ctx context.Context) ([]DirEntryOps, error) {\n\tchildrenEntries, err := dir.fs.store.GetChildren(ctx, dir.entry.Path())\n\tif err != nil {\n\t\treturn nil, syscall.ENOENT\n\t}\n\n\tvar result []DirEntryOps\n\tfor _, entry := range childrenEntries {\n\t\tif entry.IsDir() {\n\t\t\tresult = append(result, &SpaceDirectory{\n\t\t\t\tfs:    dir.fs,\n\t\t\t\tentry: entry,\n\t\t\t})\n\t\t} else {\n\t\t\tresult = append(result, &SpaceFile{\n\t\t\t\tfs:    dir.fs,\n\t\t\t\tentry: entry,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\n// SpaceFile is a file managed by space\ntype SpaceFile struct {\n\tfs    *SpaceFS\n\tentry *fsds.DirEntry\n}\n\nvar _ = FileOps(&SpaceFile{})\n\n// Path implements DirEntryOps Path() and return the path of the directory\nfunc (f *SpaceFile) Path() string {\n\treturn f.entry.Path()\n}\n\n// Attribute implements DirEntryOps Attribute() and fetches the metadata of the directory\nfunc (f *SpaceFile) Attribute(ctx context.Context) (DirEntryAttribute, error) {\n\tfileInfo, err := f.fs.store.Open(ctx, f.Path())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstats, err := fileInfo.Stats(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn stats, nil\n}\n\n// Open implements FileOps Open\n// It should download/cache the content of the file and return a fileHandler\n// that can read the cached content.\nfunc (f *SpaceFile) Open(ctx context.Context, mode FileHandlerMode) (FileHandler, error) {\n\tfileHandler, err := f.fs.Open(ctx, f.entry.Path(), mode)\n\treturn fileHandler, err\n}\n\nfunc (f *SpaceFile) Truncate(ctx context.Context, size uint64) error {\n\tfileInfo, err := f.fs.store.Open(ctx, f.Path())\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn fileInfo.Truncate(ctx, size)\n}\n"
  },
  {
    "path": "core/spacefs/fs_test.go",
    "content": "package spacefs\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n//\nfunc TestSpaceFS_LookupPath(t *testing.T) {\n\tassert.Equal(t, true, true)\n\t//\tctx := context.Background()\n\t//\tmemStore, err := fsds.NewIpfsDataSource(ctx)\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\n\t//\tfs, err := New(ctx, memStore)\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\n\t//\tresult, err := fs.LookupPath(\"/static\")\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\n\t//\tlog.Printf(\"Path %s\", result.Path())\n\t//\n\t//\tresult, err = fs.LookupPath(\"/static/js/2.b4ef1316.chunk.js\")\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\tlog.Printf(\"Path %s\", result.Path())\n\t//\tattr, err := result.Attribute()\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\tlog.Printf(\"Name %s\", attr.Name())\n\t//\tlog.Printf(\"IsDir %v\", attr.IsDir())\n\t//\tlog.Printf(\"Size %d\", attr.Size())\n\t//\n\t//\tresult, err = fs.LookupPath(\"/static/js\")\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\n\t//\tdirOps, ok := result.(DirOps)\n\t//\tif !ok {\n\t//\t\tt.Fatal(errors.New(\"result is not a DirOps\"))\n\t//\t}\n\t//\tjsDirectory, err := dirOps.ReadDir()\n\t//\tif err != nil {\n\t//\t\tt.Fatal(err)\n\t//\t}\n\t//\tfor _, dir := range jsDirectory {\n\t//\t\tdirAttr, err := dir.Attribute()\n\t//\t\tif err != nil {\n\t//\t\t\tt.Fatal(err)\n\t//\t\t}\n\t//\t\tlog.Printf(\"\\nName: %s\\nIs Dir: %v\\nSize: %d\\n\", dirAttr.Name(), dirAttr.IsDir(), dirAttr.Size())\n\t//\t}\n}\n"
  },
  {
    "path": "core/spacefs/interfaces.go",
    "content": "package spacefs\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"time\"\n)\n\ntype FileHandlerMode uint8\n\nconst (\n\tReadMode = FileHandlerMode(0)\n\tWriteMode\n)\n\n// DirEntryAttribute similar to the FileInfo in the os.Package\ntype DirEntryAttribute interface {\n\tName() string       // base name of the file\n\tSize() uint64       // length in bytes for files; can be anything for directories\n\tMode() os.FileMode  // file mode bits\n\tUid() uint32        // user id of owner of entry\n\tGid() uint32        // group id of owner of entry\n\tCtime() time.Time   // creation time\n\tModTime() time.Time // modification time\n\tIsDir() bool\n}\n\n// DirEntryOps are the list of actions to be invoked on a directry entry\n// A directory entry is either a file or a folder.\n// See DirOps and FileOps for operations specific to those types\ntype DirEntryOps interface {\n\t// Path should return the absolute path string for directory or file\n\t// Directory path's should end in `/`\n\tPath() string\n\t// Attribute should return the metadata information for the file\n\tAttribute(ctx context.Context) (DirEntryAttribute, error)\n}\n\n// DirOps are the list of actions that can be done on a directory\ntype DirOps interface {\n\tDirEntryOps\n\tReadDir(ctx context.Context) ([]DirEntryOps, error)\n}\n\n// FileHandler is in charge of reading, writing and closing access to a file\n// It should handle locking and track read and write offsets till it is closed\ntype FileHandler interface {\n\tRead(ctx context.Context, data []byte, offset int64) (int, error)\n\tWrite(ctx context.Context, data []byte, offset int64) (int, error)\n\tClose(ctx context.Context) error\n}\n\n// FileOps are the list of actions that can be done on a file\ntype FileOps interface {\n\tDirEntryOps\n\tOpen(ctx context.Context, mode FileHandlerMode) (FileHandler, error)\n\tTruncate(ctx context.Context, size uint64) error\n}\n\ntype CreateDirEntry struct {\n\tPath string\n\tMode os.FileMode\n}\n\ntype RenameDirEntry struct {\n\tOldPath string\n\tNewPath string\n}\n\n// FSOps represents the filesystem operations\ntype FSOps interface {\n\t// Root should return the root directory entry\n\tRoot(ctx context.Context) (DirEntryOps, error)\n\t// LookupPath should return the directory entry at that particular path\n\tLookupPath(ctx context.Context, path string) (DirEntryOps, error)\n\t// Open a file at specific path, with specified mode\n\tOpen(ctx context.Context, path string, mode FileHandlerMode) (FileHandler, error)\n\t// CreateEntry should create an directory entry and return either a FileOps or DirOps entry\n\t// depending on the mode\n\tCreateEntry(ctx context.Context, req CreateDirEntry) (DirEntryOps, error)\n\t// RenameEntry should rename the directory entry from old to new\n\tRenameEntry(ctx context.Context, req RenameDirEntry) error\n\t// DeleteEntry should delete the item at the path\n\tDeleteEntry(ctx context.Context, path string) error\n}\n"
  },
  {
    "path": "core/store/store.go",
    "content": "package store\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\ts \"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/util\"\n\n\t\"github.com/FleekHQ/space-daemon/core\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\tbadger \"github.com/dgraph-io/badger\"\n)\n\nconst DefaultRootDir = \"~/.fleek-space\"\nconst BadgerFileName = \"db\"\n\ntype store struct {\n\trootDir string\n\tdb      *badger.DB\n\tisOpen  bool\n}\n\nvar _ = core.Component(store{})\n\ntype Store interface {\n\tOpen() error\n\tClose() error\n\tSet(key []byte, value []byte) error\n\tSetString(key string, value string) error\n\tGet(key []byte) ([]byte, error)\n\tRemove(key []byte) error\n\tDropAll() error\n\tIsOpen() bool\n\tKeysWithPrefix(prefix string) ([]string, error)\n}\n\ntype storeOptions struct {\n\trootDir string\n}\n\nvar defaultStoreOptions = storeOptions{\n\trootDir: DefaultRootDir,\n}\n\n// Idea taken from here https://medium.com/soon-london/variadic-configuration-functions-in-go-8cef1c97ce99\n\ntype Option func(o *storeOptions)\n\nfunc New(opts ...Option) *store {\n\to := defaultStoreOptions\n\tfor _, opt := range opts {\n\t\topt(&o)\n\t}\n\n\tlog.Info(fmt.Sprintf(\"using path %s for store\", o.rootDir))\n\n\tstore := &store{\n\t\trootDir: o.rootDir,\n\t\tisOpen:  false,\n\t}\n\n\treturn store\n}\n\nfunc (store *store) Open() error {\n\tif store.isOpen {\n\t\tlog.Warn(\"Trying to open an already open\")\n\t\treturn nil\n\t}\n\n\trootDir, err := util.ResolvePath(s.Join([]string{store.rootDir, BadgerFileName}, \"/\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// We create the directory in case it doesn't exist yet\n\tif err := os.MkdirAll(rootDir, os.ModePerm); err != nil {\n\t\treturn err\n\t}\n\n\tdb, err := badger.Open(\n\t\tbadger.DefaultOptions(rootDir).\n\t\t\tWithEventLogging(false).\n\t\t\tWithTruncate(runtime.GOOS == \"windows\"),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstore.db = db\n\tstore.isOpen = true\n\n\treturn nil\n}\n\nfunc (store store) IsOpen() bool {\n\treturn store.isOpen\n}\n\nfunc (store *store) Close() error {\n\tif !store.isOpen {\n\t\treturn nil\n\t}\n\n\terr := store.db.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstore.isOpen = false\n\n\treturn nil\n}\n\n// Testing that store is correctly working\nfunc (store *store) hotInit() {\n\tif err := store.Set([]byte(\"A\"), []byte(\"B\")); err != nil {\n\t\tlog.Error(\"error\", err)\n\t\treturn\n\t}\n\n\tif val, err := store.Get([]byte(\"A\")); err != nil {\n\t\tlog.Error(\"error\", err)\n\t} else {\n\t\tlog.Info(\"Got store response\")\n\t\tlog.Info(string(val))\n\t}\n}\n\n// Helper function for setting store path\nfunc WithPath(path string) Option {\n\treturn func(o *storeOptions) {\n\t\tif path != \"\" {\n\t\t\to.rootDir = path\n\t\t}\n\t}\n}\n\nfunc (store *store) getDb() (*badger.DB, error) {\n\tif store.isOpen == false {\n\t\treturn nil, errors.New(\"Database has not been opened yet\")\n\t}\n\n\treturn store.db, nil\n}\n\n// Stores a key/value pair in the db.\nfunc (store *store) Set(key []byte, value []byte) error {\n\tdb, err := store.getDb()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tupdateHandler := func(txn *badger.Txn) error {\n\t\te := badger.NewEntry(key, value)\n\t\terr := txn.SetEntry(e)\n\t\treturn err\n\t}\n\n\tif err := db.Update(updateHandler); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Removes a key/value pair in the db.\nfunc (store *store) Remove(key []byte) error {\n\tdb, err := store.getDb()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tremoveHandler := func(txn *badger.Txn) error {\n\t\terr := txn.Delete(key)\n\t\treturn err\n\t}\n\n\tif err := db.Update(removeHandler); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (store *store) SetString(key string, value string) error {\n\treturn store.Set([]byte(key), []byte(value))\n}\n\n// Given a key, retrieves the stored value. If the key is not found returns ErrKeyNotFound.\nfunc (store *store) Get(key []byte) ([]byte, error) {\n\tdb, err := store.getDb()\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar valCopy []byte\n\n\ttransactionHandler := func(txn *badger.Txn) error {\n\t\tif item, err := txn.Get(key); err != nil {\n\t\t\treturn err\n\t\t} else {\n\t\t\terr = item.Value(func(val []byte) error {\n\t\t\t\t// Copying or parsing val is valid.\n\t\t\t\tvalCopy = append([]byte{}, val...)\n\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t}\n\n\tif err = db.View(transactionHandler); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn valCopy, nil\n}\n\n// Returns keys in the store filtered by prefix\nfunc (store store) KeysWithPrefix(prefix string) ([]string, error) {\n\tdb, err := store.getDb()\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkeys := make([]string, 0)\n\n\tdb.View(func(txn *badger.Txn) error {\n\t\tit := txn.NewIterator(badger.DefaultIteratorOptions)\n\t\tdefer it.Close()\n\t\tprefix := []byte(prefix)\n\t\tfor it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {\n\t\t\titem := it.Item()\n\t\t\tk := item.Key()\n\t\t\tkeys = append(keys, string(k))\n\t\t}\n\t\treturn nil\n\t})\n\n\treturn keys, nil\n}\n\nfunc (store store) Shutdown() error {\n\treturn store.Close()\n}\n\nfunc (store store) DropAll() error {\n\tdb, err := store.getDb()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn db.DropAll()\n}\n"
  },
  {
    "path": "core/sync/fs.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tipfspath \"github.com/ipfs/interface-go-ipfs-core/path\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nfunc (h *watcherHandler) OnCreate(ctx context.Context, path string, fileInfo os.FileInfo) {\n\tlog.Info(\n\t\t\"FS Handler: OnCreate\", fmt.Sprintf(\"path:%s\", path),\n\t\tfmt.Sprintf(\"fileName:%s\", fileInfo.Name()),\n\t)\n\t// TODO: Synchronizer lock check should ensure that no other operation is currently ongoing\n\t// with this path or its parent folder\n\n\tvar result ipfspath.Resolved\n\tvar newRoot ipfspath.Path\n\tvar err error\n\n\twatchInfo, exists := h.bs.getOpenFileBucketSlugAndPath(path)\n\tif !exists {\n\t\tmsg := fmt.Sprintf(\"error: could not find path %s\", path)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\n\tbucketSlug := watchInfo.BucketSlug\n\tbucketPath := watchInfo.BucketPath\n\n\tb, err := h.bs.textileClient.GetBucket(ctx, bucketSlug, nil)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"error: could not find bucket with slug %s\", bucketSlug)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\n\tif fileInfo.IsDir() {\n\t\texistsOnTextile, err := b.DirExists(ctx, path)\n\t\tif err != nil {\n\t\t\tlog.Error(\"Could not check if folder exists on textile\", err)\n\t\t\treturn\n\t\t}\n\n\t\tif existsOnTextile {\n\t\t\tlog.Info(\"Folder alerady exists on textile\")\n\t\t\treturn\n\t\t}\n\n\t\tresult, newRoot, err = b.CreateDirectory(ctx, path)\n\t} else {\n\t\texistsOnTextile, err := b.FileExists(ctx, path)\n\t\tif err != nil {\n\t\t\tlog.Error(\"Could not check if file exists on textile\", err)\n\t\t\treturn\n\t\t}\n\n\t\tif existsOnTextile {\n\t\t\tlog.Info(\"File alerady exists on textile\")\n\t\t\treturn\n\t\t}\n\n\t\tfileReader, err := os.Open(path)\n\t\tif err != nil {\n\t\t\tlog.Error(\"Could not open file for upload\", err)\n\t\t\treturn\n\t\t}\n\n\t\tresult, newRoot, err = b.UploadFile(ctx, bucketPath, fileReader)\n\t}\n\n\tif err != nil {\n\t\tlog.Error(\"Uploading to textile failed\", err, fmt.Sprintf(\"path:%s\", path))\n\t\treturn\n\t}\n\tif err = result.IsValid(); err != nil {\n\t\tlog.Error(\"Uploading to textile not valid\", err, fmt.Sprintf(\"path:%s\", path))\n\t\treturn\n\t}\n\n\tlog.Info(\n\t\t\"Successfully uploaded item to textile\",\n\t\tfmt.Sprintf(\"bucketPath:%s\", bucketPath),\n\t\tfmt.Sprintf(\"itemCid:%s\", result.Cid()),\n\t\tfmt.Sprintf(\"rootCid:%s\", newRoot.String()),\n\t)\n\n\t// TODO: Update synchronizer/store (maybe in a defer function)\n}\n\nfunc (h *watcherHandler) OnRemove(ctx context.Context, path string, fileInfo os.FileInfo) {\n\tlog.Info(\"FS Handler: OnRemove\", fmt.Sprintf(\"path:%s\", path), fmt.Sprintf(\"fileName:%s\", fileInfo.Name()))\n\t// TODO: Also synchronizer lock check here\n\n\twatchInfo, exists := h.bs.getOpenFileBucketSlugAndPath(path)\n\tif !exists {\n\t\tmsg := fmt.Sprintf(\"error: could not find path %s\", path)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\tbucketSlug := watchInfo.BucketSlug\n\tbucketPath := watchInfo.BucketPath\n\n\tb, err := h.bs.textileClient.GetBucket(ctx, bucketSlug, nil)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"error: could not find bucket with slug %s\", bucketSlug)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\n\t_, err = b.DeleteDirOrFile(ctx, bucketPath)\n\n\tif err != nil {\n\t\tlog.Error(\"Deleting from textile failed\", err, fmt.Sprintf(\"path:%s\", path))\n\t\treturn\n\t}\n\n\tlog.Info(\n\t\t\"Successfully deleted item from textile\",\n\t\tfmt.Sprintf(\"path:%s\", path),\n\t)\n\t// TODO: Update synchronizer/store (maybe in a defer function)\n}\n\n// OnWrite is invoked when a new file is created or files content is updated\nfunc (h *watcherHandler) OnWrite(ctx context.Context, path string, fileInfo os.FileInfo) {\n\tlog.Info(\"FS Handler: OnWrite\", fmt.Sprintf(\"path:%s\", path), fmt.Sprintf(\"fileName:%s\", fileInfo.Name()))\n\n\twatchInfo, exists := h.bs.getOpenFileBucketSlugAndPath(path)\n\tif !exists {\n\t\tmsg := fmt.Sprintf(\"error: could not find path %s\", path)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\n\tvar b textile.Bucket\n\tvar err error\n\tbucketSlug := watchInfo.BucketSlug\n\tbucketPath := watchInfo.BucketPath\n\n\tif watchInfo.IsRemote {\n\t\tb, err = h.bs.textileClient.GetBucket(ctx, bucketSlug, &textile.GetBucketForRemoteFileInput{\n\t\t\tBucket: bucketSlug,\n\t\t\tDbID:   watchInfo.DbId,\n\t\t\tPath:   watchInfo.BucketPath,\n\t\t})\n\t} else {\n\t\tb, err = h.bs.textileClient.GetBucket(ctx, bucketSlug, nil)\n\t}\n\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"error: could not find bucket with slug %s\", bucketSlug)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\tfileReader, err := os.Open(path)\n\tif err != nil {\n\t\tlog.Error(\"Could not open file for upload\", err)\n\t\treturn\n\t}\n\n\t_, _, err = b.UploadFile(ctx, bucketPath, fileReader)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"error: could not sync file at path %s to bucket %s as %s\", path, bucketSlug, bucketPath)\n\t\tlog.Error(msg, fmt.Errorf(msg))\n\t\treturn\n\t}\n\tmsg := fmt.Sprintf(\"success syncing file at path %s to bucket %s as %s\", path, bucketSlug, bucketPath)\n\tlog.Printf(msg)\n\n}\n\nfunc (h *watcherHandler) OnRename(ctx context.Context, path string, fileInfo os.FileInfo, oldPath string) {\n\tlog.Info(\n\t\t\"Watcher Handler: OnRename\",\n\t\tfmt.Sprintf(\"path:%s\", path),\n\t\tfmt.Sprintf(\"fileName:%s\", fileInfo.Name()),\n\t\tfmt.Sprintf(\"path:%s\", oldPath),\n\t)\n\th.OnRemove(ctx, oldPath, fileInfo)\n\th.OnCreate(ctx, path, fileInfo)\n}\n\nfunc (h *watcherHandler) OnMove(ctx context.Context, path string, fileInfo os.FileInfo, oldPath string) {\n\tlog.Info(\n\t\t\"Watcher Handler: OnMove\",\n\t\tfmt.Sprintf(\"path:%s\", path),\n\t\tfmt.Sprintf(\"fileName:%s\", fileInfo.Name()),\n\t\tfmt.Sprintf(\"path:%s\", oldPath),\n\t)\n\th.OnRemove(ctx, oldPath, fileInfo)\n\th.OnCreate(ctx, path, fileInfo)\n}\n"
  },
  {
    "path": "core/sync/notifier_default.go",
    "content": "package sync\n\nimport (\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n)\n\ntype defaultNotifier struct{}\n\nfunc (d defaultNotifier) SendFileEvent(event events.FileEvent) {\n\treturn\n}\n\nfunc (d defaultNotifier) SendTextileEvent(event events.TextileEvent) {\n\treturn\n}\n"
  },
  {
    "path": "core/sync/sync.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/services\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/FleekHQ/space-daemon/core/watcher\"\n)\n\nvar (\n\tErrAddFileWatch = errors.New(\"error adding file to watch\")\n)\n\nconst (\n\tOpenFilesKeyPrefix        = \"openFiles#\"\n\tReverseOpenFilesKeyPrefix = \"reverseOpenFiles#\"\n)\n\ntype GrpcNotifier interface {\n\tSendFileEvent(event events.FileEvent)\n\tSendTextileEvent(event events.TextileEvent)\n}\n\ntype BucketSynchronizer interface {\n\tWaitForReady() chan bool\n\tStart(ctx context.Context) error\n\tShutdown() error\n\tRegisterNotifier(notifier GrpcNotifier)\n\tAddFileWatch(addFileInfo domain.AddWatchFile) error\n\tGetOpenFilePath(bucketSlug, bucketPath, dbID, cid string) (string, bool)\n}\n\ntype TextileNotifier interface {\n\tSendTextileEvent(event events.TextileEvent)\n}\n\n// Implementation to handle events from FS\ntype watcherHandler struct {\n\tclient textile.Client\n\tbs     *bucketSynchronizer\n}\n\n// Implementation to handle events from textile\ntype textileHandler struct {\n\tnotifier TextileNotifier\n\tbs       *bucketSynchronizer\n}\n\ntype bucketSynchronizer struct {\n\tfolderWatcher watcher.FolderWatcher\n\ttextileClient textile.Client\n\tfh            *watcherHandler\n\tth            *textileHandler\n\tnotifier      GrpcNotifier\n\tstore         store.Store\n\tready         chan bool\n}\n\n// Creates a new bucketSynchronizer instancelistenerEventHandler\nfunc New(\n\tfolderWatcher watcher.FolderWatcher,\n\ttextileClient textile.Client,\n\tstore store.Store,\n\tnotifier GrpcNotifier,\n) *bucketSynchronizer {\n\n\treturn &bucketSynchronizer{\n\t\tfolderWatcher: folderWatcher,\n\t\ttextileClient: textileClient,\n\t\tfh:            nil,\n\t\tth:            nil,\n\t\tnotifier:      notifier,\n\t\tstore:         store,\n\t\tready:         make(chan bool),\n\t}\n}\n\n// Starts the folder watcher and the textile watcher.\nfunc (bs *bucketSynchronizer) Start(ctx context.Context) error {\n\tif bs.notifier == nil {\n\t\tlog.Printf(\"using default notifier to start bucket sync\")\n\t\tbs.notifier = &defaultNotifier{}\n\t}\n\n\tbs.fh = &watcherHandler{\n\t\tclient: bs.textileClient,\n\t\tbs:     bs,\n\t}\n\n\tbs.folderWatcher.RegisterHandler(bs.fh)\n\n\tg, newCtx := errgroup.WithContext(ctx)\n\n\tg.Go(func() error {\n\t\tlog.Debug(\"Starting watcher in bucketsync\")\n\t\treturn bs.folderWatcher.Watch(newCtx)\n\t})\n\n\t// add open files to watcher\n\tkeys, err := bs.store.KeysWithPrefix(OpenFilesKeyPrefix)\n\tif err != nil {\n\t\tlog.Error(\"error getting keys from store\", err)\n\t\treturn err\n\t}\n\tlog.Debug(\"start watching open files ...\")\n\tfor _, k := range keys {\n\t\tif fi, err := bs.getOpenFileInfo(k); err == nil {\n\t\t\tif services.PathExists(fi.LocalPath) {\n\t\t\t\tif err := bs.folderWatcher.AddFile(fi.LocalPath); err != nil {\n\t\t\t\t\tlog.Error(fmt.Sprintf(\"error opening file at %s\", fi.LocalPath), err)\n\t\t\t\t\t// remove fileInfo from store for cleanup\n\t\t\t\t\tbs.removeFileInfo(fi)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tbs.ready <- true\n\n\terr = g.Wait()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (bs *bucketSynchronizer) WaitForReady() chan bool {\n\treturn bs.ready\n}\n\nfunc (bs *bucketSynchronizer) Shutdown() error {\n\t// add shutdown logic here\n\tlog.Debug(\"shutting down folder watcher in bucketsync\")\n\tbs.folderWatcher.Close()\n\tlog.Debug(\"shutting down textile thread listener in bucketsync\")\n\n\tclose(bs.ready)\n\treturn nil\n}\n\nfunc (bs *bucketSynchronizer) RegisterNotifier(notifier GrpcNotifier) {\n\tbs.notifier = notifier\n}\n\n// TODO: add GC code logic to open files to cleanup\n// Adds a file to watcher list to keep track of\nfunc (bs *bucketSynchronizer) AddFileWatch(addFileInfo domain.AddWatchFile) error {\n\tif addFileInfo.LocalPath == \"\" {\n\t\treturn ErrAddFileWatch\n\t}\n\tif addFileInfo.BucketKey == \"\" {\n\t\treturn ErrAddFileWatch\n\t}\n\n\tif addFileInfo.BucketPath == \"\" {\n\t\treturn ErrAddFileWatch\n\t}\n\n\terr := bs.addFileInfoToStore(addFileInfo)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = bs.folderWatcher.AddFile(addFileInfo.LocalPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (bs *bucketSynchronizer) GetOpenFilePath(bucketSlug, bucketPath, dbID, cid string) (string, bool) {\n\tvar fi domain.AddWatchFile\n\tvar err error\n\treversKey := getOpenFileReverseKey(bucketSlug, bucketPath, dbID, cid)\n\n\tif fi, err = bs.getOpenFileInfo(reversKey); err != nil {\n\t\treturn \"\", false\n\t}\n\n\tif fi.LocalPath == \"\" {\n\t\treturn \"\", false\n\t}\n\n\treturn fi.LocalPath, true\n}\n\nfunc getOpenFileKey(localPath string) string {\n\treturn OpenFilesKeyPrefix + localPath\n}\n\nfunc getOpenFileReverseKey(bucketSlug, bucketPath, dbID, cid string) string {\n\treturn ReverseOpenFilesKeyPrefix + bucketSlug + \":\" + bucketPath + \":\" + dbID + \":\" + cid\n}\n\nfunc (bs *bucketSynchronizer) getOpenFileBucketSlugAndPath(localPath string) (domain.AddWatchFile, bool) {\n\tvar fi domain.AddWatchFile\n\tvar err error\n\tif fi, err = bs.getOpenFileInfo(getOpenFileKey(localPath)); err != nil {\n\t\treturn domain.AddWatchFile{}, false\n\t}\n\n\tif fi.BucketSlug == \"\" {\n\t\treturn domain.AddWatchFile{}, false\n\t}\n\n\treturn fi, true\n}\n\n// Helper function to set open file info in the store\nfunc (bs *bucketSynchronizer) addFileInfoToStore(addFileInfo domain.AddWatchFile) error {\n\tout, err := json.Marshal(addFileInfo)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := bs.store.SetString(getOpenFileKey(addFileInfo.LocalPath), string(out)); err != nil {\n\t\treturn err\n\t}\n\treverseKey := getOpenFileReverseKey(addFileInfo.BucketSlug, addFileInfo.BucketPath, addFileInfo.DbId, addFileInfo.Cid)\n\tif err := bs.store.SetString(reverseKey, string(out)); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Helper function to remove file information from store\nfunc (bs *bucketSynchronizer) removeFileInfo(addFileInfo domain.AddWatchFile) error {\n\tif err := bs.store.Remove([]byte(getOpenFileKey(addFileInfo.LocalPath))); err != nil {\n\t\treturn err\n\t}\n\treverseKey := getOpenFileReverseKey(addFileInfo.BucketSlug, addFileInfo.BucketPath, addFileInfo.DbId, addFileInfo.Cid)\n\tif err := bs.store.Remove([]byte(reverseKey)); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Helper function to retrieve open file info from store\nfunc (bs *bucketSynchronizer) getOpenFileInfo(key string) (domain.AddWatchFile, error) {\n\tvar fi []byte\n\tvar err error\n\n\tif fi, err = bs.store.Get([]byte(key)); err != nil {\n\t\treturn domain.AddWatchFile{}, err\n\t}\n\n\tvar fileInfo domain.AddWatchFile\n\n\tif err := json.Unmarshal(fi, &fileInfo); err != nil {\n\t\treturn domain.AddWatchFile{}, err\n\t}\n\n\treturn fileInfo, nil\n}\n"
  },
  {
    "path": "core/sync/textile.go",
    "content": "package sync\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n)\n\nfunc (h *textileHandler) OnCreate(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Info(\"Default Listener Handler: OnCreate\")\n\tinstance := &bucket.BucketData{}\n\tif err := json.Unmarshal(listenEvent.Action.Instance, instance); err != nil {\n\t\tlog.Error(\"failed to unmarshal listen result: %v\", err)\n\t}\n\tevt := events.NewTextileEvent(instance.Name)\n\th.notifier.SendTextileEvent(evt)\n}\n\nfunc (h *textileHandler) OnRemove(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Info(\"Default Listener Handler: OnRemove\")\n\tinstance := &bucket.BucketData{}\n\tif err := json.Unmarshal(listenEvent.Action.Instance, instance); err != nil {\n\t\tlog.Error(\"failed to unmarshal listen result: %v\", err)\n\t}\n\tevt := events.NewTextileEvent(instance.Name)\n\th.notifier.SendTextileEvent(evt)\n}\n\nfunc (h *textileHandler) OnSave(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Info(\"Default Listener Handler: OnSave\")\n\tinstance := &bucket.BucketData{}\n\tif err := json.Unmarshal(listenEvent.Action.Instance, instance); err != nil {\n\t\tlog.Error(\"failed to unmarshal listen result: %v\", err)\n\t}\n\tevt := events.NewTextileEvent(instance.Name)\n\th.notifier.SendTextileEvent(evt)\n}\n"
  },
  {
    "path": "core/sync/textile_test.go",
    "content": "package sync\n\nimport (\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\t\"github.com/stretchr/testify/mock\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n)\n\nfunc TestTextileHandler_OnCreate(t *testing.T) {\n\tn := new(mocks.TextileNotifier)\n\tth := &textileHandler{\n\t\tnotifier: n,\n\t}\n\n\tb := []byte(`{\"Key\":\"bafzbeid2zp544qy6ktwdlr5xxsmsioclbxj42dkbqckm35e6l5biqlo3tq\",\"Name\":\"test-bucket-1\"}`)\n\n\tbuck := &bucket.BucketData{}\n\taction := tc.Action{\n\t\tCollection: \"buckets\",\n\t\tType:       1,\n\t\tInstanceID: \"dummy-id\",\n\t\tInstance:   b,\n\t}\n\tevt := &tc.ListenEvent{\n\t\tAction: action,\n\t}\n\n\tn.On(\"SendTextileEvent\", mock.Anything).Return()\n\n\tth.OnCreate(buck, evt)\n\tn.AssertExpectations(t)\n}\n\nfunc TestTextileHandler_OnRemove(t *testing.T) {\n\tn := new(mocks.TextileNotifier)\n\tth := &textileHandler{\n\t\tnotifier: n,\n\t}\n\n\tb := []byte(`{\"Key\":\"bafzbeid2zp544qy6ktwdlr5xxsmsioclbxj42dkbqckm35e6l5biqlo3tq\",\"Name\":\"test-bucket-1\"}`)\n\n\tbuck := &bucket.BucketData{}\n\taction := tc.Action{\n\t\tCollection: \"buckets\",\n\t\tType:       1,\n\t\tInstanceID: \"dummy-id\",\n\t\tInstance:   b,\n\t}\n\tevt := &tc.ListenEvent{\n\t\tAction: action,\n\t}\n\n\tn.On(\"SendTextileEvent\", mock.Anything).Return()\n\n\tth.OnRemove(buck, evt)\n\tn.AssertExpectations(t)\n}\n\nfunc TestTextileHandler_OnSave(t *testing.T) {\n\tn := new(mocks.TextileNotifier)\n\tth := &textileHandler{\n\t\tnotifier: n,\n\t}\n\n\tb := []byte(`{\"Key\":\"bafzbeid2zp544qy6ktwdlr5xxsmsioclbxj42dkbqckm35e6l5biqlo3tq\",\"Name\":\"test-bucket-1\"}`)\n\n\tbuck := &bucket.BucketData{}\n\taction := tc.Action{\n\t\tCollection: \"buckets\",\n\t\tType:       1,\n\t\tInstanceID: \"dummy-id\",\n\t\tInstance:   b,\n\t}\n\tevt := &tc.ListenEvent{\n\t\tAction: action,\n\t}\n\n\tn.On(\"SendTextileEvent\", mock.Anything).Return()\n\n\tth.OnSave(buck, evt)\n\tn.AssertExpectations(t)\n}\n"
  },
  {
    "path": "core/textile/README.md",
    "content": "# Textile Wrappers\n\nThis package contains wrappers around Textile Threads and Buckets.\n\n## Usage\n\n### Initialization and Startup\n\nInitialize Space's Textile Client by runing\n\n```go\nclient := textile.NewClient(store)\nclient.Start(ctx, config)\n```\n\nThis will start the Textile connection, try to authenticate to the Hub, create a thread for metadata and a default bucket if there's none.\n\n#### TODO\n\n- Separate the initialization logic into a new function that can be called from an imported \"wallet\". That way the initialized metadata and initial buckets can be pulled from the Hub if they exist.\n\n## Internal State\n\nTextile Client holds the following objects:\n\n- store: A connection to the store. Used to fetch keys and store the meta thread threadID.\n- threads: A connection to Textile's Thread Client, initiated after startup.\n- bucketsClient: A connection to Textile's Bucket Client, initiated after startup.\n- netc: Wraps Textile network operations.\n- isRunning: Boolean that is set to true if the initialization after calling Start finished successfully.\n- Ready: A channel that gets emitted to after startup.\n- cfg: A reference to the config object.\n- isConnectedToHub: A boolean indicating if the initial Hub connection and authorization succeeded. If false, bucket operations will not be replicated on the Hub.\n\nAfter initialization, Textile Client's state is mainly stored in the \"meta thread\". This meta thread stores a collection of the buckets the user has created or joined. This meta thread can be synced and joined in case the user wants to go cross-platform. The thread ID of the meta thread is stored in the local store. Operations over the meta thread are done in `collections.go`.\n\nCreating and joining buckets (`bucket_factory.go`) adds a bucket instance to the meta thread. Listing and getting buckets query the meta thread to obtain the bucket's threadID and name. Using this info, these methods instantiate a Bucket object (`./bucket/bucket.go`), which exposes methods to do in bucket operations such as listing and adding files to a bucket.\n\n## Hub authentication\n\nCurrently, we attempt to connect to the Hub on initialization. In coming releases, we might switch that so that it can be toggled on and off from the API. If the Hub connection succeeds, all bucket operations will include the auth token in the calls to Textile's bucket client. This will trigger Hub replication. The auth token is obtained by signing a challenge received from the Hub using the user private key. If the challenge is signed correctly, the Hub returns a non-expiring auth token that we store so that we don't need to re-authenticate.\n\nThe logic for authenticating and prepending the keys before bucket operations can be seen in `bucket_factory.go` in the method `getBucketContext`. It creates a Context instance that includes all the necessary information for accessing the correct thread and include the correct auth token.\n"
  },
  {
    "path": "core/textile/account.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n)\n\nfunc (tc *textileClient) DeleteAccount(ctx context.Context) error {\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn err\n\t}\n\n\t// delete local buckets\n\tbucks, err := tc.ListBuckets(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, b := range bucks {\n\t\tbs, err := tc.GetModel().FindBucket(ctx, b.Slug())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdbid, err := b.GetThreadID(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx, _, err = tc.getBucketContext(ctx, utils.CastDbIDToString(*dbid), b.Slug(), false, bs.EncryptionKey)\n\t\terr = tc.bucketsClient.Remove(ctx, b.Key())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tctx, _, err = tc.getBucketContext(ctx, bs.RemoteDbID, b.Slug(), true, bs.EncryptionKey)\n\t\terr = tc.hb.Remove(ctx, bs.RemoteBucketKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// disable sync\n\ttc.DisableSync()\n\n\t// stop backgroundjobs\n\ttc.sync.Shutdown()\n\n\t// stop listener\n\ttc.DeleteListeners(ctx)\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/textile/buckd.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\tconnmgr \"github.com/libp2p/go-libp2p-connmgr\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"github.com/textileio/textile/v2/core\"\n)\n\nvar IpfsAddr string\nvar MaxThreadsConn int\nvar MinThreadsConn int\n\ntype TextileBuckd struct {\n\ttextile   *core.Textile\n\tIsRunning bool\n\tReady     chan bool\n\tcfg       config.Config\n}\n\nfunc NewBuckd(cfg config.Config) *TextileBuckd {\n\treturn &TextileBuckd{\n\t\tReady: make(chan bool),\n\t\tcfg:   cfg,\n\t}\n}\n\nfunc (tb *TextileBuckd) Start(ctx context.Context) error {\n\tIpfsAddr = tb.cfg.GetString(config.Ipfsaddr, \"/ip4/127.0.0.1/tcp/5001\")\n\tMinThreadsConn = tb.cfg.GetInt(config.MinThreadsConnection, 50)\n\tMaxThreadsConn = tb.cfg.GetInt(config.MaxThreadsConnection, 100)\n\n\taddrAPI := cmd.AddrFromStr(tb.cfg.GetString(config.BuckdApiMaAddr, \"/ip4/127.0.0.1/tcp/3006\"))\n\taddrAPIProxy := cmd.AddrFromStr(tb.cfg.GetString(config.BuckdApiProxyMaAddr, \"/ip4/127.0.0.1/tcp/3007\"))\n\taddrThreadsHost := cmd.AddrFromStr(tb.cfg.GetString(config.BuckdThreadsHostMaAddr, \"/ip4/0.0.0.0/tcp/4006\"))\n\n\taddrIpfsAPI := cmd.AddrFromStr(IpfsAddr)\n\n\tgatewayPort := tb.cfg.GetInt(config.BuckdGatewayPort, 8006)\n\taddrGatewayHost := cmd.AddrFromStr(fmt.Sprintf(\"/ip4/127.0.0.1/tcp/%d\", gatewayPort))\n\taddrGatewayURL := fmt.Sprintf(\"http://127.0.0.1:%d\", gatewayPort)\n\n\tbuckdPath := tb.cfg.GetString(config.BuckdPath, \"\")\n\tif buckdPath == \"\" {\n\t\thomeDir, err := os.UserHomeDir()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbuckdPath = homeDir + \"/.buckd\"\n\t\tlog.Debug(\"No Buckd Path provided. Using default.\", \"path:\"+buckdPath)\n\t}\n\n\ttextile, err := core.NewTextile(ctx, core.Config{\n\t\tRepoPath:           buckdPath + \"/repo\",\n\t\tCollectionRepoPath: buckdPath + \"/collections\",\n\t\tAddrAPI:            addrAPI,\n\t\tAddrAPIProxy:       addrAPIProxy,\n\t\tAddrThreadsHost:    addrThreadsHost,\n\t\tAddrIPFSAPI:        addrIpfsAPI,\n\t\tAddrGatewayHost:    addrGatewayHost,\n\t\tAddrGatewayURL:     addrGatewayURL,\n\t\t//AddrPowergateAPI: addrPowergateApi,\n\t\t//UseSubdomains:    config.Viper.GetBool(\"gateway.subdomains\"),\n\t\t//DNSDomain:        dnsDomain,\n\t\t//DNSZoneID:        dnsZoneID,\n\t\t//DNSToken:         dnsToken,\n\t\tThreadsConnManager: connmgr.NewConnManager(MinThreadsConn, MaxThreadsConn, time.Second*20),\n\t\tDebug:              false,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttextile.Bootstrap()\n\n\tlog.Info(\"Welcome to bucket\", fmt.Sprintf(\"peerID:%s\", textile.HostID().String()))\n\n\tlog.Info(\"Sleeping for 5s to wait for buckd grpc ports to listen ...\")\n\ttime.Sleep(5 * time.Second)\n\n\ttb.textile = textile\n\ttb.IsRunning = true\n\ttb.Ready <- true\n\treturn nil\n}\n\nfunc (tb *TextileBuckd) WaitForReady() chan bool {\n\treturn tb.Ready\n}\n\nfunc (tb *TextileBuckd) Stop() error {\n\ttb.IsRunning = false\n\terr := tb.textile.Close(true)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (tb *TextileBuckd) Shutdown() error {\n\tclose(tb.Ready)\n\treturn tb.Stop()\n}\n"
  },
  {
    "path": "core/textile/bucket/bucket.go",
    "content": "package bucket\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/ipfs/interface-go-ipfs-core/path\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tbucketsClient \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbucketsproto \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/buckets\"\n)\n\ntype BucketData struct {\n\tKey       string `json:\"_id\"`\n\tName      string `json:\"name\"`\n\tPath      string `json:\"path\"`\n\tDNSRecord string `json:\"dns_record,omitempty\"`\n\t//Archives  Archives `json:\"archives\"`\n\tCreatedAt int64 `json:\"created_at\"`\n\tUpdatedAt int64 `json:\"updated_at\"`\n}\n\ntype DirEntries bucketsproto.ListPathResponse\n\ntype BucketsClient interface {\n\tPushPath(ctx context.Context, key, pth string, reader io.Reader, opts ...bucketsClient.Option) (result path.Resolved, root path.Resolved, err error)\n\tPullPath(ctx context.Context, key, pth string, writer io.Writer, opts ...bucketsClient.Option) error\n\tListPath(ctx context.Context, key, pth string) (*bucketsproto.ListPathResponse, error)\n\tRemovePath(ctx context.Context, key, pth string, opts ...bucketsClient.Option) (path.Resolved, error)\n\tListIpfsPath(ctx context.Context, ipfsPath path.Path) (*bucketsproto.ListIpfsPathResponse, error)\n\tPushPathAccessRoles(ctx context.Context, key, path string, roles map[string]buckets.Role) error\n}\n\ntype EachFunc = func(ctx context.Context, b *Bucket, path string) error\n\ntype BucketInterface interface {\n\tSlug() string\n\tKey() string\n\tGetData() BucketData\n\tGetContext(ctx context.Context) (context.Context, *thread.ID, error)\n\tGetClient() BucketsClient\n\tGetThreadID(ctx context.Context) (*thread.ID, error)\n\tDirExists(ctx context.Context, path string) (bool, error)\n\tFileExists(ctx context.Context, path string) (bool, error)\n\tUpdatedAt(ctx context.Context, path string) (int64, error)\n\tUploadFile(\n\t\tctx context.Context,\n\t\tpath string,\n\t\treader io.Reader,\n\t) (result path.Resolved, root path.Path, err error)\n\tDownloadFile(\n\t\tctx context.Context,\n\t\tpath string,\n\t\treader io.Reader,\n\t) (result path.Resolved, root path.Path, err error)\n\tGetFile(\n\t\tctx context.Context,\n\t\tpath string,\n\t\tw io.Writer,\n\t) error\n\tCreateDirectory(\n\t\tctx context.Context,\n\t\tpath string,\n\t) (result path.Resolved, root path.Path, err error)\n\tListDirectory(\n\t\tctx context.Context,\n\t\tpath string,\n\t) (*DirEntries, error)\n\tDeleteDirOrFile(\n\t\tctx context.Context,\n\t\tpath string,\n\t) (path.Resolved, error)\n\tItemsCount(\n\t\tctx context.Context,\n\t\tpath string,\n\t\twithRecursive bool,\n\t) (int32, error)\n\tEach(\n\t\tctx context.Context,\n\t\tpath string,\n\t\titerator EachFunc,\n\t\twithRecursive bool,\n\t) (int, error)\n}\n\ntype Notifier interface {\n\tOnUploadFile(bucketSlug string, bucketPath string, result path.Resolved, root path.Path)\n}\n\n// NOTE: all write operations should use the lock for the bucket to keep consistency\n// TODO: Maybe read operations dont need a lock, needs testing\n// struct for implementing bucket interface\ntype Bucket struct {\n\tlock             sync.RWMutex\n\troot             *bucketsproto.Root\n\tbucketsClient    BucketsClient\n\tgetBucketContext GetBucketContextFn\n\tnotifier         Notifier\n}\n\nfunc (b *Bucket) Slug() string {\n\treturn b.GetData().Name\n}\n\ntype GetBucketContextFn func(context.Context, string) (context.Context, *thread.ID, error)\n\nfunc New(\n\troot *bucketsproto.Root,\n\tgetBucketContext GetBucketContextFn,\n\tbucketsClient BucketsClient,\n) *Bucket {\n\treturn &Bucket{\n\t\troot:             root,\n\t\tbucketsClient:    bucketsClient,\n\t\tgetBucketContext: getBucketContext,\n\t\tnotifier:         nil,\n\t}\n}\n\nfunc (b *Bucket) Key() string {\n\treturn b.GetData().Key\n}\n\nfunc (b *Bucket) GetData() BucketData {\n\treturn BucketData{\n\t\tKey:       b.root.Key,\n\t\tName:      b.root.Name,\n\t\tPath:      b.root.Path,\n\t\tDNSRecord: \"\",\n\t\tCreatedAt: b.root.CreatedAt,\n\t\tUpdatedAt: b.root.UpdatedAt,\n\t}\n}\n\nfunc (b *Bucket) GetContext(ctx context.Context) (context.Context, *thread.ID, error) {\n\treturn b.getBucketContext(ctx, b.root.Name)\n}\n\nfunc (b *Bucket) GetClient() BucketsClient {\n\treturn b.bucketsClient\n}\n\nfunc (b *Bucket) GetThreadID(ctx context.Context) (*thread.ID, error) {\n\t_, threadID, err := b.GetContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn threadID, nil\n}\n\nfunc (b *Bucket) AttachNotifier(n Notifier) {\n\tb.notifier = n\n}\n"
  },
  {
    "path": "core/textile/bucket/bucket_dir.go",
    "content": "package bucket\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/ipfs/interface-go-ipfs-core/path\"\n)\n\n// Keep file is added to empty directories\nvar keepFileName = \".keep\"\n\nfunc (b *Bucket) DirExists(ctx context.Context, path string) (bool, error) {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\n\t_, err := b.ListDirectory(ctx, path)\n\n\tlog.Debug(\"returned from bucket call\")\n\n\tif err != nil {\n\t\t// NOTE: not sure if this is the best approach but didnt\n\t\t// want to loop over items each time\n\t\tmatch, _ := regexp.MatchString(\".*no link named.*under.*\", err.Error())\n\t\tif match {\n\t\t\treturn false, nil\n\t\t}\n\t\tlog.Info(\"error doing list path on non existent directoy: \", err.Error())\n\t\t// Since a nil would be interpreted as a false\n\t\treturn false, err\n\t}\n\treturn true, nil\n}\n\n// CreateDirectory creates an empty directory\n// Because textile doesn't support empty directory an empty .keep file is created\n// in the directory\nfunc (b *Bucket) CreateDirectory(ctx context.Context, path string) (result path.Resolved, root path.Path, err error) {\n\tb.lock.Lock()\n\tdefer b.lock.Unlock()\n\tctx, _, err = b.GetContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// append .keep file to the end of the directory\n\temptyDirPath := strings.TrimRight(path, \"/\") + \"/\" + keepFileName\n\treturn b.bucketsClient.PushPath(ctx, b.Key(), emptyDirPath, &bytes.Buffer{})\n}\n\n// ListDirectory returns a list of items in a particular directory\nfunc (b *Bucket) ListDirectory(ctx context.Context, path string) (*DirEntries, error) {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\tctx, _, err := b.GetContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err := b.bucketsClient.ListPath(ctx, b.Key(), path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn (*DirEntries)(result), err\n}\n\n// DeleteDirOrFile will delete file or directory at path\nfunc (b *Bucket) DeleteDirOrFile(ctx context.Context, path string) (path.Resolved, error) {\n\tb.lock.Lock()\n\tdefer b.lock.Unlock()\n\n\tctx, _, err := b.GetContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b.bucketsClient.RemovePath(ctx, b.Key(), path)\n}\n\n// return the recursive items count for a path\nfunc (b *Bucket) ItemsCount(ctx context.Context, path string, withRecursive bool) (int32, error) {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\n\tvar count int32\n\n\tdir, err := b.ListDirectory(ctx, path)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tcount = dir.Item.ItemsCount\n\n\tif withRecursive {\n\t\tfor _, item := range dir.Item.Items {\n\t\t\tif utils.IsMetaFileName(item.Name) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif item.IsDir {\n\t\t\t\tn, err := b.ItemsCount(ctx, item.Path, withRecursive)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\n\t\t\t\tcount += n\n\t\t\t}\n\t\t}\n\t}\n\n\treturn count, nil\n}\n\n// iterate over the bucket\nfunc (b *Bucket) Each(ctx context.Context, path string, iterator EachFunc, withRecursive bool) (int, error) {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\n\tvar count int\n\n\tdir, err := b.ListDirectory(ctx, path)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tfor _, item := range dir.Item.Items {\n\t\tif utils.IsMetaFileName(item.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tcurrItemPath := item.Name\n\t\tif path != \"\" {\n\t\t\tcurrItemPath = path + \"/\" + currItemPath\n\t\t}\n\n\t\tvar n int\n\n\t\tif withRecursive && item.IsDir {\n\t\t\tif n, err = b.Each(ctx, currItemPath, iterator, withRecursive); err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\n\t\t\tcount += n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := iterator(ctx, b, currItemPath); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tcount += n\n\t}\n\n\treturn count, nil\n}\n"
  },
  {
    "path": "core/textile/bucket/bucket_file.go",
    "content": "package bucket\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/opentracing/opentracing-go\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/ipfs/interface-go-ipfs-core/path\"\n)\n\nfunc (b *Bucket) FileExists(ctx context.Context, pth string) (bool, error) {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\n\tctx, _, err := b.GetContext(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tlistPathRes, err := b.bucketsClient.ListPath(ctx, b.GetData().Key, pth)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tctxWithDeadline, ctxCancel := context.WithDeadline(ctx, time.Now().Add(3*time.Second))\n\tdefer ctxCancel()\n\n\t// Call ListIpfsPath with deadline to avoid waiting too much for DHT to resolve\n\t_, err = b.bucketsClient.ListIpfsPath(ctxWithDeadline, path.New(listPathRes.Item.Cid))\n\tif err != nil {\n\t\tmatch, _ := regexp.MatchString(\".*no link named.*under.*\", err.Error())\n\t\tif match {\n\t\t\treturn false, nil\n\t\t}\n\t\t// Since a nil would be interpreted as a false\n\t\treturn false, err\n\t}\n\n\treturn true, nil\n}\n\nfunc (b *Bucket) UpdatedAt(ctx context.Context, pth string) (int64, error) {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\n\tctx, _, err := b.GetContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tresponse, err := b.bucketsClient.ListPath(ctx, b.GetData().Key, pth)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn response.Item.Metadata.UpdatedAt, nil\n}\n\nfunc (b *Bucket) UploadFile(\n\tctx context.Context,\n\tpath string,\n\treader io.Reader,\n) (result path.Resolved, root path.Path, err error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"Bucket.UploadFile\")\n\tdefer span.Finish()\n\n\tb.lock.Lock()\n\tdefer b.lock.Unlock()\n\n\tctx, _, err = b.GetContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tresult, root, err = b.bucketsClient.PushPath(ctx, b.Key(), path, reader)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif b.notifier != nil {\n\t\tb.notifier.OnUploadFile(b.Slug(), path, result, root)\n\t}\n\n\treturn result, root, nil\n}\n\nfunc (b *Bucket) DownloadFile(ctx context.Context, path string, reader io.Reader) (result path.Resolved, root path.Path, err error) {\n\tb.lock.Lock()\n\tdefer b.lock.Unlock()\n\n\tctx, _, err = b.GetContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tresult, root, err = b.bucketsClient.PushPath(ctx, b.Key(), path, reader)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// no notification\n\n\treturn result, root, nil\n}\n\n// GetFile pulls path from bucket writing it to writer if it's a file.\nfunc (b *Bucket) GetFile(ctx context.Context, path string, w io.Writer) error {\n\tb.lock.RLock()\n\tdefer b.lock.RUnlock()\n\n\tctx, _, err := b.GetContext(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := b.bucketsClient.PullPath(ctx, b.Key(), path, w); err != nil {\n\t\tlog.Error(\"error in GetFile from textile client\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/textile/bucket/crypto/crypto.go",
    "content": "package crypto\n\nimport (\n\t\"bytes\"\n\tb64 \"encoding/base64\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"strings\"\n)\n\nfunc parseKeys(key []byte) (aesKey, iv, hmacKey []byte, err error) {\n\tif len(key) != aesKeySize+ivKeySize+hmacKeySize {\n\t\treturn nil, nil, nil, errors.New(\"unsupported encryption keys provided.\")\n\t}\n\n\treturn key[:aesKeySize], key[aesKeySize:(aesKeySize + ivKeySize)], key[(aesKeySize + ivKeySize):], nil\n}\n\n// EncryptPathItems returns an encrypted path and a Reader that reads the encrypted data from the\n// plain reader passed into the function.\n// Encrypted data is AES-CTR of data + AES-512 HMAC of encrypted data\n//\n// NOTE: key must be a 64 byte long key\n// To decrypt the result of this function use the DecryptPathItems function\nfunc EncryptPathItems(key []byte, path string, plainReader io.Reader) (string, io.Reader, error) {\n\t// split key into key and secret\n\t// use key and secret and IV\n\n\t// encrypt path\n\taesKey, iv, hmacKey, err := parseKeys(key)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tencryptedPath := \"\"\n\tpathParts := strings.Split(path, \"/\")\n\tpathPartsLen := len(pathParts)\n\tfor i, pathItem := range pathParts {\n\t\tif pathItem == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tencryptedPathReader, err := NewEncryptReader(\n\t\t\tstrings.NewReader(pathItem),\n\t\t\taesKey,\n\t\t\tiv,\n\t\t\thmacKey,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\n\t\tencryptedPathItem, err := readAsBase64Strings(encryptedPathReader)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t\tencryptedPath += encryptedPathItem\n\t\tif i != pathPartsLen-1 {\n\t\t\tencryptedPath += \"/\"\n\t\t}\n\t}\n\n\t// encrypt data\n\tvar encryptedReader io.Reader\n\tif plainReader != nil {\n\t\tvar err error\n\t\tencryptedReader, err = NewEncryptReader(\n\t\t\tplainReader,\n\t\t\taesKey,\n\t\t\tiv,\n\t\t\thmacKey,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t}\n\n\treturn encryptedPath, encryptedReader, nil\n}\n\n// DecryptPathItems returns a decrypted path string and an io.Reader that reads the decrypted data from the\n// encrypted reader passed into the function.\n// To only decrypt a path, pass in an empty byte buffer as the reader and check only for the string result.\n//\n// NOTE: key must be a 64 byte long key\nfunc DecryptPathItems(key []byte, path string, encryptedReader io.Reader) (string, io.ReadCloser, error) {\n\t// decrypt path\n\taesKey, iv, hmacKey, err := parseKeys(key)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tdecryptedPath := \"\"\n\tpathParts := strings.Split(path, \"/\")\n\tpathPartsLen := len(pathParts)\n\tfor i, pathItem := range pathParts {\n\t\tif pathItem == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tencryptedEntryNameBytes, err := bytesFromBase64Strings(pathItem)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\n\t\tdecryptedPathReader, err := NewDecryptReader(\n\t\t\tbytes.NewBuffer(encryptedEntryNameBytes),\n\t\t\taesKey,\n\t\t\tiv,\n\t\t\thmacKey,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\n\t\tdecryptedPathItem, err := readBufferString(decryptedPathReader)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\n\t\tdecryptedPath += decryptedPathItem\n\t\tif i != pathPartsLen-1 {\n\t\t\tdecryptedPath += \"/\"\n\t\t}\n\t}\n\n\t// decrypt data\n\tvar decryptedReader io.ReadCloser\n\tif encryptedReader != nil {\n\t\tvar err error\n\t\tdecryptedReader, err = NewDecryptReader(\n\t\t\tencryptedReader,\n\t\t\taesKey,\n\t\t\tiv,\n\t\t\thmacKey,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t}\n\n\treturn decryptedPath, decryptedReader, nil\n}\n\nfunc readBufferString(buf io.Reader) (string, error) {\n\tbuilder := new(strings.Builder)\n\t_, err := io.Copy(builder, buf)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn builder.String(), nil\n}\n\nfunc readAsBase64Strings(buf io.Reader) (string, error) {\n\tdata, err := ioutil.ReadAll(buf)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tencodedData := b64.URLEncoding.EncodeToString(data)\n\treturn encodedData, nil\n}\n\nfunc bytesFromBase64Strings(data string) ([]byte, error) {\n\tdecodedData, err := b64.URLEncoding.DecodeString(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn decodedData, nil\n}\n"
  },
  {
    "path": "core/textile/bucket/crypto/crypto_test.go",
    "content": "package crypto\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"io/ioutil\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar validKeysSize = 80\n\nfunc Test_EncryptPathItems_Fails_For_InvalidKeys(t *testing.T) {\n\tassert := require.New(t)\n\n\tkey := make([]byte, 64)\n\t_, _ = rand.Read(key)\n\n\t_, _, err := EncryptPathItems(key, \"\", bytes.NewBufferString(\"\"))\n\tassert.Error(err, \"Encrypt Path Item with wrong key should fail\")\n}\n\nfunc Test_DecryptPathItems_Fails_For_InvalidKeys(t *testing.T) {\n\tassert := require.New(t)\n\n\tkey := make([]byte, 64)\n\t_, _ = rand.Read(key)\n\n\t_, _, err := DecryptPathItems(key, \"\", bytes.NewBufferString(\"\"))\n\tassert.Error(err, \"Decrypt Path Item with wrong key should fail\")\n}\n\nfunc Test_EncryptPathItems_Works_With_DecryptPathItems(t *testing.T) {\n\tassert := require.New(t)\n\n\tkey := make([]byte, validKeysSize)\n\t_, _ = rand.Read(key)\n\tplainPath := \"smiggle/was/here\"\n\tplainData := \"This is the original unencrypted data\"\n\n\tencryptedPath, encryptedReader, err := EncryptPathItems(key, plainPath, bytes.NewBufferString(plainData))\n\tassert.NoError(err, \"Error encrypting Path Items\")\n\tassert.NotEqual(encryptedPath, plainPath, \"Encrypted Path is equal to Plain Path\")\n\n\tdecryptedPath, decryptedReader, err := DecryptPathItems(key, encryptedPath, encryptedReader)\n\tassert.NoError(err, \"Error decrypting Path Items\")\n\tassert.Equal(plainPath, decryptedPath, \"Plain Path is not equal to decrypted path\")\n\tdecryptedData, err := ioutil.ReadAll(decryptedReader)\n\tassert.NoError(err)\n\tassert.Equal(plainData, bytes.NewBuffer(decryptedData).String(), \"Plain data is not equal to decrypted data\")\n}\n\nfunc Test_EncryptPathItems_And_DecryptPathItems_Work_With_TopLevel_Files(t *testing.T) {\n\tassert := require.New(t)\n\n\tkey := make([]byte, validKeysSize)\n\t_, _ = rand.Read(key)\n\tplainPath := \"single_directory_entry\"\n\n\tencryptedPath, _, err := EncryptPathItems(key, plainPath, nil)\n\tassert.NoError(err, \"Error encrypting Path Items\")\n\tassert.NotEqual(encryptedPath, plainPath, \"Encrypted Path is equal to Plain Path\")\n\n\tdecryptedPath, _, err := DecryptPathItems(key, encryptedPath, nil)\n\tassert.NoError(err, \"Error decrypting Path Items\")\n\tassert.Equal(plainPath, decryptedPath, \"Plain Path is not equal to decrypted path\")\n}\n"
  },
  {
    "path": "core/textile/bucket/crypto/decrypter.go",
    "content": "package crypto\n\nimport (\n\t\"bufio\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/hmac\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/odeke-em/go-utils/tmpfile\"\n)\n\nconst _16KB = 16 * 1024\n\nvar DecryptErr = errors.New(\"message corrupt or incorrect keys\")\n\n// NewDecryptReader creates an io.ReadCloser wrapping an io.Reader using the keys and iv\n// to decode the content using AES and verify HMAC.\nfunc NewDecryptReader(r io.Reader, aesKey, iv, hmacKey []byte) (io.ReadCloser, error) {\n\treturn newDecryptReader(r, aesKey, iv, hmacKey)\n}\n\nfunc newDecryptReader(r io.Reader, aesKey []byte, iv []byte, hmacKey []byte) (io.ReadCloser, error) {\n\tmac := make([]byte, hmacSize)\n\th := hmac.New(hashFunc, hmacKey)\n\tdst, err := tmpfile.New(&tmpfile.Context{\n\t\tDir:    os.TempDir(),\n\t\tSuffix: \"space-encrypted-\",\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// If there is an error, try to delete the temp file.\n\tdefer func() {\n\t\tif err != nil {\n\t\t\t_ = dst.Done()\n\t\t}\n\t}()\n\tb, err := aes.NewCipher(aesKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\td := &decryptReader{\n\t\ttmpFile: dst,\n\t\tsReader: &cipher.StreamReader{R: dst, S: cipher.NewCTR(b, iv)},\n\t}\n\tw := io.MultiWriter(h, dst)\n\tbuf := bufio.NewReaderSize(r, _16KB)\n\tfor {\n\t\tb, err := buf.Peek(_16KB)\n\t\tif err != nil && err != io.EOF {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err == io.EOF {\n\t\t\tleft := buf.Buffered()\n\t\t\tif left < hmacSize {\n\t\t\t\treturn nil, DecryptErr\n\t\t\t}\n\t\t\tcopy(mac, b[left-hmacSize:left])\n\t\t\t_, err = io.CopyN(w, buf, int64(left-hmacSize))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\t_, err = io.CopyN(w, buf, _16KB-hmacSize)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif !hmac.Equal(mac, h.Sum(nil)) {\n\t\treturn nil, DecryptErr\n\t}\n\n\tif _, err = dst.Seek(0, 0); err != nil {\n\t\treturn nil, err\n\t}\n\treturn d, nil\n}\n\n// decryptReader wraps a io.Reader decrypting its content.\ntype decryptReader struct {\n\ttmpFile *tmpfile.TmpFile\n\tsReader *cipher.StreamReader\n}\n\n// Read implements io.Reader.\nfunc (d *decryptReader) Read(dst []byte) (int, error) {\n\treturn d.sReader.Read(dst)\n}\n\n// Close implements io.Closer.\nfunc (d *decryptReader) Close() error {\n\treturn d.tmpFile.Done()\n}\n"
  },
  {
    "path": "core/textile/bucket/crypto/encrypter.go",
    "content": "package crypto\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/hmac\"\n\t\"crypto/sha512\"\n\t\"errors\"\n\t\"hash\"\n\t\"io\"\n)\n\nconst (\n\taesKeySize  = 32\n\tivKeySize   = 16\n\thmacKeySize = 32\n\thmacSize    = 64\n)\n\nvar hashFunc = sha512.New\n\n// hashReadWriter hashes on write and on read finalizes the hash and returns it.\n// Writes after a Read will return an error.\ntype hashReadWriter struct {\n\thash hash.Hash\n\tdone bool\n\tsum  io.Reader\n}\n\n// Write implements io.Writer\nfunc (h *hashReadWriter) Write(p []byte) (int, error) {\n\tif h.done {\n\t\treturn 0, errors.New(\"writing to hashReadWriter after read is not allowed\")\n\t}\n\treturn h.hash.Write(p)\n}\n\n// Read implements io.Reader.\nfunc (h *hashReadWriter) Read(p []byte) (int, error) {\n\tif !h.done {\n\t\th.done = true\n\t\th.sum = bytes.NewReader(h.hash.Sum(nil))\n\t}\n\treturn h.sum.Read(p)\n}\n\n// NewEncryptReader returns an io.Reader wrapping the provided io.Reader.\nfunc NewEncryptReader(r io.Reader, aesKey, iv, hmacKey []byte) (io.Reader, error) {\n\tif len(aesKey) != aesKeySize {\n\t\treturn nil, errors.New(\"encryption key has incorrect length\")\n\t}\n\n\tif len(iv) != ivKeySize {\n\t\treturn nil, errors.New(\"encryption initialization vector size has incorrect length\")\n\t}\n\n\tif len(hmacKey) != hmacKeySize {\n\t\treturn nil, errors.New(\"encryption hmac key has incorrect length\")\n\t}\n\n\treturn newEncryptReader(r, aesKey, iv, hmacKey)\n}\n\nfunc newEncryptReader(r io.Reader, aesKey, iv, hmacKey []byte) (io.Reader, error) {\n\tb, err := aes.NewCipher(aesKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\th := hmac.New(hashFunc, hmacKey)\n\thr := &hashReadWriter{hash: h}\n\tsr := &cipher.StreamReader{R: r, S: cipher.NewCTR(b, iv)}\n\treturn io.MultiReader(io.TeeReader(sr, hr), hr), nil\n}\n"
  },
  {
    "path": "core/textile/bucket_factory.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/common\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tma \"github.com/multiformats/go-multiaddr\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/alecthomas/jsonschema\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbuckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\ttdb \"github.com/textileio/textile/v2/threaddb\"\n)\n\nfunc NotFound(slug string) error {\n\treturn errors.New(fmt.Sprintf(\"bucket %s not found\", slug))\n}\n\ntype GetBucketForRemoteFileInput struct {\n\tPath   string\n\tDbID   string\n\tBucket string\n}\n\n// Gets a wrapped bucket\n// remoteFile is optional. Include if looking for wrappers for remote buckets (mainly used for received files)\nfunc (tc *textileClient) GetBucket(ctx context.Context, slug string, remoteFile *GetBucketForRemoteFileInput) (Bucket, error) {\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.getBucket(ctx, slug, remoteFile)\n}\n\n// Gets a wrapped bucket\n// remoteFile is optional. Include if looking for wrappers for remote buckets (mainly used for received files)\nfunc (tc *textileClient) getBucket(ctx context.Context, slug string, remoteFile *GetBucketForRemoteFileInput) (Bucket, error) {\n\tvar root *buckets_pb.Root\n\tgetContextFn := tc.getOrCreateBucketContext\n\tbucketsClient := tc.bucketsClient\n\tvar err error\n\n\tif remoteFile == nil {\n\t\t_, root, err = tc.getBucketRootFromSlug(ctx, slug)\n\t} else {\n\t\troot, getContextFn, err = tc.getBucketRootFromReceivedFile(ctx, remoteFile)\n\t\tbucketsClient = tc.hb\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb := bucket.New(\n\t\troot,\n\t\tgetContextFn,\n\t\ttc.getSecureBucketsClient(bucketsClient),\n\t)\n\n\t// Attach a notifier if the bucket is local\n\t// So that local ops can be synced to the remote node\n\tif remoteFile == nil && tc.notifier != nil {\n\t\tb.AttachNotifier(tc.notifier)\n\t}\n\n\treturn b, nil\n}\n\nfunc (tc *textileClient) getBucketForMirror(ctx context.Context, slug string) (Bucket, error) {\n\troot, getContextFn, _, err := tc.getBucketRootForMirror(ctx, slug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb := bucket.New(\n\t\troot,\n\t\tgetContextFn,\n\t\ttc.getSecureBucketsClient(tc.hb),\n\t)\n\n\treturn b, nil\n}\n\nfunc (tc *textileClient) GetDefaultBucket(ctx context.Context) (Bucket, error) {\n\treturn tc.GetBucket(ctx, defaultPersonalBucketSlug, nil)\n}\n\nfunc (tc *textileClient) getBucketContext(ctx context.Context, sDbID string, bucketSlug string, ishub bool, enckey []byte) (context.Context, *thread.ID, error) {\n\tdbID, err := utils.ParseDbIDFromString(sDbID)\n\tif err != nil {\n\t\tlog.Error(\"Error casting thread id\", err)\n\t\treturn nil, nil, err\n\t}\n\tctx, err = utils.GetThreadContext(ctx, bucketSlug, *dbID, ishub, tc.kc, tc.hubAuth, nil)\n\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tctx = common.NewBucketEncryptionKeyContext(ctx, enckey)\n\n\treturn ctx, dbID, err\n}\n\n// Returns a context that works for accessing a bucket\nfunc (tc *textileClient) getOrCreateBucketContext(ctx context.Context, bucketSlug string) (context.Context, *thread.ID, error) {\n\tm := tc.GetModel()\n\tbucketSchema, notFoundErr := m.FindBucket(ctx, bucketSlug)\n\n\tif notFoundErr == nil { // This means the bucket was already present in the schema\n\t\tvar err error\n\t\tvar dbID *thread.ID\n\t\tctx, dbID, err = tc.getBucketContext(ctx, bucketSchema.DbID, bucketSlug, false, bucketSchema.EncryptionKey)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\treturn ctx, dbID, err\n\t}\n\n\t// We need to create the thread and store it in the collection\n\tlog.Debug(\"getOrCreateBucketContext: Thread ID not found in meta store. Generating a new one...\")\n\tdbID := thread.NewIDV1(thread.Raw, 32)\n\n\tlog.Debug(\"getOrCreateBucketContext: Creating Thread DB for bucket \" + bucketSlug + \" at db \" + dbID.String())\n\n\tmanagedKey, err := tc.kc.GetManagedThreadKey(getBucketThreadManagedKey(bucketSlug))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tpk, _, err := tc.kc.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif err := tc.threads.NewDB(ctx, dbID, db.WithNewManagedThreadKey(managedKey), db.WithNewManagedLogKey(pk)); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tlog.Debug(\"getOrCreateBucketContext: Thread DB Created\")\n\tbucketSchema, err = m.CreateBucket(ctx, bucketSlug, utils.CastDbIDToString(dbID))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tbucketCtx, _, err := tc.getBucketContext(ctx, utils.CastDbIDToString(dbID), bucketSlug, false, bucketSchema.EncryptionKey)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn bucketCtx, &dbID, err\n}\n\nfunc (tc *textileClient) ListBuckets(ctx context.Context) ([]Bucket, error) {\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.listBuckets(ctx)\n}\n\nfunc (tc *textileClient) listBuckets(ctx context.Context) ([]Bucket, error) {\n\tbucketList, err := tc.GetModel().ListBuckets(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]Bucket, 0)\n\tfor _, b := range bucketList {\n\t\t// Skip listing the mirror bucket\n\t\tif b.Slug == defaultPersonalMirrorBucketSlug {\n\t\t\tcontinue\n\t\t}\n\t\tbucketObj, err := tc.getBucket(ctx, b.Slug, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult = append(result, bucketObj)\n\t}\n\n\treturn result, nil\n}\n\nfunc (tc *textileClient) getBucketRootFromReceivedFile(ctx context.Context, file *GetBucketForRemoteFileInput) (*buckets_pb.Root, bucket.GetBucketContextFn, error) {\n\treceivedFile, err := tc.GetModel().FindReceivedFile(ctx, file.DbID, file.Bucket, file.Path)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tgetCtxFn := func(ctx context.Context, slug string) (context.Context, *thread.ID, error) {\n\t\treturn tc.getBucketContext(ctx, receivedFile.DbID, receivedFile.Bucket, true, receivedFile.EncryptionKey)\n\t}\n\n\tremoteCtx, _, err := getCtxFn(ctx, receivedFile.Bucket)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tsbs := tc.getSecureBucketsClient(tc.hb)\n\n\tb, err := sbs.ListPath(remoteCtx, receivedFile.BucketKey, receivedFile.Path)\n\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif b != nil {\n\t\treturn b.GetRoot(), getCtxFn, nil\n\t}\n\n\treturn nil, nil, NotFound(receivedFile.Bucket)\n}\n\nfunc (tc *textileClient) getBucketRootForMirror(ctx context.Context, slug string) (*buckets_pb.Root, bucket.GetBucketContextFn, string, error) {\n\tbucket, err := tc.GetModel().FindBucket(ctx, slug)\n\tif err != nil {\n\t\treturn nil, nil, \"\", err\n\t}\n\n\tgetCtxFn := func(ctx context.Context, slug string) (context.Context, *thread.ID, error) {\n\t\treturn tc.getBucketContext(ctx, bucket.RemoteDbID, bucket.RemoteBucketSlug, true, bucket.EncryptionKey)\n\t}\n\n\tremoteCtx, _, err := getCtxFn(ctx, bucket.RemoteBucketSlug)\n\tif err != nil {\n\t\treturn nil, nil, \"\", err\n\t}\n\n\tsbs := tc.getSecureBucketsClient(tc.hb)\n\n\tb, err := sbs.ListPath(remoteCtx, bucket.RemoteBucketKey, \"\")\n\n\tif err != nil {\n\t\treturn nil, nil, \"\", err\n\t}\n\n\tif b != nil {\n\t\treturn b.GetRoot(), getCtxFn, bucket.RemoteBucketSlug, nil\n\t}\n\n\treturn nil, nil, \"\", NotFound(bucket.RemoteBucketSlug)\n}\n\nfunc (tc *textileClient) getBucketRootFromSlug(ctx context.Context, slug string) (context.Context, *buckets_pb.Root, error) {\n\tctx, _, err := tc.getOrCreateBucketContext(ctx, slug)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tbucketListReply, err := tc.bucketsClient.List(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tfor _, root := range bucketListReply.Roots {\n\t\tif root.Name == slug {\n\t\t\treturn ctx, root, nil\n\t\t}\n\t}\n\n\treturn nil, nil, NotFound(slug)\n}\n\n// Creates a bucket.\nfunc (tc *textileClient) CreateBucket(ctx context.Context, bucketSlug string) (Bucket, error) {\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.createBucket(ctx, bucketSlug)\n}\n\nfunc (tc *textileClient) createBucket(ctx context.Context, bucketSlug string) (Bucket, error) {\n\tlog.Debug(\"Creating a new bucket with slug \" + bucketSlug)\n\tvar err error\n\tm := tc.GetModel()\n\n\tif b, _ := tc.getBucket(ctx, bucketSlug, nil); b != nil {\n\t\treturn b, nil\n\t}\n\n\tctx, dbID, err := tc.getOrCreateBucketContext(ctx, bucketSlug)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Debug(\"Creating Bucket in db \" + dbID.String())\n\t// create bucket\n\tb, err := tc.bucketsClient.Create(ctx, bc.WithName(bucketSlug))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// We store the bucket in a meta thread so that we can later fetch a list of all buckets\n\tlog.Debug(\"Bucket \" + bucketSlug + \" created. Storing metadata.\")\n\tschema, err := m.CreateBucket(ctx, bucketSlug, utils.CastDbIDToString(*dbID))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttc.sync.NotifyBucketCreated(schema.Slug, schema.EncryptionKey)\n\ttc.sync.NotifyBucketRestore(bucketSlug)\n\n\tnewB := bucket.New(\n\t\tb.Root,\n\t\ttc.getOrCreateBucketContext,\n\t\ttc.getSecureBucketsClient(tc.bucketsClient),\n\t)\n\n\treturn newB, nil\n}\n\nfunc (tc *textileClient) ShareBucket(ctx context.Context, bucketSlug string) (*db.Info, error) {\n\tbs, err := tc.GetModel().FindBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdbID, err := utils.ParseDbIDFromString(bs.DbID)\n\tb, err := tc.threads.GetDBInfo(ctx, *dbID)\n\n\t// replicate to the hub\n\thubma := tc.cfg.GetString(config.TextileHubMa, \"\")\n\tif hubma == \"\" {\n\t\treturn nil, fmt.Errorf(\"no textile hub set\")\n\t}\n\n\tif _, err := tc.netc.AddReplicator(ctx, *dbID, cmd.AddrFromStr(hubma)); err != nil {\n\t\tlog.Error(\"Unable to replicate on the hub: \", err)\n\t\t// proceeding still because local/public IP\n\t\t// addresses could be used to join thread\n\t}\n\n\treturn &b, err\n}\n\nfunc (tc *textileClient) joinBucketViaAddress(ctx context.Context, address string, key thread.Key, bucketSlug string, opts ...db.NewManagedOption) error {\n\tmultiaddress, err := ma.NewMultiaddr(address)\n\tif err != nil {\n\t\tlog.Error(\"Unable to parse multiaddr\", err)\n\t\treturn err\n\t}\n\n\tvar (\n\t\tschema  *jsonschema.Schema\n\t\tindexes = []db.Index{{\n\t\t\tPath: \"path\",\n\t\t}}\n\t)\n\n\treflector := jsonschema.Reflector{ExpandedStruct: true}\n\tschema = reflector.Reflect(&tdb.Bucket{})\n\n\tnewDbOpts := []db.NewManagedOption{db.WithNewManagedCollections(db.CollectionConfig{\n\t\tName:    \"buckets\",\n\t\tSchema:  schema,\n\t\tIndexes: indexes,\n\t})}\n\tnewDbOpts = append(newDbOpts, opts...)\n\n\terr = tc.threads.NewDBFromAddr(ctx, multiaddress, key, newDbOpts...)\n\tif err != nil {\n\t\tlog.Error(\"Unable to join addr\", err)\n\t\treturn err\n\t}\n\n\tdbID, err := thread.FromAddr(multiaddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewBucket, err := tc.GetModel().UpsertBucket(ctx, bucketSlug, utils.CastDbIDToString(dbID))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewBucketCtx, _, err := tc.getBucketContext(ctx, utils.CastDbIDToString(dbID), bucketSlug, false, newBucket.EncryptionKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Create bucket in buckets client in case it's not already there\n\ttc.bucketsClient.Create(newBucketCtx, bc.WithName(bucketSlug))\n\n\treturn nil\n}\n\nfunc (tc *textileClient) JoinBucket(ctx context.Context, slug string, ti *domain.ThreadInfo) (bool, error) {\n\tk, err := thread.KeyFromString(ti.Key)\n\n\t// get the DB ID from the first ma\n\tma1, err := ma.NewMultiaddr(ti.Addresses[0])\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"Unable to parse multiaddr\")\n\t}\n\tdbID, err := thread.FromAddr(ma1)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"Unable to parse db id\")\n\t}\n\n\tfor _, a := range ti.Addresses {\n\t\tif err := tc.joinBucketViaAddress(ctx, a, k, slug); err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn true, nil\n\t}\n\n\tlog.Info(\"unable to join any advertised addresses, so joining via the hub instead\")\n\n\t// if it reached here then no addresses worked, try the hub\n\thubAddr := tc.cfg.GetString(config.TextileHubMa, \"\") + \"/thread/\" + dbID.String()\n\tif err := tc.joinBucketViaAddress(ctx, hubAddr, k, slug); err != nil {\n\t\tlog.Error(\"error joining bucket from hub\", err)\n\t\treturn false, err\n\t}\n\n\treturn true, nil\n}\n\nfunc (tc *textileClient) ToggleBucketBackup(ctx context.Context, bucketSlug string, bucketBackup bool) (bool, error) {\n\tbucketSchema, err := tc.GetModel().BucketBackupToggle(ctx, bucketSlug, bucketBackup)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif bucketSchema.Backup {\n\t\ttc.sync.NotifyBucketBackupOn(bucketSlug)\n\t} else {\n\t\ttc.sync.NotifyBucketBackupOff(bucketSlug)\n\t}\n\n\treturn bucketSchema.Backup, nil\n}\n\nfunc (tc *textileClient) BucketBackupRestore(ctx context.Context, bucketSlug string) error {\n\ttc.sync.NotifyBucketRestore(bucketSlug)\n\n\treturn nil\n}\n\nfunc (tc *textileClient) IsBucketBackup(ctx context.Context, bucketSlug string) bool {\n\tbucketSchema, err := tc.GetModel().FindBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn bucketSchema.Backup\n}\n\nfunc GetDefaultBucketSlug() string {\n\treturn defaultPersonalBucketSlug\n}\n\nfunc GetDefaultMirrorBucketSlug() string {\n\treturn defaultPersonalMirrorBucketSlug\n}\n\n// Attempts to restore buckets from a hub replication\n// Returns nil if there's nothing to restore or the restoration succeeded\nfunc (tc *textileClient) restoreBuckets(ctx context.Context) error {\n\tbucketList, err := tc.GetModel().ListBuckets(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(bucketList) == 0 && tc.shouldForceRestore {\n\t\treturn errors.New(\"No buckets ready for restore\")\n\t}\n\n\tdbs, err := tc.threads.ListDBs(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tthreadsInitialized := true\n\tfor _, b := range bucketList {\n\t\tdbID, err := utils.ParseDbIDFromString(b.DbID)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif _, ok := dbs[*dbID]; !ok {\n\t\t\tthreadsInitialized = false\n\t\t}\n\t}\n\n\t// Buckets already initialized\n\tif threadsInitialized {\n\t\treturn nil\n\t}\n\n\thubCtx, err := tc.getHubCtx(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thubmaStr := tc.cfg.GetString(config.TextileHubMa, \"\")\n\n\tpk, _, err := tc.kc.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Check if there's a bucket replicated on the hub\n\tfor _, b := range bucketList {\n\t\tdbID, err := utils.ParseDbIDFromString(b.DbID)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = tc.hnetc.GetThread(hubCtx, *dbID)\n\t\treplThreadExists := err == nil\n\n\t\tif replThreadExists {\n\t\t\thubmaWithThreadID := hubmaStr + \"/thread/\" + dbID.String()\n\n\t\t\tmanagedKey, err := tc.kc.GetManagedThreadKey(getBucketThreadManagedKey(b.Slug))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\terr = tc.joinBucketViaAddress(\n\t\t\t\tctx,\n\t\t\t\thubmaWithThreadID,\n\t\t\t\tmanagedKey,\n\t\t\t\tb.Slug,\n\t\t\t\tdb.WithNewManagedBackfillBlock(true),\n\t\t\t\tdb.WithNewManagedLogKey(pk),\n\t\t\t\tdb.WithNewManagedThreadKey(managedKey),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tlog.Error(\"could not join replicated bucket\", err)\n\t\t\t}\n\n\t\t\tif err != nil && tc.shouldForceRestore {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc getBucketThreadManagedKey(bucketSlug string) string {\n\treturn \"bucketKey_\" + bucketSlug\n}\n"
  },
  {
    "path": "core/textile/client.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tmanet \"github.com/multiformats/go-multiaddr/net\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\thttpapi \"github.com/ipfs/go-ipfs-http-client\"\n\tiface \"github.com/ipfs/interface-go-ipfs-core\"\n\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\tdb \"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/notifier\"\n\tsynchronizer \"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/core/util/address\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tma \"github.com/multiformats/go-multiaddr\"\n\tthreadsClient \"github.com/textileio/go-threads/api/client\"\n\tnc \"github.com/textileio/go-threads/net/api/client\"\n\tbucketsClient \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\tuc \"github.com/textileio/textile/v2/api/usersd/client\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\tmail \"github.com/textileio/textile/v2/mail/local\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n)\n\nconst healthcheckFailuresBeforeUnhealthy = 3\n\nvar HealthcheckMaxRetriesReachedErr = errors.New(fmt.Sprintf(\"textile client not initialized after %d attempts\", healthcheckFailuresBeforeUnhealthy))\n\ntype textileClient struct {\n\tstore              db.Store\n\tkc                 keychain.Keychain\n\tthreads            *threadsClient.Client\n\tht                 *threadsClient.Client\n\tbucketsClient      *bucketsClient.Client\n\tmb                 Mailbox\n\thb                 *bucketsClient.Client\n\tfilesSearchEngine  search.FilesSearchEngine\n\tisRunning          bool\n\tisInitialized      bool\n\tisSyncInitialized  bool\n\tReady              chan bool\n\tkeypairDeleted     chan bool\n\tshuttingDown       chan bool\n\tonHealthy          chan error\n\tonInitialized      chan bool\n\tcfg                config.Config\n\tisConnectedToHub   bool\n\tnetc               *nc.Client\n\thnetc              *nc.Client\n\tuc                 UsersClient\n\tmailEvents         chan mail.MailboxEvent\n\thubAuth            hub.HubAuth\n\tmbNotifier         GrpcMailboxNotifier\n\tfailedHealthchecks int\n\tsync               synchronizer.Synchronizer\n\tnotifier           bucket.Notifier\n\tipfsClient         iface.CoreAPI\n\tdbListeners        map[string]Listener\n\tshouldForceRestore bool\n\thealthcheckMutex   *sync.Mutex\n}\n\n// Creates a new Textile Client\nfunc NewClient(\n\tstore db.Store,\n\tkc keychain.Keychain,\n\thubAuth hub.HubAuth,\n\tuc UsersClient,\n\tmb Mailbox,\n\tsearch search.FilesSearchEngine,\n) *textileClient {\n\treturn &textileClient{\n\t\tstore:              store,\n\t\tkc:                 kc,\n\t\tthreads:            nil,\n\t\tbucketsClient:      nil,\n\t\tmb:                 mb,\n\t\tnetc:               nil,\n\t\thnetc:              nil,\n\t\tuc:                 uc,\n\t\tht:                 nil,\n\t\thb:                 nil,\n\t\tisRunning:          false,\n\t\tisInitialized:      false,\n\t\tisSyncInitialized:  false,\n\t\tReady:              make(chan bool),\n\t\tkeypairDeleted:     make(chan bool),\n\t\tshuttingDown:       make(chan bool),\n\t\tonHealthy:          make(chan error),\n\t\tonInitialized:      make(chan bool),\n\t\tmailEvents:         make(chan mail.MailboxEvent),\n\t\tisConnectedToHub:   false,\n\t\thubAuth:            hubAuth,\n\t\tmbNotifier:         nil,\n\t\tfailedHealthchecks: 0,\n\t\tsync:               nil,\n\t\tnotifier:           nil,\n\t\tdbListeners:        make(map[string]Listener),\n\t\tshouldForceRestore: false,\n\t\thealthcheckMutex:   &sync.Mutex{},\n\t\tfilesSearchEngine:  search,\n\t}\n}\n\nfunc (tc *textileClient) WaitForReady() chan bool {\n\treturn tc.Ready\n}\n\nfunc (tc *textileClient) WaitForInitialized() chan bool {\n\treturn tc.onInitialized\n}\n\n// Returns an error if it exceeds the max amount of attempts\nfunc (tc *textileClient) WaitForHealthy() chan error {\n\treturn tc.onHealthy\n}\n\nfunc (tc *textileClient) IsInitialized() bool {\n\treturn tc.isInitialized\n}\n\n// Healthy means initialized and connected to hub\nfunc (tc *textileClient) IsHealthy() bool {\n\treturn tc.isInitialized && tc.isConnectedToHub\n}\n\nfunc (tc *textileClient) requiresRunning() error {\n\tif tc.isRunning == false || tc.isInitialized == false {\n\t\treturn errors.New(\"ran an operation that requires starting and initializing textileClient first\")\n\t}\n\treturn nil\n}\n\nfunc (tc *textileClient) getHubCtx(ctx context.Context) (context.Context, error) {\n\tctx, err := tc.hubAuth.GetHubContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ctx, nil\n}\n\nfunc (tc *textileClient) initializeSync(ctx context.Context) {\n\tgetLocalBucketFn := func(ctx context.Context, slug string) (bucket.BucketInterface, error) {\n\t\treturn tc.getBucket(ctx, slug, nil)\n\t}\n\n\tgetMirrorBucketFn := func(ctx context.Context, slug string) (bucket.BucketInterface, error) {\n\t\treturn tc.getBucketForMirror(ctx, slug)\n\t}\n\n\ttc.sync = synchronizer.New(\n\t\ttc.store,\n\t\ttc.GetModel(),\n\t\ttc.kc,\n\t\ttc.hubAuth,\n\t\ttc.hb,\n\t\ttc.ht,\n\t\ttc.netc,\n\t\ttc.cfg,\n\t\tgetMirrorBucketFn,\n\t\tgetLocalBucketFn,\n\t\ttc.getBucketContext,\n\t\ttc.addListener,\n\t)\n\n\ttc.notifier = notifier.New(tc.sync)\n\n\tif err := tc.sync.RestoreQueue(); err != nil {\n\t\tlog.Warn(\"Could not restore Textile synchronizer queue. Queue will start fresh.\")\n\t}\n\n\ttc.isSyncInitialized = true\n\ttc.sync.Start(ctx)\n}\n\n// Starts the Textile Client\nfunc (tc *textileClient) start(ctx context.Context, cfg config.Config) error {\n\ttc.cfg = cfg\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\n\topts = append(opts, grpc.WithInsecure())\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\tvar threads *threadsClient.Client\n\tvar buckets *bucketsClient.Client\n\tvar netc *nc.Client\n\n\t// by default it goes to local threads now\n\taddrAPI := cmd.AddrFromStr(tc.cfg.GetString(config.BuckdApiMaAddr, \"/ip4/127.0.0.1/tcp/3006\"))\n\t_, host, err := manet.DialArgs(addrAPI)\n\tif err != nil {\n\t\treturn errors.New(\"invalid bucket daemon host provided: \" + err.Error())\n\t}\n\n\tlog.Debug(\"Creating buckets client in \" + host)\n\tif b, err := bucketsClient.NewClient(host, opts...); err != nil {\n\t\tcmd.Fatal(err)\n\t} else {\n\t\tbuckets = b\n\t}\n\n\tlog.Debug(\"Creating threads client in \" + host)\n\tif t, err := threadsClient.NewClient(host, opts...); err != nil {\n\t\tcmd.Fatal(err)\n\t} else {\n\t\tthreads = t\n\t}\n\n\tif n, err := nc.NewClient(host, opts...); err != nil {\n\t\tcmd.Fatal(err)\n\t} else {\n\t\tnetc = n\n\t}\n\n\tipfsNodeAddr := cfg.GetString(config.Ipfsnodeaddr, \"/ip4/127.0.0.1/tcp/5001\")\n\tif ipfsNodeAddr == \"\" {\n\t\tipfsNodeAddr = \"/ip4/127.0.0.1/tcp/5001\"\n\t}\n\n\tmultiAddr, err := ma.NewMultiaddr(ipfsNodeAddr)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\tif ic, err := httpapi.NewApi(multiAddr); err != nil {\n\t\tcmd.Fatal(err)\n\t} else {\n\t\ttc.ipfsClient = ic\n\t}\n\n\ttc.bucketsClient = buckets\n\ttc.threads = threads\n\ttc.netc = netc\n\ttc.ht = getHubThreadsClient(tc.cfg.GetString(config.TextileHubTarget, \"\"))\n\ttc.hb = getHubBucketClient(tc.cfg.GetString(config.TextileHubTarget, \"\"))\n\ttc.hnetc = getHubNetworkClient(tc.cfg.GetString(config.TextileHubTarget, \"\"))\n\n\ttc.isRunning = true\n\n\ttc.healthcheck(ctx)\n\n\ttc.Ready <- true\n\n\t// Repeating healthcheck\n\tfor {\n\t\ttimeAfterNextCheck := 60 * time.Second\n\t\t// Do more frequent checks if the client is not initialized/running\n\t\tif tc.isConnectedToHub == false || tc.isInitialized == false {\n\t\t\ttimeAfterNextCheck = 3 * time.Second\n\t\t}\n\n\t\t// If it's trying to shutdown we return right away\n\t\tif tc.isRunning == false {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-time.After(timeAfterNextCheck):\n\t\t\ttc.healthcheck(ctx)\n\n\t\t// If we get notified that the keypair got deleted, start checking right away\n\t\tcase <-tc.keypairDeleted:\n\t\t\ttc.healthcheck(ctx)\n\n\t\t// If it's trying to shutdown we return right away\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-tc.shuttingDown:\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (tc *textileClient) checkHubConnection(ctx context.Context) error {\n\t// Get the public key to see if we have any\n\t// Reject right away if not\n\t_, err := tc.kc.GetStoredPublicKey()\n\tif err != nil {\n\t\ttc.isConnectedToHub = false\n\t\treturn err\n\t}\n\n\t// Attempt to connect to the Hub\n\thubctx, err := tc.getHubCtx(ctx)\n\tif err != nil {\n\t\ttc.isConnectedToHub = false\n\t\tlog.Error(\"Could not connect to Textile Hub. Starting in offline mode.\", err)\n\t\treturn err\n\t}\n\n\tif tc.isConnectedToHub == false {\n\t\t// setup mailbox\n\t\tmailbox, err := tc.setupOrCreateMailBox(hubctx)\n\t\tif err != nil {\n\t\t\tlog.Error(\"Unable to setup mailbox\", err)\n\t\t\ttc.isConnectedToHub = false\n\t\t\treturn err\n\t\t}\n\t\ttc.mb = mailbox\n\n\t\tif err := tc.listenForMessages(hubctx); err != nil {\n\t\t\ttc.isConnectedToHub = false\n\t\t\tlog.Error(\"Could not listen for mailbox messages\", err)\n\t\t\treturn err\n\t\t}\n\t}\n\n\ttc.isConnectedToHub = true\n\n\treturn nil\n}\n\nfunc getHubTargetOpts(host string) []grpc.DialOption {\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\n\tif strings.Contains(host, \"443\") {\n\t\tcreds := credentials.NewTLS(&tls.Config{})\n\t\topts = append(opts, grpc.WithTransportCredentials(creds))\n\t\tauth.Secure = true\n\t} else {\n\t\topts = append(opts, grpc.WithInsecure())\n\t}\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\treturn opts\n}\n\nfunc CreateUserClient(host string) UsersClient {\n\topts := getHubTargetOpts(host)\n\n\tusers, err := uc.NewClient(host, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\treturn users\n}\n\nfunc getHubThreadsClient(host string) *threadsClient.Client {\n\topts := getHubTargetOpts(host)\n\n\ttc, err := threadsClient.NewClient(host, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\treturn tc\n}\n\nfunc getHubNetworkClient(host string) *nc.Client {\n\topts := getHubTargetOpts(host)\n\n\tn, err := nc.NewClient(host, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\treturn n\n}\n\nfunc getHubBucketClient(host string) *bucketsClient.Client {\n\topts := getHubTargetOpts(host)\n\n\ttc, err := bucketsClient.NewClient(host, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\treturn tc\n}\n\nfunc (tc *textileClient) initialize(ctx context.Context) error {\n\terr := tc.restoreBuckets(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbuckets, err := tc.listBuckets(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpub, _ := tc.kc.GetStoredPublicKey()\n\tif pub != nil {\n\t\taddress := address.DeriveAddress(pub)\n\t\tlog.Debug(\"Initializing Textile client\", fmt.Sprintf(\"address:%s\", address))\n\t}\n\n\t// Create default bucket if it doesnt exist\n\tdefaultBucketExists := false\n\tfor _, b := range buckets {\n\t\tif b.Slug() == defaultPersonalBucketSlug {\n\t\t\tdefaultBucketExists = true\n\t\t}\n\t}\n\tif defaultBucketExists == false {\n\t\t_, err := tc.createBucket(ctx, defaultPersonalBucketSlug)\n\t\tif err != nil {\n\t\t\tlog.Error(\"Error creating default bucket\", err)\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err = tc.initSearchIndex(ctx); err != nil {\n\t\tlog.Error(\"Error initializing files search index\", err)\n\t\treturn err\n\t}\n\n\tif tc.sync != nil {\n\t\ttc.sync.NotifyBucketStartup(defaultPersonalBucketSlug)\n\t}\n\n\t_, err = tc.createDefaultPublicBucket(ctx)\n\tif err != nil {\n\t\tlog.Warn(\"Failed to create default public bucket\", \"err:\"+err.Error())\n\t}\n\n\ttc.isInitialized = true\n\t// Non-blocking channel send in case there are no listeners registered\n\tselect {\n\tcase tc.onInitialized <- true:\n\t\tlog.Debug(\"Notifying Textile Client init ready\")\n\tdefault:\n\t\t// Do nothing\n\t}\n\tlog.Debug(\"Textile Client initialized successfully\")\n\treturn nil\n}\n\n// Starts a Textile Client and also initializes default resources for it (default bucket and metathread).\n// Then leaves the process running to attempt to connect or to initialize if it's not already initialized\nfunc (tc *textileClient) Start(ctx context.Context, cfg config.Config) error {\n\t// Start Textile Client\n\treturn tc.start(ctx, cfg)\n}\n\n// Used by delete account so we can disable it so it gets\n// enabled again during startup\nfunc (tc *textileClient) DisableSync() {\n\ttc.isSyncInitialized = false\n}\n\n// Closes connection to Textile\nfunc (tc *textileClient) Shutdown() error {\n\ttc.shuttingDown <- true\n\ttc.isRunning = false\n\ttc.isInitialized = false\n\ttc.isSyncInitialized = false\n\ttc.shouldForceRestore = false\n\n\t// Close channels\n\tclose(tc.mailEvents)\n\tclose(tc.Ready)\n\tclose(tc.onHealthy)\n\tclose(tc.keypairDeleted)\n\tclose(tc.shuttingDown)\n\n\ttc.closeListeners()\n\n\tif err := tc.bucketsClient.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := tc.threads.Close(); err != nil {\n\t\treturn err\n\t}\n\n\ttc.sync.Shutdown()\n\n\ttc.bucketsClient = nil\n\ttc.threads = nil\n\n\treturn nil\n}\n\n// Returns a thread client connection. Requires the client to be running.\nfunc (tc *textileClient) GetThreadsConnection() (*threadsClient.Client, error) {\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.threads, nil\n}\n\nfunc (tc *textileClient) IsRunning() bool {\n\treturn tc.isRunning\n}\n\nfunc (tc *textileClient) GetFailedHealthchecks() int {\n\treturn tc.failedHealthchecks\n}\n\n// Checks for connection and initialization needs.\nfunc (tc *textileClient) healthcheck(ctx context.Context) {\n\ttc.healthcheckMutex.Lock()\n\tdefer tc.healthcheckMutex.Unlock()\n\n\tlog.Debug(\"Textile Client healthcheck... Start.\")\n\n\tif tc.isSyncInitialized == false {\n\t\ttc.initializeSync(ctx)\n\t}\n\n\tif tc.isInitialized == false {\n\t\t// NOTE: Initialize does not need a hub connection as remote syncing is done in a background process\n\t\ttc.initialize(ctx)\n\t}\n\n\ttc.checkHubConnection(ctx)\n\n\tif len(tc.dbListeners) == 0 {\n\t\ttc.initializeListeners(ctx)\n\t}\n\n\tswitch {\n\tcase tc.isInitialized == false:\n\t\tlog.Debug(\"Textile Client healthcheck... Not initialized yet.\")\n\t\ttc.failedHealthchecks = tc.failedHealthchecks + 1\n\tcase tc.isConnectedToHub == false:\n\t\tlog.Debug(\"Textile Client healthcheck... Not connected to hub.\")\n\t\ttc.failedHealthchecks = tc.failedHealthchecks + 1\n\tdefault:\n\t\tlog.Debug(\"Textile Client healthcheck... OK.\")\n\t\ttc.failedHealthchecks = 0\n\t\t// Non-blocking channel send in case there are no listeners registered\n\t\tselect {\n\t\tcase tc.onHealthy <- nil:\n\t\t\tlog.Debug(\"Notifying health OK\")\n\t\tdefault:\n\t\t\t// Do nothing\n\t\t}\n\t}\n\n\tif tc.failedHealthchecks >= 3 {\n\t\t// Non-blocking channel send in case there are no listeners registered\n\t\tselect {\n\t\tcase tc.onHealthy <- HealthcheckMaxRetriesReachedErr:\n\t\t\tlog.Debug(\"Notifying healthcheck: max attempts surpassed\")\n\t\t\ttc.failedHealthchecks = 0\n\t\tdefault:\n\t\t\t// Do nothing\n\t\t}\n\t}\n}\n\nfunc (tc *textileClient) RemoveKeys(ctx context.Context) error {\n\tif err := tc.hubAuth.ClearCache(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := tc.clearLocalMailbox(); err != nil {\n\t\treturn err\n\t}\n\n\ttc.isInitialized = false\n\ttc.isConnectedToHub = false\n\ttc.keypairDeleted <- true\n\n\tmetathreadID, err := utils.NewDeterministicThreadID(tc.kc, utils.MetathreadThreadVariant)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = tc.threads.DeleteDB(ctx, metathreadID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (tc *textileClient) GetModel() model.Model {\n\treturn model.New(\n\t\ttc.store,\n\t\ttc.kc,\n\t\ttc.threads,\n\t\ttc.ht,\n\t\ttc.hubAuth,\n\t\ttc.cfg,\n\t\ttc.netc,\n\t\ttc.hnetc,\n\t\ttc.shouldForceRestore,\n\t\ttc.filesSearchEngine,\n\t)\n}\n\nfunc (tc *textileClient) getSecureBucketsClient(baseClient *bucketsClient.Client) *SecureBucketClient {\n\tisRemote := baseClient == tc.hb\n\treturn NewSecureBucketsClient(baseClient, tc.kc, tc.store, tc.threads, tc.ipfsClient, isRemote, tc.cfg)\n}\n\nfunc (tc *textileClient) requiresHubConnection() error {\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn err\n\t}\n\n\tif tc.isConnectedToHub == false || tc.mb == nil {\n\t\treturn errors.New(\"ran an operation that requires connection to hub\")\n\t}\n\treturn nil\n}\n\nfunc (tc *textileClient) AttachSynchronizerNotifier(notif synchronizer.EventNotifier) {\n\ttc.sync.AttachNotifier(notif)\n}\n\n// Initializes dbs from a backup. Returns error if it can't initialize\nfunc (tc *textileClient) RestoreDB(ctx context.Context) error {\n\ttc.healthcheckMutex.Lock()\n\tdefer tc.healthcheckMutex.Unlock()\n\n\ttc.shouldForceRestore = true\n\terr := tc.initialize(ctx)\n\ttc.shouldForceRestore = false\n\tif err != nil {\n\t\ttc.kc.DeleteKeypair()\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "core/textile/common/common.go",
    "content": "package common\n\nimport \"context\"\n\n// NewBucketEncryptionKeyContext adds the encryption key to the context\n// which is used to encrypt and decrypt requests to buckets client.\nfunc NewBucketEncryptionKeyContext(ctx context.Context, key []byte) context.Context {\n\tif key == nil || len(key) == 0 {\n\t\treturn ctx\n\t}\n\treturn context.WithValue(ctx, \"bucketEncryptionKey\", key)\n}\n\n// BucketEncryptionKeyFromContext returns the bucket encryption key from a context.\nfunc BucketEncryptionKeyFromContext(ctx context.Context) ([]byte, bool) {\n\tkey, ok := ctx.Value(\"bucketEncryptionKey\").([]byte)\n\treturn key, ok\n}\n"
  },
  {
    "path": "core/textile/event_handler.go",
    "content": "package textile\n\nimport (\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tiface \"github.com/ipfs/interface-go-ipfs-core\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n)\n\n// EventHandler\ntype EventHandler interface {\n\tOnCreate(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent)\n\tOnRemove(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent)\n\tOnSave(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent)\n}\n\n// Implements EventHandler and defaults to logging actions performed\ntype defaultListenerHandler struct{}\n\nfunc (h *defaultListenerHandler) OnCreate(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Info(\"Default Listener Handler: OnCreate\")\n}\n\nfunc (h *defaultListenerHandler) OnRemove(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Info(\"Default Listener Handler: OnRemove\")\n}\n\nfunc (h *defaultListenerHandler) OnSave(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Info(\"Default Listener Handler: OnSave\")\n}\n\ntype restorerListenerHandler struct {\n\tsynchronizer sync.Synchronizer\n\tst           store.Store\n\tipfsClient   iface.CoreAPI\n}\n\nfunc newRestorerListenerHandler(synchronizer sync.Synchronizer, st store.Store, ipfsClient iface.CoreAPI) *restorerListenerHandler {\n\treturn &restorerListenerHandler{\n\t\tsynchronizer: synchronizer,\n\t\tst:           st,\n\t\tipfsClient:   ipfsClient,\n\t}\n}\n\nfunc (h *restorerListenerHandler) OnCreate(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Debug(\"Restorer Listener Handler: OnCreate\")\n\th.synchronizer.NotifyBucketRestore(bucketData.Name)\n}\n\nfunc (h *restorerListenerHandler) OnRemove(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Debug(\"Restorer Listener Handler: OnRemove\")\n\th.synchronizer.NotifyBucketRestore(bucketData.Name)\n}\n\nfunc (h *restorerListenerHandler) OnSave(bucketData *bucket.BucketData, listenEvent *tc.ListenEvent) {\n\tlog.Debug(\"Restorer Listener Handler: OnSave\")\n\th.synchronizer.NotifyBucketRestore(bucketData.Name)\n}\n"
  },
  {
    "path": "core/textile/hub/hmacTestKey",
    "content": "\u0003#5K+\u000f~\u0006ew{Z(T(\u000fP.Z\u0006Gwb=\"=.!r\u0005.O\b͚gЀ"
  },
  {
    "path": "core/textile/hub/hub_auth.go",
    "content": "package hub\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\tb64 \"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/dgrijalva/jwt-go\"\n\tmbase \"github.com/multiformats/go-multibase\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\t\"golang.org/x/net/websocket\"\n)\n\ntype sentMessageData struct {\n\tSignature string `json:\"sig\"`\n\tPublicKey string `json:\"pubkey\"`\n}\n\ntype outMessage struct {\n\tAction string          `json:\"action\"`\n\tData   sentMessageData `json:\"data\"`\n}\n\ntype inMessageChallengeValue struct {\n\tType string `json:\"type\"`\n\tData []byte `json:\"data\"`\n}\n\ntype inMessageChallenge struct {\n\tType  string                  `json:\"type\"`\n\tValue inMessageChallengeValue `json:\"value\"`\n}\n\ntype inMessageTokenValue struct {\n\tToken    string `json:\"token\"`\n\tKey      string `json:\"key\"`\n\tMsg      string `json:\"msg\"`\n\tSig      string `json:\"sig\"`\n\tAppToken string `json:\"appToken\"`\n}\n\ntype inMessageToken struct {\n\tType  string              `json:\"type\"`\n\tValue inMessageTokenValue `json:\"value\"`\n}\n\ntype AuthTokens struct {\n\tHubToken string\n\tKey      string\n\tSig      string\n\tAppToken string\n\tMsg      string\n}\n\ntype HubAuth interface {\n\tGetTokensWithCache(ctx context.Context) (*AuthTokens, error)\n\tGetHubContext(ctx context.Context) (context.Context, error)\n\tClearCache() error\n}\n\ntype hub struct {\n\tst               store.Store\n\tkc               keychain.Keychain\n\tcfg              config.Config\n\tfetchTokensMutex *sync.Mutex\n}\n\nfunc New(st store.Store, kc keychain.Keychain, cfg config.Config) *hub {\n\treturn &hub{\n\t\tst:               st,\n\t\tkc:               kc,\n\t\tcfg:              cfg,\n\t\tfetchTokensMutex: &sync.Mutex{},\n\t}\n}\n\nconst tokensStoreKey = \"hubTokens\"\n\nfunc isTokenExpired(t string) bool {\n\ttoken, _, err := new(jwt.Parser).ParseUnverified(t, jwt.MapClaims{})\n\tif err != nil {\n\t\treturn true\n\t}\n\n\tclaims, ok := token.Claims.(jwt.MapClaims)\n\tif !ok {\n\t\treturn true\n\t}\n\n\tvar expiryTime time.Time\n\tswitch exp := claims[\"exp\"].(type) {\n\tcase float64:\n\t\texpiryTime = time.Unix(int64(exp), 0)\n\tcase json.Number:\n\t\tv, err := exp.Int64()\n\t\tif err != nil {\n\t\t\treturn true\n\t\t}\n\t\texpiryTime = time.Unix(v, 0)\n\t}\n\n\tnow := time.Now()\n\n\treturn expiryTime.Before(now)\n}\n\nfunc (h *hub) retrieveTokens() (*inMessageTokenValue, error) {\n\tstored, err := h.st.Get([]byte(tokensStoreKey))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttokens := &inMessageTokenValue{}\n\ttokensBytes := bytes.NewBuffer(stored)\n\n\tif err := json.NewDecoder(tokensBytes).Decode(tokens); err != nil {\n\t\treturn nil, err\n\t}\n\n\texpired := isTokenExpired(tokens.AppToken)\n\tif expired {\n\t\treturn nil, errors.New(\"App token is expired\")\n\t}\n\n\treturn tokens, nil\n}\n\nfunc (h *hub) storeTokens(tokens *inMessageTokenValue) error {\n\ttokensBytes := new(bytes.Buffer)\n\tif err := json.NewEncoder(tokensBytes).Encode(tokens); err != nil {\n\t\treturn err\n\t}\n\n\tif err := h.st.Set([]byte(tokensStoreKey), tokensBytes.Bytes()); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Removes the stored tokens\nfunc (h *hub) ClearCache() error {\n\treturn h.st.Remove([]byte(tokensStoreKey))\n}\n\nfunc (h *hub) getTokensThroughChallenge(ctx context.Context) (*inMessageTokenValue, error) {\n\tlog.Debug(\"Token Challenge: Connecting through websocket\")\n\tconn, err := websocket.Dial(h.cfg.GetString(config.SpaceServicesHubAuthURL, \"\"), \"\", \"http://localhost/\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\tlog.Debug(\"Token Challenge: Connected\")\n\n\tprivateKey, _, err := h.kc.GetStoredKeyPairInLibP2PFormat()\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tidentity := thread.NewLibp2pIdentity(privateKey)\n\tpub := identity.GetPublic().String()\n\n\t// Request a challenge (a payload we need to sign)\n\tlog.Debug(\"Token Challenge: Sending token request with pub key\" + pub)\n\ttokenRequest := &outMessage{\n\t\tAction: \"token\",\n\t\tData: sentMessageData{\n\t\t\tPublicKey: identity.GetPublic().String(),\n\t\t},\n\t}\n\terr = websocket.JSON.Send(conn, tokenRequest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tchallenge := inMessageChallenge{}\n\tif err := websocket.JSON.Receive(conn, &challenge); err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debug(\"Token Challenge: Received challenge\")\n\n\tsolution, err := identity.Sign(ctx, challenge.Value.Data)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsignature := b64.StdEncoding.EncodeToString(solution)\n\n\t// Send back channel solution\n\tsolMessage := &outMessage{\n\t\tAction: \"challenge\",\n\t\tData: sentMessageData{\n\t\t\tSignature: signature,\n\t\t\tPublicKey: pub,\n\t\t},\n\t}\n\tlog.Debug(\"Token Challenge: Sending signature\")\n\terr = websocket.JSON.Send(conn, solMessage)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Receive the token\n\tvar token inMessageToken\n\tfor token.Type != \"token\" {\n\t\tcurrToken := inMessageToken{}\n\t\tif err := websocket.JSON.Receive(conn, &token); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif currToken.Type == \"token\" {\n\t\t\ttoken = currToken\n\t\t}\n\t}\n\tif token.Type == \"token\" {\n\t\tlog.Debug(\"Token Challenge: Received token successfully\")\n\t\treturn &token.Value, nil\n\t}\n\n\treturn nil, errors.New(\"Did not receive a correct token challenge response\")\n}\n\nfunc (h *hub) GetTokensWithCache(ctx context.Context) (*AuthTokens, error) {\n\th.fetchTokensMutex.Lock()\n\tdefer h.fetchTokensMutex.Unlock()\n\tif tokensInStore, _ := h.retrieveTokens(); tokensInStore != nil {\n\t\treturn &AuthTokens{\n\t\t\tHubToken: tokensInStore.Token,\n\t\t\tAppToken: tokensInStore.AppToken,\n\t\t\tKey:      tokensInStore.Key,\n\t\t\tSig:      tokensInStore.Sig,\n\t\t\tMsg:      tokensInStore.Msg,\n\t\t}, nil\n\t}\n\n\ttokens, err := h.getTokensThroughChallenge(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := h.storeTokens(tokens); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &AuthTokens{\n\t\tHubToken: tokens.Token,\n\t\tAppToken: tokens.AppToken,\n\t\tKey:      tokens.Key,\n\t\tSig:      tokens.Sig,\n\t\tMsg:      tokens.Msg,\n\t}, nil\n}\n\nfunc (h *hub) GetHubContext(ctx context.Context) (context.Context, error) {\n\ttokens, err := h.GetTokensWithCache(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, sig, err := mbase.Decode(tokens.Sig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tctx = common.NewAPIKeyContext(ctx, tokens.Key)\n\tctx = common.NewAPISigContext(ctx, tokens.Msg, sig)\n\n\ttok := thread.Token(tokens.HubToken)\n\tctx = thread.NewTokenContext(ctx, tok)\n\n\treturn ctx, nil\n}\n"
  },
  {
    "path": "core/textile/hub/hub_auth_test.go",
    "content": "package hub\n\nimport (\n\t\"io/ioutil\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/dgrijalva/jwt-go\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar hmacTestKey, _ = ioutil.ReadFile(\"hmacTestKey\")\n\nfunc TestHubAuth_isTokenExpiredTrue(t *testing.T) {\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{\n\t\t\"exp\": time.Now().AddDate(0, 0, -1).Unix(),\n\t\t\"iat\": time.Now().Unix(),\n\t})\n\n\ttokenStr, _ := token.SignedString(hmacTestKey)\n\n\texp := isTokenExpired(tokenStr)\n\tassert.Equal(t, true, exp)\n}\n\nfunc TestHubAuth_isTokenExpiredFalse(t *testing.T) {\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{\n\t\t\"exp\": time.Now().AddDate(0, 0, 1).Unix(),\n\t\t\"iat\": time.Now().Unix(),\n\t})\n\n\ttokenStr, _ := token.SignedString(hmacTestKey)\n\n\texp := isTokenExpired(tokenStr)\n\tassert.Equal(t, false, exp)\n}\n"
  },
  {
    "path": "core/textile/listener.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/textileio/go-threads/api/client\"\n\tthreadsClient \"github.com/textileio/go-threads/api/client\"\n)\n\nfunc (tc *textileClient) Listen(ctx context.Context, dbID, threadName string) (<-chan threadsClient.ListenEvent, error) {\n\tdb, err := utils.ParseDbIDFromString(dbID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewCtx, err := utils.GetThreadContext(ctx, \"\", *db, true, tc.kc, tc.hubAuth, tc.ht)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.ht.Listen(newCtx, *db, nil)\n}\n\nfunc (tc *textileClient) addListener(ctx context.Context, bucketSlug string) error {\n\tif err := tc.requiresHubConnection(); err != nil {\n\t\treturn err\n\t}\n\thandler := newRestorerListenerHandler(tc.sync, tc.store, tc.ipfsClient)\n\thandlers := []EventHandler{handler}\n\tlistener := NewListener(tc, bucketSlug, handlers)\n\ttc.dbListeners[bucketSlug] = listener\n\n\tgo func() {\n\t\terr := listener.Listen(ctx)\n\t\tif err != nil {\n\t\t\t// Remove element from map as it's not listening anymore\n\t\t\tdelete(tc.dbListeners, bucketSlug)\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (tc *textileClient) DeleteListeners(ctx context.Context) {\n\tfor k, _ := range tc.dbListeners {\n\t\tdelete(tc.dbListeners, k)\n\t}\n}\n\nfunc (tc *textileClient) initializeListeners(ctx context.Context) error {\n\tif err := tc.requiresHubConnection(); err != nil {\n\t\treturn err\n\t}\n\n\ttc.closeListeners()\n\n\tbuckets, err := tc.listBuckets(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, bucket := range buckets {\n\t\ttc.addListener(ctx, bucket.Slug())\n\t}\n\n\treturn nil\n}\n\nfunc (tc *textileClient) closeListeners() {\n\tfor key, listener := range tc.dbListeners {\n\t\tlistener.Close()\n\t\tdelete(tc.dbListeners, key)\n\t}\n\n}\n\ntype listener struct {\n\tclient     Client\n\tbucketSlug string\n\thandlers   []EventHandler\n\tshutdown   chan bool\n\tisRunning  bool\n}\n\nfunc NewListener(client Client, bucketSlug string, handlers []EventHandler) *listener {\n\treturn &listener{\n\t\tclient:     client,\n\t\tbucketSlug: bucketSlug,\n\t\thandlers:   handlers,\n\t\tshutdown:   make(chan bool),\n\t\tisRunning:  false,\n\t}\n}\n\nfunc (l *listener) Listen(ctx context.Context) error {\n\tbucketSchema, err := l.client.GetModel().FindBucket(ctx, l.bucketSlug)\n\tif bucketSchema == nil || bucketSchema.RemoteDbID == \"\" {\n\t\treturn errors.New(\"Bucket does not have a linked mirror bucket\")\n\t}\n\n\tbucket, err := l.client.GetBucket(ctx, l.bucketSlug, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tbucketData := bucket.GetData()\n\n\teventChan, err := l.client.Listen(ctx, bucketSchema.RemoteDbID, bucketSchema.RemoteBucketSlug)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tl.isRunning = true\n\tdefer func() {\n\t\tl.isRunning = false\n\t}()\n\nLoop:\n\tfor {\n\t\tselect {\n\t\tcase ev := <-eventChan:\n\t\t\tif ev.Err != nil {\n\t\t\t\treturn ev.Err\n\t\t\t}\n\n\t\t\tif !l.client.IsRunning() {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tfor _, handler := range l.handlers {\n\t\t\t\tswitch ev.Action.Type {\n\t\t\t\tcase client.ActionCreate:\n\t\t\t\t\thandler.OnCreate(&bucketData, &ev)\n\t\t\t\tcase client.ActionSave:\n\t\t\t\t\thandler.OnSave(&bucketData, &ev)\n\t\t\t\tcase client.ActionDelete:\n\t\t\t\t\thandler.OnRemove(&bucketData, &ev)\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-l.shutdown:\n\t\t\tbreak Loop\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *listener) Close() {\n\tif !l.isRunning {\n\t\treturn\n\t}\n\tl.shutdown <- true\n}\n"
  },
  {
    "path": "core/textile/mailbox.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"os\"\n\t\"os/user\"\n\t\"path/filepath\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tcrypto \"github.com/libp2p/go-libp2p-crypto\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/textile/v2/api/usersd/client\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\tmail \"github.com/textileio/textile/v2/mail/local\"\n)\n\ntype GrpcMailboxNotifier interface {\n\tSendNotificationEvent(notif *domain.Notification)\n}\n\nconst mailboxSetupFlagStoreKey = \"mailboxSetupFlag\"\n\ntype UsersClient interface {\n\tListInboxMessages(ctx context.Context, opts ...client.ListOption) ([]client.Message, error)\n\tSendMessage(ctx context.Context, from thread.Identity, to thread.PubKey, body []byte) (msg client.Message, err error)\n\tSetupMailbox(ctx context.Context) (mailbox thread.ID, err error)\n}\n\ntype Mailbox interface {\n\tListInboxMessages(ctx context.Context, opts ...client.ListOption) ([]client.Message, error)\n\tSendMessage(ctx context.Context, to thread.PubKey, body []byte) (msg client.Message, err error)\n\tWatchInbox(ctx context.Context, mevents chan<- mail.MailboxEvent, offline bool) (<-chan cmd.WatchState, error)\n\tIdentity() thread.Identity\n}\n\nfunc (tc *textileClient) parseMessage(ctx context.Context, msgs []client.Message) ([]*domain.Notification, error) {\n\tns := make([]*domain.Notification, 0)\n\n\tids := []string{}\n\tfor _, n := range msgs {\n\t\tids = append(ids, n.ID)\n\t}\n\n\tfileschemas, err := tc.GetModel().FindReceivedFilesByIds(ctx, ids)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// make map so we dont have to iterate each time\n\tfsmap := make(map[string]*model.ReceivedFileSchema)\n\tfor _, fs := range fileschemas {\n\t\tfsmap[fs.InvitationId] = fs\n\t}\n\n\tfor _, msg := range msgs {\n\t\tp, err := msg.Open(ctx, tc.mb.Identity())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tb := &domain.MessageBody{}\n\t\terr = json.Unmarshal(p, b)\n\n\t\tif err != nil {\n\t\t\tlog.Error(\"Error parsing message into MessageBody type\", err)\n\n\t\t\t// returning generic notification since body was not able to be parsed\n\t\t\tn := &domain.Notification{\n\t\t\t\tID:        msg.ID,\n\t\t\t\tBody:      string(p),\n\t\t\t\tCreatedAt: msg.CreatedAt.Unix(),\n\t\t\t\tReadAt:    msg.ReadAt.Unix(),\n\t\t\t}\n\n\t\t\tns = append(ns, n)\n\t\t\tcontinue\n\t\t}\n\n\t\tn := &domain.Notification{\n\t\t\tID:               msg.ID,\n\t\t\tBody:             string(p),\n\t\t\tNotificationType: (*b).Type,\n\t\t\tCreatedAt:        msg.CreatedAt.Unix(),\n\t\t\tReadAt:           msg.ReadAt.Unix(),\n\t\t}\n\n\t\tswitch (*b).Type {\n\t\tcase domain.INVITATION:\n\t\t\ti := &domain.Invitation{}\n\t\t\terr := json.Unmarshal((*b).Body, i)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif fsmap[msg.ID] == nil {\n\t\t\t\ti.Status = domain.PENDING\n\t\t\t} else {\n\t\t\t\tif fsmap[msg.ID].Accepted {\n\t\t\t\t\ti.Status = domain.ACCEPTED\n\t\t\t\t} else {\n\t\t\t\t\ti.Status = domain.REJECTED\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti.InvitationID = msg.ID\n\t\t\tn.InvitationValue = *i\n\t\t\tn.RelatedObject = *i\n\t\tcase domain.USAGEALERT:\n\t\t\tu := &domain.UsageAlert{}\n\t\t\terr := json.Unmarshal((*b).Body, u)\n\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tn.UsageAlertValue = *u\n\t\t\tn.RelatedObject = *u\n\t\tcase domain.REVOKED_INVITATION:\n\t\t\tinvite := domain.RevokedInvitation{}\n\t\t\tif err := json.Unmarshal((*b).Body, &invite); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\t// NOTE: current, this would run every time this notification is fetched\n\t\t\t// we can further optimize this later to prevent unnecessary calls, but for now\n\t\t\t// it would run asynchronously.\n\t\t\tgo func() {\n\t\t\t\tif err = tc.GetModel().DeleteReceivedFiles(ctx, invite.ItemPaths, invite.Keys); err != nil {\n\t\t\t\t\tlog.Error(\"Failed to delete revoked files\", err)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tn.RevokedInvitationValue = invite\n\t\t\tn.RelatedObject = invite\n\t\tdefault:\n\t\t}\n\n\t\tns = append(ns, n)\n\t}\n\n\treturn ns, nil\n}\n\nfunc (tc *textileClient) SendMessage(ctx context.Context, recipient crypto.PubKey, body []byte) (*client.Message, error) {\n\tif err := tc.requiresHubConnection(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar err error\n\tctx, err = tc.getHubCtx(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmsg, err := tc.mb.SendMessage(ctx, thread.NewLibp2pPubKey(recipient), body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &msg, nil\n}\n\nfunc (tc *textileClient) GetMailAsNotifications(ctx context.Context, seek string, limit int) ([]*domain.Notification, error) {\n\tif err := tc.requiresHubConnection(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar err error\n\n\tctx, err = tc.getHubCtx(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnotifs, err := tc.mb.ListInboxMessages(ctx, client.WithSeek(seek), client.WithLimit(limit))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tns, err := tc.parseMessage(ctx, notifs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ns, nil\n}\n\ntype handleMessage func(context.Context, interface{}) error\n\nfunc (tc *textileClient) listenForMessages(ctx context.Context) error {\n\tif tc.mbNotifier == nil {\n\t\treturn errors.New(\"no mailbox notifier, run AttachMailboxNotifier first\")\n\t}\n\tlog.Info(\"Starting to listen for mailbox messages\")\n\n\tvar err error\n\tctx, err = tc.getHubCtx(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Handle mailbox events as they arrive\n\tgo func() {\n\t\tfor e := range tc.mailEvents {\n\t\t\tswitch e.Type {\n\t\t\tcase mail.NewMessage:\n\t\t\t\t// handle new message\n\t\t\t\tlog.Info(\"Received mail: \" + e.MessageID.String())\n\n\t\t\t\t// need to fetch the message again because the event\n\t\t\t\t// payload doesn't have the full deets, will remove\n\t\t\t\t// once its fixed on txl end\n\t\t\t\tmsg, err := tc.mb.ListInboxMessages(ctx, client.WithSeek(e.MessageID.String()), client.WithLimit(1))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tp, err := tc.parseMessage(ctx, msg)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Error(\"Unable to parse incoming message: \", err)\n\t\t\t\t}\n\n\t\t\t\ttc.mbNotifier.SendNotificationEvent(p[0])\n\t\t\tcase mail.MessageRead:\n\t\t\t\t// handle message read (inbox only)\n\t\t\tcase mail.MessageDeleted:\n\t\t\t\t// handle message deleted\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Start watching (the third param indicates we want to keep watching when offline)\n\tgo func() {\n\t\tstate, err := tc.mb.WatchInbox(ctx, tc.mailEvents, true)\n\t\tif err != nil {\n\t\t\tlog.Error(\"Unable to watch mailbox, \", err)\n\t\t\treturn\n\t\t}\n\n\t\t// TODO: handle connectivity state if needed\n\t\tfor s := range state {\n\t\t\tlog.Info(\"received inbox watch state: \" + s.State.String())\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// Attachs a handler for mailbox notification events\nfunc (tc *textileClient) AttachMailboxNotifier(notif GrpcMailboxNotifier) {\n\ttc.mbNotifier = notif\n}\n\nfunc (tc *textileClient) createMailBox(ctx context.Context, maillib *mail.Mail, mbpath string) (*mail.Mailbox, error) {\n\t// create\n\tpriv, _, err := tc.kc.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tid := thread.NewLibp2pIdentity(priv)\n\n\tmailbox, err := maillib.NewMailbox(ctx, mail.Config{\n\t\tPath:      mbpath,\n\t\tIdentity:  id,\n\t\tAPIKey:    tc.cfg.GetString(config.TextileUserKey, \"\"),\n\t\tAPISecret: tc.cfg.GetString(config.TextileUserSecret, \"\"),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttc.store.Set([]byte(mailboxSetupFlagStoreKey), []byte(\"true\"))\n\treturn mailbox, nil\n}\n\nfunc (tc *textileClient) getMailboxPath() string {\n\tusr, _ := user.Current()\n\tmbpath := filepath.Join(\n\t\ttc.cfg.GetString(config.SpaceStorePath, filepath.Join(usr.HomeDir, \".fleek-space/textile/mail\")),\n\t\t\"textile\",\n\t\t\"mail\",\n\t)\n\treturn mbpath\n}\n\nfunc (tc *textileClient) setupOrCreateMailBox(ctx context.Context) (*mail.Mailbox, error) {\n\tmaillib := mail.NewMail(cmd.NewClients(tc.cfg.GetString(config.TextileHubTarget, \"\"), true), mail.DefaultConfConfig())\n\n\tmbpath := tc.getMailboxPath()\n\n\tvar mailbox *mail.Mailbox\n\tdbid, err := tc.store.Get([]byte(mailboxSetupFlagStoreKey))\n\tif err == nil && len(dbid) > 0 {\n\t\t// restore\n\t\tmailbox, err = maillib.GetLocalMailbox(ctx, mbpath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tmailbox, err = tc.createMailBox(ctx, maillib, mbpath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tmid := mailbox.Identity()\n\tlog.Info(\"Mailbox identity: \" + mid.GetPublic().String())\n\treturn mailbox, nil\n}\n\nfunc (tc *textileClient) clearLocalMailbox() error {\n\tmbpath := tc.getMailboxPath()\n\treturn os.RemoveAll(mbpath)\n}\n"
  },
  {
    "path": "core/textile/mailbox_test.go",
    "content": "package textile_test\n\nimport (\n\t\"encoding/hex\"\n\t\"testing\"\n\n\ttc \"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\tcrypto \"github.com/libp2p/go-libp2p-crypto\"\n)\n\nvar (\n\tcfg         *mocks.Config\n\tst          *mocks.Store\n\tmockUc      *mocks.UsersClient\n\tmockKc      *mocks.Keychain\n\tmockPubKey  crypto.PubKey\n\tmockPrivKey crypto.PrivKey\n\tmockMb      *mocks.Mailbox\n\tmockHubAuth *mocks.HubAuth\n\tmockSearch  *mocks.FilesSearchEngine\n)\n\ntype TearDown func()\n\nfunc initTestMailbox(t *testing.T) (tc.Client, TearDown) {\n\tst = new(mocks.Store)\n\tmockKc = new(mocks.Keychain)\n\tmockHubAuth = new(mocks.HubAuth)\n\tmockUc = new(mocks.UsersClient)\n\tmockMb = new(mocks.Mailbox)\n\tmockSearch = new(mocks.FilesSearchEngine)\n\tclient := tc.NewClient(st, mockKc, mockHubAuth, mockUc, mockMb, mockSearch)\n\n\tmockPubKeyHex := \"67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"\n\tmockPrivKeyHex := \"dd55f8921f90fdf31c6ef9ad86bd90605602fd7d32dc8ea66ab72deb6a82821c67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"\n\n\tpubKeyBytes, _ := hex.DecodeString(mockPubKeyHex)\n\tprivKeyBytes, _ := hex.DecodeString(mockPrivKeyHex)\n\tmockPubKey, _ = crypto.UnmarshalEd25519PublicKey(pubKeyBytes)\n\tmockPrivKey, _ = crypto.UnmarshalEd25519PrivateKey(privKeyBytes)\n\n\ttearDown := func() {\n\t\tst = nil\n\t\tclient = nil\n\t\tmockUc = nil\n\t\tmockKc = nil\n\t}\n\n\treturn client, tearDown\n}\n\nfunc TestSendMessage(t *testing.T) {\n\t// tc, tearDown := initTestMailbox(t)\n\t// defer tearDown()\n\n\t// assert.NotNil(t, tc)\n\n\t// _, rp, _ := crypto.GenerateEd25519Key(nil)\n\n\t// mockKc.On(\n\t// \t\"GetStoredKeyPairInLibP2PFormat\",\n\t// ).Return(mockPrivKey, mockPubKey, nil)\n\n\t// msg := uc.Message{\n\t// \tID: \"testid\",\n\t// }\n\n\t// mockMb.On(\"SendMessage\", mock.Anything, mock.Anything, mock.Anything).Return(msg, nil)\n\t// mockHubAuth.On(\"GetHubContext\", mock.Anything).Return(context.Background(), nil)\n\t// body := \"mockbody\"\n\t// rmsg, err := tc.SendMessage(context.Background(), rp, []byte(body))\n\n\t// assert.NotNil(t, rmsg)\n\t// assert.Nil(t, err)\n\t// mockMb.AssertCalled(t, \"SendMessage\", context.Background(), thread.NewLibp2pPubKey(rp), []byte(body))\n\t// assert.Equal(t, msg.ID, rmsg.ID)\n}\n\n// func TestSendMessageFailGettingSenderKey(t *testing.T) {\n// \ttc, tearDown := initTestMailbox(t)\n// \tdefer tearDown()\n\n// \tassert.NotNil(t, tc)\n\n// \t_, rp, _ := crypto.GenerateEd25519Key(nil)\n\n// \tmockKc.On(\n// \t\t\"GetStoredKeyPairInLibP2PFormat\",\n// \t).Return(nil, nil, keychain.ErrKeyPairNotFound)\n\n// \tmsg := uc.Message{\n// \t\tID: \"testid\",\n// \t}\n\n// mockHubAuth.On(\"GetHubContext\", mock.Anything).Return(context.Background(), nil)\n// mockMb.On(\"SendMessage\", mock.Anything, mock.Anything, mock.Anything).Return(msg, nil)\n// body := \"mockbody\"\n// rmsg, err := tc.SendMessage(context.Background(), rp, []byte(body))\n\n// \tassert.Nil(t, rmsg)\n// \tassert.NotNil(t, err)\n// \tassert.Equal(t, keychain.ErrKeyPairNotFound, err)\n// \tmockMb.AssertNotCalled(t, \"SendMessage\", mock.Anything, mock.Anything, mock.Anything)\n// }\n\nfunc TestSendMessageFailureOnHub(t *testing.T) {\n\t// tc, tearDown := initTestMailbox(t)\n\t// defer tearDown()\n\n\t// assert.NotNil(t, tc)\n\n\t// _, rp, _ := crypto.GenerateEd25519Key(nil)\n\n\t// errToRet := errors.New(\"failed sending message at the hub\")\n\n\t// mockKc.On(\n\t// \t\"GetStoredKeyPairInLibP2PFormat\",\n\t// ).Return(mockPrivKey, mockPubKey, nil)\n\n\t// msg := uc.Message{}\n\n\t// mockMb.On(\"SendMessage\", mock.Anything, mock.Anything, mock.Anything).Return(msg, errToRet)\n\t// mockHubAuth.On(\"GetHubContext\", mock.Anything).Return(context.Background(), nil)\n\t// body := \"mockbody\"\n\t// rmsg, err := tc.SendMessage(context.Background(), rp, []byte(body))\n\n\t// assert.Nil(t, rmsg)\n\t// assert.NotNil(t, err)\n\t// assert.Equal(t, errToRet, err)\n}\n"
  },
  {
    "path": "core/textile/mirror.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nconst mirrorThreadKeyName = \"mirrorV1\"\n\nfunc (tc *textileClient) IsMirrorFile(ctx context.Context, path, bucketSlug string) bool {\n\tmirrorFile, _ := tc.GetModel().FindMirrorFileByPathAndBucketSlug(ctx, path, bucketSlug)\n\tif mirrorFile != nil {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// set mirror file as backup\n\n// return true if mirror file is a backup\nfunc (tc *textileClient) isMirrorBackupFile(ctx context.Context, path, bucketSlug string) bool {\n\tmf, err := tc.GetModel().FindMirrorFileByPathAndBucketSlug(ctx, path, bucketSlug)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"Error checking if path=%+v bucketSlug=%+v is a mirror backup file\", path, bucketSlug), err)\n\t\treturn false\n\t}\n\tif mf == nil {\n\t\tlog.Warn(fmt.Sprintf(\"mirror file (path=%+v bucketSlug=%+v) does not exist\", path, bucketSlug))\n\t\treturn false\n\t}\n\n\treturn mf.Backup == true\n}\n"
  },
  {
    "path": "core/textile/model/buckets.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/textileio/go-threads/api/client\"\n\tcore \"github.com/textileio/go-threads/core/db\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\t\"github.com/textileio/go-threads/util\"\n)\n\ntype BucketSchema struct {\n\tID            core.InstanceID `json:\"_id\"`\n\tSlug          string          `json:\"slug\"`\n\tBackup        bool            `json:\"backup\"`\n\tEncryptionKey []byte          `json:\"hub_key\"`\n\tDbID          string\n\t*MirrorBucketSchema\n}\n\nconst bucketModelName = \"BucketMetadata\"\n\n// 32 bytes aes key + 16 bytes salt/IV + 32 bytes HMAC key\nconst BucketEncryptionKeyLength = 32 + 16 + 32\n\nvar errBucketNotFound = errors.New(\"Bucket not found\")\n\nfunc (m *model) CreateBucket(ctx context.Context, bucketSlug, dbID string) (*BucketSchema, error) {\n\tlog.Debug(\"Model.CreateBucket: Storing bucket \" + bucketSlug)\n\tif existingBucket, err := m.FindBucket(ctx, bucketSlug); err == nil {\n\t\tlog.Debug(\"Model.CreateBucket: Bucket already in collection\")\n\t\treturn existingBucket, nil\n\t}\n\n\tlog.Debug(\"Model.CreateBucket: Initializing db\")\n\tmetaCtx, metaDbID, err := m.initBucketModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tbucketEncryptionKey, err := utils.RandBytes(BucketEncryptionKeyLength)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to generate bucket encryption key\")\n\t}\n\n\tnewInstance := &BucketSchema{\n\t\tSlug:          bucketSlug,\n\t\tID:            \"\",\n\t\tDbID:          dbID,\n\t\tBackup:        true,\n\t\tEncryptionKey: bucketEncryptionKey,\n\t\tMirrorBucketSchema: &MirrorBucketSchema{\n\t\t\tHubAddr:          \"\",\n\t\t\tRemoteBucketKey:  \"\",\n\t\t\tRemoteDbID:       \"\",\n\t\t\tRemoteBucketSlug: \"\",\n\t\t},\n\t}\n\n\tinstances := client.Instances{newInstance}\n\tlog.Debug(\"Model.CreateBucket: Creating instance\")\n\n\tres, err := m.threads.Create(metaCtx, *metaDbID, bucketModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debug(\"Model.CreateBucket: stored bucket with dbid \" + newInstance.DbID)\n\n\tid := res[0]\n\treturn &BucketSchema{\n\t\tSlug:   newInstance.Slug,\n\t\tID:     core.InstanceID(id),\n\t\tDbID:   newInstance.DbID,\n\t\tBackup: newInstance.Backup,\n\t\tMirrorBucketSchema: &MirrorBucketSchema{\n\t\t\tHubAddr:          newInstance.MirrorBucketSchema.HubAddr,\n\t\t\tRemoteBucketKey:  newInstance.MirrorBucketSchema.RemoteBucketKey,\n\t\t\tRemoteDbID:       newInstance.MirrorBucketSchema.RemoteDbID,\n\t\t\tRemoteBucketSlug: newInstance.MirrorBucketSchema.RemoteBucketSlug,\n\t\t},\n\t}, nil\n}\n\nfunc (m *model) UpsertBucket(ctx context.Context, bucketSlug, dbID string) (*BucketSchema, error) {\n\tmetaCtx, metaDbID, err := m.initBucketModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tif existingBucket, err := m.FindBucket(ctx, bucketSlug); err == nil {\n\t\texistingBucket.DbID = dbID\n\t\tinstances := client.Instances{existingBucket}\n\t\tm.threads.Save(metaCtx, *metaDbID, bucketModelName, instances)\n\t\treturn existingBucket, nil\n\t}\n\n\treturn m.CreateBucket(ctx, bucketSlug, dbID)\n}\n\nfunc (m *model) BucketBackupToggle(ctx context.Context, bucketSlug string, backup bool) (*BucketSchema, error) {\n\tmetaCtx, metaDbID, err := m.initBucketModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tbucket, err := m.FindBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbucket.Backup = backup\n\n\tinstances := client.Instances{bucket}\n\n\terr = m.threads.Save(metaCtx, *metaDbID, bucketModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bucket, nil\n}\n\nfunc (m *model) FindBucket(ctx context.Context, bucketSlug string) (*BucketSchema, error) {\n\tmetaCtx, dbID, err := m.initBucketModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawBuckets, err := m.threads.Find(metaCtx, *dbID, bucketModelName, db.Where(\"slug\").Eq(bucketSlug), &BucketSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawBuckets == nil {\n\t\treturn nil, errBucketNotFound\n\t}\n\n\tbuckets := rawBuckets.([]*BucketSchema)\n\tif len(buckets) == 0 {\n\t\treturn nil, errBucketNotFound\n\t}\n\n\treturn buckets[0], nil\n}\n\nfunc (m *model) ListBuckets(ctx context.Context) ([]*BucketSchema, error) {\n\tmetaCtx, dbID, err := m.initBucketModel(ctx)\n\tif err != nil && dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawBuckets, err := m.threads.Find(metaCtx, *dbID, bucketModelName, &db.Query{}, &BucketSchema{})\n\tif rawBuckets == nil {\n\t\treturn []*BucketSchema{}, nil\n\t}\n\tbuckets := rawBuckets.([]*BucketSchema)\n\treturn buckets, nil\n}\n\nfunc (m *model) initBucketModel(ctx context.Context) (context.Context, *thread.ID, error) {\n\tmetaCtx, dbID, err := m.getMetaThreadContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tm.threads.NewCollection(metaCtx, *dbID, GetBucketCollectionConfig())\n\n\treturn metaCtx, dbID, nil\n}\n\nfunc GetBucketCollectionConfig() db.CollectionConfig {\n\treturn db.CollectionConfig{\n\t\tName:   bucketModelName,\n\t\tSchema: util.SchemaFromInstance(&BucketSchema{}, false),\n\t\tIndexes: []db.Index{{\n\t\t\tPath:   \"slug\",\n\t\t\tUnique: true,\n\t\t}},\n\t}\n}\n"
  },
  {
    "path": "core/textile/model/mirror_file.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/go-threads/api/client\"\n\tcore \"github.com/textileio/go-threads/core/db\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\t\"github.com/textileio/go-threads/util\"\n)\n\ntype MirrorFileSchema struct {\n\tID                core.InstanceID `json:\"_id\"`\n\tPath              string          `json:\"path\"`\n\tBucketSlug        string          `json:\"bucket_slug\"`\n\tBackup            bool            `json:\"backup\"`\n\tShared            bool            `json:\"shared\"`\n\tBackupInProgress  bool            `json:\"backupInProgress\"`\n\tRestoreInProgress bool            `json:\"restoreInProgress\"`\n\tDbID              string\n}\n\ntype MirrorBucketSchema struct {\n\tRemoteDbID       string `json:\"remoteDbId\"`\n\tRemoteBucketKey  string `json:\"remoteBucketKey\"`\n\tHubAddr          string `json:\"HubAddr\"`\n\tRemoteBucketSlug string `json:\"remoteBucketSlug\"`\n}\n\nconst mirrorFileModelName = \"MirrorFile\"\n\nvar errMirrorFileNotFound = errors.New(\"Mirror file not found\")\nvar errMirrorFileAlreadyExists = errors.New(\"Mirror file already exists\")\n\nfunc (m *model) CreateMirrorBucket(ctx context.Context, bucketSlug string, mirrorBucket *MirrorBucketSchema) (*BucketSchema, error) {\n\tmetaCtx, metaDbID, err := m.initBucketModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tbucket, err := m.FindBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbucket.RemoteDbID = mirrorBucket.RemoteDbID\n\tbucket.HubAddr = mirrorBucket.HubAddr\n\tbucket.RemoteBucketKey = mirrorBucket.RemoteBucketKey\n\tbucket.RemoteBucketSlug = mirrorBucket.RemoteBucketSlug\n\n\tinstances := client.Instances{bucket}\n\n\terr = m.threads.Save(metaCtx, *metaDbID, bucketModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bucket, nil\n}\n\nfunc (m *model) FindMirrorFileByPaths(ctx context.Context, paths []string) (map[string]*MirrorFileSchema, error) {\n\tmetaCtx, dbID, err := m.initMirrorFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\tvar qry *db.Query\n\tfor i, path := range paths {\n\t\tif i == 0 {\n\t\t\tqry = db.Where(\"path\").Eq(filepath.Clean(path))\n\t\t} else {\n\t\t\tqry = qry.Or(db.Where(\"path\").Eq(filepath.Clean(path)))\n\t\t}\n\t}\n\n\trawMirrorFiles, err := m.threads.Find(metaCtx, *dbID, mirrorFileModelName, qry, &MirrorFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawMirrorFiles == nil {\n\t\treturn nil, nil\n\t}\n\n\tmirror_files := rawMirrorFiles.([]*MirrorFileSchema)\n\tif len(mirror_files) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tmirror_map := make(map[string]*MirrorFileSchema)\n\tfor _, mirror_file := range mirror_files {\n\t\tmirror_map[mirror_file.Path] = mirror_file\n\t}\n\n\treturn mirror_map, nil\n}\n\n// Finds the metadata of a file that has been shared to the user\nfunc (m *model) FindMirrorFileByPathAndBucketSlug(ctx context.Context, path, bucketSlug string) (*MirrorFileSchema, error) {\n\tmetaCtx, dbID, err := m.initMirrorFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawMirrorFiles, err := m.threads.Find(metaCtx, *dbID, mirrorFileModelName, db.Where(\"path\").Eq(path), &MirrorFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawMirrorFiles == nil {\n\t\treturn nil, nil\n\t}\n\n\tmirror_files := rawMirrorFiles.([]*MirrorFileSchema)\n\tif len(mirror_files) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tlog.Debug(\"Model.FindMirrorFileByPathAndBucketSlug: returning mirror file with dbid \" + mirror_files[0].DbID)\n\treturn mirror_files[0], nil\n}\n\n// create a new mirror file\nfunc (m *model) CreateMirrorFile(ctx context.Context, mirrorFile *domain.MirrorFile) (*MirrorFileSchema, error) {\n\tmetaCtx, metaDbID, err := m.initMirrorFileModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tmf, err := m.FindMirrorFileByPathAndBucketSlug(ctx, mirrorFile.Path, mirrorFile.BucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif mf != nil {\n\t\treturn nil, errMirrorFileAlreadyExists\n\t}\n\n\tnewInstance := &MirrorFileSchema{\n\t\tPath:              mirrorFile.Path,\n\t\tBucketSlug:        mirrorFile.BucketSlug,\n\t\tBackup:            mirrorFile.Backup,\n\t\tBackupInProgress:  mirrorFile.BackupInProgress,\n\t\tRestoreInProgress: mirrorFile.RestoreInProgress,\n\t\tShared:            mirrorFile.Shared,\n\t}\n\n\tinstances := client.Instances{newInstance}\n\n\tres, err := m.threads.Create(metaCtx, *metaDbID, mirrorFileModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tid := res[0]\n\treturn &MirrorFileSchema{\n\t\tPath:              newInstance.Path,\n\t\tBucketSlug:        newInstance.BucketSlug,\n\t\tBackup:            newInstance.Backup,\n\t\tBackupInProgress:  newInstance.BackupInProgress,\n\t\tRestoreInProgress: newInstance.RestoreInProgress,\n\t\tShared:            newInstance.Shared,\n\t\tID:                core.InstanceID(id),\n\t\tDbID:              newInstance.DbID,\n\t}, nil\n}\n\n// update existing mirror file\nfunc (m *model) UpdateMirrorFile(ctx context.Context, mirrorFile *MirrorFileSchema) (*MirrorFileSchema, error) {\n\tmetaCtx, metaDbID, err := m.initMirrorFileModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tmf, err := m.FindMirrorFileByPathAndBucketSlug(ctx, mirrorFile.Path, mirrorFile.BucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif mf == nil {\n\t\treturn nil, errMirrorFileNotFound\n\t}\n\n\texistingInstance := mirrorFile\n\tinstances := client.Instances{existingInstance}\n\n\terr = m.threads.Save(metaCtx, *metaDbID, mirrorFileModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debug(fmt.Sprintf(\"saved mirror file (%+v)\", mirrorFile))\n\n\treturn mf, nil\n}\n\nfunc (m *model) initMirrorFileModel(ctx context.Context) (context.Context, *thread.ID, error) {\n\tmetaCtx, dbID, err := m.getMetaThreadContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tm.threads.NewCollection(metaCtx, *dbID, GetMirrorFileCollectionConfig())\n\n\t// Migrates db by adding new fields between old version of the daemon and a new one\n\tm.threads.UpdateCollection(metaCtx, *dbID, db.CollectionConfig{\n\t\tName:   mirrorFileModelName,\n\t\tSchema: util.SchemaFromInstance(&MirrorFileSchema{}, false),\n\t})\n\n\treturn metaCtx, dbID, nil\n}\n\nfunc GetMirrorFileCollectionConfig() db.CollectionConfig {\n\treturn db.CollectionConfig{\n\t\tName:   mirrorFileModelName,\n\t\tSchema: util.SchemaFromInstance(&MirrorFileSchema{}, false),\n\t\tIndexes: []db.Index{{\n\t\t\tPath:   \"path\",\n\t\t\tUnique: true, // TODO: multicolumn index\n\t\t}},\n\t}\n}\n"
  },
  {
    "path": "core/textile/model/model.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\tthreadsClient \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\tnc \"github.com/textileio/go-threads/net/api/client\"\n)\n\nconst metaThreadName = \"metathreadV1\"\n\ntype model struct {\n\tst                 store.Store\n\tkc                 keychain.Keychain\n\tthreads            *threadsClient.Client\n\thubAuth            hub.HubAuth\n\tcfg                config.Config\n\tnetc               *nc.Client\n\thnetc              *nc.Client\n\tht                 *threadsClient.Client\n\tshouldForceRestore bool\n\tfsearch            search.FilesSearchEngine\n}\n\ntype Model interface {\n\tCreateBucket(ctx context.Context, bucketSlug, dbID string) (*BucketSchema, error)\n\tUpsertBucket(ctx context.Context, bucketSlug, dbID string) (*BucketSchema, error)\n\tBucketBackupToggle(ctx context.Context, bucketSlug string, backup bool) (*BucketSchema, error)\n\tFindBucket(ctx context.Context, bucketSlug string) (*BucketSchema, error)\n\tListBuckets(ctx context.Context) ([]*BucketSchema, error)\n\tCreateReceivedFileViaInvitation(\n\t\tctx context.Context,\n\t\tfile domain.FullPath,\n\t\tinvitationId string,\n\t\taccepted bool,\n\t\tkey []byte,\n\t\tsharedBy string,\n\t) (*ReceivedFileSchema, error)\n\tCreateReceivedFileViaPublicLink(\n\t\tctx context.Context,\n\t\tipfsHash string,\n\t\tpassword string,\n\t\tfilename string,\n\t\tfilesize string,\n\t\taccepted bool,\n\t) (*ReceivedFileSchema, error)\n\tCreateSentFileViaInvitation(\n\t\tctx context.Context,\n\t\tfile domain.FullPath,\n\t\tinvitationId string,\n\t\tkey []byte,\n\t) (*SentFileSchema, error)\n\tFindReceivedFile(ctx context.Context, remoteDbID, bucket, path string) (*ReceivedFileSchema, error)\n\tFindPublicLinkReceivedFile(ctx context.Context, ipfsHash string) (*ReceivedFileSchema, error)\n\tFindSentFile(ctx context.Context, remoteDbID, bucket, path string) (*SentFileSchema, error)\n\tCreateSharedPublicKey(ctx context.Context, pubKey string) (*SharedPublicKeySchema, error)\n\tListSharedPublicKeys(ctx context.Context) ([]*SharedPublicKeySchema, error)\n\tCreateMirrorBucket(ctx context.Context, bucketSlug string, mirrorBucket *MirrorBucketSchema) (*BucketSchema, error)\n\tFindMirrorFileByPathAndBucketSlug(ctx context.Context, path, bucketSlug string) (*MirrorFileSchema, error)\n\tCreateMirrorFile(ctx context.Context, mirrorFile *domain.MirrorFile) (*MirrorFileSchema, error)\n\tUpdateMirrorFile(ctx context.Context, mirrorFile *MirrorFileSchema) (*MirrorFileSchema, error)\n\tListReceivedFiles(ctx context.Context, accepted bool, seek string, limit int) ([]*ReceivedFileSchema, error)\n\tListSentFiles(ctx context.Context, seek string, limit int) ([]*SentFileSchema, error)\n\tListReceivedPublicFiles(ctx context.Context, cidHash string, accepted bool) ([]*ReceivedFileSchema, error)\n\tDeleteReceivedFiles(ctx context.Context, paths []domain.FullPath, keys [][]byte) error\n\tFindMirrorFileByPaths(ctx context.Context, paths []string) (map[string]*MirrorFileSchema, error)\n\tFindReceivedFilesByIds(ctx context.Context, ids []string) ([]*ReceivedFileSchema, error)\n\tInitSearchIndexCollection(ctx context.Context) error\n\tUpdateSearchIndexRecord(\n\t\tctx context.Context,\n\t\tname, path string,\n\t\titemType SearchItemType,\n\t\tbucketSlug, dbId string,\n\t) (*SearchIndexRecord, error)\n\tQuerySearchIndex(ctx context.Context, query string) ([]*SearchIndexRecord, error)\n\tDeleteSearchIndexRecord(ctx context.Context, name, path, bucketSlug, dbId string) error\n}\n\nfunc New(\n\tst store.Store,\n\tkc keychain.Keychain,\n\tthreads *threadsClient.Client,\n\tht *threadsClient.Client,\n\thubAuth hub.HubAuth,\n\tcfg config.Config,\n\tnetc *nc.Client,\n\thnetc *nc.Client,\n\tshouldForceRestore bool,\n\tsearch search.FilesSearchEngine,\n) *model {\n\treturn &model{\n\t\tst:                 st,\n\t\tkc:                 kc,\n\t\tthreads:            threads,\n\t\thubAuth:            hubAuth,\n\t\tcfg:                cfg,\n\t\tnetc:               netc,\n\t\thnetc:              hnetc,\n\t\tht:                 ht,\n\t\tshouldForceRestore: shouldForceRestore,\n\t\tfsearch:            search,\n\t}\n}\n\nfunc (m *model) findOrCreateMetaThreadID(ctx context.Context) (*thread.ID, error) {\n\treturn utils.FindOrCreateDeterministicThread(\n\t\tctx,\n\t\tutils.MetathreadThreadVariant,\n\t\tmetaThreadName,\n\t\tm.kc,\n\t\tm.st,\n\t\tm.threads,\n\t\tm.cfg,\n\t\tm.netc,\n\t\tm.hnetc,\n\t\tm.hubAuth,\n\t\tm.shouldForceRestore,\n\t\tGetAllCollectionConfigs(),\n\t)\n}\n\nfunc (m *model) getMetaThreadContext(ctx context.Context) (context.Context, *thread.ID, error) {\n\tvar err error\n\n\tvar dbID *thread.ID\n\tif dbID, err = m.findOrCreateMetaThreadID(ctx); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tmetathreadCtx, err := utils.GetThreadContext(ctx, metaThreadName, *dbID, false, m.kc, m.hubAuth, m.threads)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn metathreadCtx, dbID, nil\n}\n\nfunc GetAllCollectionConfigs() []db.CollectionConfig {\n\treturn []db.CollectionConfig{\n\t\tGetBucketCollectionConfig(),\n\t\tGetMirrorFileCollectionConfig(),\n\t\tGetReceivedFileCollectionConfig(),\n\t\tGetSentFileCollectionConfig(),\n\t\tGetSharedPublicKeyCollectionConfig(),\n\t}\n}\n"
  },
  {
    "path": "core/textile/model/received_file.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/go-threads/api/client\"\n\tcore \"github.com/textileio/go-threads/core/db\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\t\"github.com/textileio/go-threads/util\"\n)\n\ntype ReceivedFileViaPublicLinkSchema struct {\n\tPublicIpfsHash string `json:\"publicIpfsHash\"`\n\tFilePassword   string `json:\"filePassword\"`\n\tFileName       string `json:\"fileName\"`\n\tFileSize       string `json:\"fileSize\"`\n}\n\ntype ReceivedFileViaInvitationSchema struct {\n\tDbID          string `json:\"dbId\"`\n\tBucket        string `json:\"bucket\"`\n\tPath          string `json:\"path\"`\n\tInvitationId  string `json:\"invitationId\"`\n\tBucketKey     string `json:\"bucketKey\"`\n\tEncryptionKey []byte `json:\"encryptionKey\"`\n\tSharedBy      string `json:\"sharedBy\"`\n}\n\n// ReceivedFileSchema represents data of files shared with a user\n// A file is shared with a user either by direct invite to the user or through a publicly accessible link\ntype ReceivedFileSchema struct {\n\tID        core.InstanceID `json:\"_id\"`\n\tAccepted  bool            `json:\"accepted\"`\n\tCreatedAt int64           `json:\"created_at\"`\n\tReceivedFileViaInvitationSchema\n\tReceivedFileViaPublicLinkSchema\n}\n\nfunc (r ReceivedFileSchema) IsPublicLinkReceived() bool {\n\treturn r.InvitationId == \"\"\n}\n\nconst receivedFileModelName = \"ReceivedFile\"\n\nvar errReceivedFileNotFound = errors.New(\"Received file not found\")\n\n// Creates the metadata for a file that has been shared to the user\nfunc (m *model) CreateReceivedFileViaInvitation(\n\tctx context.Context,\n\tfile domain.FullPath,\n\tinvitationID string,\n\taccepted bool,\n\tkey []byte,\n\tinviterPubKey string,\n) (*ReceivedFileSchema, error) {\n\tlog.Debug(\"Model.CreateReceivedFileViaInvitation: Storing received file\", \"file:\"+file.Path)\n\tif existingFile, err := m.FindReceivedFile(ctx, file.DbId, file.Bucket, file.Path); err == nil {\n\t\tlog.Debug(\"Model.CreateReceivedFileViaInvitation: Bucket already in collection\")\n\t\treturn existingFile, nil\n\t}\n\n\tnewInstance := &ReceivedFileSchema{\n\t\tID: \"\",\n\t\tReceivedFileViaInvitationSchema: ReceivedFileViaInvitationSchema{\n\t\t\tDbID:          file.DbId,\n\t\t\tBucket:        file.Bucket,\n\t\t\tPath:          file.Path,\n\t\t\tInvitationId:  invitationID,\n\t\t\tBucketKey:     file.BucketKey,\n\t\t\tEncryptionKey: key,\n\t\t\tSharedBy:      inviterPubKey,\n\t\t},\n\t\tAccepted:  accepted,\n\t\tCreatedAt: time.Now().UnixNano(),\n\t}\n\n\treturn m.createReceivedFile(ctx, newInstance)\n}\n\nfunc (m *model) CreateReceivedFileViaPublicLink(\n\tctx context.Context,\n\tipfsHash string,\n\tpassword string,\n\tfilename string,\n\tfileSize string,\n\taccepted bool,\n) (*ReceivedFileSchema, error) {\n\tlog.Debug(\n\t\t\"Model.CreateReceivedFileViaPublicLink: Storing received file\",\n\t\t\"hash:\"+ipfsHash,\n\t\t\"filename:\"+filename,\n\t)\n\tif existingFile, err := m.FindPublicLinkReceivedFile(ctx, ipfsHash); err == nil {\n\t\tlog.Debug(\"Model.CreateReceivedFileViaPublicLink: similar file already shared with user\")\n\t\treturn existingFile, nil\n\t}\n\n\tnewInstance := &ReceivedFileSchema{\n\t\tReceivedFileViaPublicLinkSchema: ReceivedFileViaPublicLinkSchema{\n\t\t\tPublicIpfsHash: ipfsHash,\n\t\t\tFilePassword:   password,\n\t\t\tFileName:       filename,\n\t\t\tFileSize:       fileSize,\n\t\t},\n\t\tReceivedFileViaInvitationSchema: ReceivedFileViaInvitationSchema{\n\t\t\tEncryptionKey: []byte(\"\"),\n\t\t},\n\t\tAccepted:  accepted,\n\t\tCreatedAt: time.Now().UnixNano(),\n\t}\n\n\treturn m.createReceivedFile(ctx, newInstance)\n}\n\nfunc (m *model) createReceivedFile(ctx context.Context, instance *ReceivedFileSchema) (*ReceivedFileSchema, error) {\n\tmetaCtx, metaDbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tinstances := client.Instances{instance}\n\tres, err := m.threads.Create(metaCtx, *metaDbID, receivedFileModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debug(\"Model.createReceivedFile: stored received file\", \"instance_id:\"+res[0])\n\n\tid := res[0]\n\treturn &ReceivedFileSchema{\n\t\tID:                              core.InstanceID(id),\n\t\tReceivedFileViaInvitationSchema: instance.ReceivedFileViaInvitationSchema,\n\t\tReceivedFileViaPublicLinkSchema: instance.ReceivedFileViaPublicLinkSchema,\n\t\tAccepted:                        instance.Accepted,\n\t\tCreatedAt:                       instance.CreatedAt,\n\t}, nil\n}\n\nfunc (m *model) FindReceivedFilesByIds(ctx context.Context, ids []string) ([]*ReceivedFileSchema, error) {\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\tvar qry *db.Query\n\tfor i, id := range ids {\n\t\tif i == 0 {\n\t\t\tqry = db.Where(\"invitationId\").Eq(id)\n\t\t} else {\n\t\t\tqry = qry.Or(db.Where(\"invitationId\").Eq(id))\n\t\t}\n\t}\n\n\tfileSchemasRaw, err := m.threads.Find(metaCtx, *dbID, receivedFileModelName, qry, &ReceivedFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfileSchemas := fileSchemasRaw.([]*ReceivedFileSchema)\n\n\treturn fileSchemas, nil\n}\n\n// Finds the metadata of a file that has been shared to the user\nfunc (m *model) FindReceivedFile(ctx context.Context, remoteDbID, bucket, path string) (*ReceivedFileSchema, error) {\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawFiles, err := m.threads.Find(metaCtx, *dbID, receivedFileModelName, db.Where(\"dbId\").Eq(remoteDbID).And(\"bucket\").Eq(bucket).And(\"path\").Eq(path), &ReceivedFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawFiles == nil {\n\t\treturn nil, errReceivedFileNotFound\n\t}\n\n\tfiles := rawFiles.([]*ReceivedFileSchema)\n\tif len(files) == 0 {\n\t\treturn nil, errReceivedFileNotFound\n\t}\n\tlog.Debug(\"Model.FindReceivedFile: returning file with path \" + files[0].Path)\n\treturn files[0], nil\n}\n\nfunc (m *model) FindPublicLinkReceivedFile(ctx context.Context, ipfsHash string) (*ReceivedFileSchema, error) {\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawFiles, err := m.threads.Find(\n\t\tmetaCtx,\n\t\t*dbID,\n\t\treceivedFileModelName,\n\t\tdb.Where(\"publicIpfsHash\").Eq(ipfsHash),\n\t\t&ReceivedFileSchema{},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawFiles == nil {\n\t\treturn nil, errReceivedFileNotFound\n\t}\n\n\tfiles := rawFiles.([]*ReceivedFileSchema)\n\tif len(files) == 0 {\n\t\treturn nil, errReceivedFileNotFound\n\t}\n\tlog.Debug(\"Model.findPublicLinkReceivedFile: returning file with hash \" + files[0].PublicIpfsHash)\n\treturn files[0], nil\n}\n\n// Lists the metadata of files received by the user\n// use accepted bool to look up for either accepted or rejected files\n// If seek == \"\", will start looking from the beginning. If it's an existing ID it will start looking from that ID.\nfunc (m *model) ListReceivedFiles(ctx context.Context, accepted bool, seek string, limit int) ([]*ReceivedFileSchema, error) {\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\tquery := db.Where(\"accepted\").Eq(accepted).LimitTo(limit)\n\n\tif seek != \"\" {\n\t\tquery = query.SeekID(core.InstanceID(seek))\n\t}\n\n\trawFiles, err := m.threads.Find(metaCtx, *dbID, receivedFileModelName, query, &ReceivedFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawFiles == nil {\n\t\treturn []*ReceivedFileSchema{}, nil\n\t}\n\n\tfiles := rawFiles.([]*ReceivedFileSchema)\n\treturn files, nil\n}\n\nfunc (m *model) DeleteReceivedFiles(ctx context.Context, paths []domain.FullPath, keys [][]byte) error {\n\tif len(paths) == 0 {\n\t\treturn nil\n\t}\n\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn err\n\t}\n\n\t// build find query\n\tvar findQuery *db.Query\n\tfor i, path := range paths {\n\t\tq := db.Where(\"dbId\").Eq(path.DbId).\n\t\t\tAnd(\"bucket\").Eq(path.BucketKey).\n\t\t\tAnd(\"path\").Eq(path.Path).\n\t\t\tAnd(\"encryptionKey\").Eq(keys[i])\n\t\tif findQuery == nil {\n\t\t\tfindQuery = q\n\t\t} else {\n\t\t\tfindQuery = findQuery.Or(q)\n\t\t}\n\t}\n\n\trawFiles, err := m.threads.Find(metaCtx, *dbID, receivedFileModelName, findQuery, &ReceivedFileSchema{})\n\tif err != nil {\n\t\treturn err\n\t}\n\tif rawFiles == nil {\n\t\treturn nil\n\t}\n\n\t// extract instance ids from result\n\tfiles := rawFiles.([]*ReceivedFileSchema)\n\tinstanceIds := make([]string, len(files))\n\tfor i, file := range files {\n\t\tinstanceIds[i] = file.ID.String()\n\t}\n\n\treturn m.threads.Delete(metaCtx, *dbID, receivedFileModelName, instanceIds)\n}\n\nfunc (m *model) ListReceivedPublicFiles(\n\tctx context.Context,\n\tcidHash string,\n\taccepted bool,\n) ([]*ReceivedFileSchema, error) {\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\tquery := db.Where(\"accepted\").Eq(accepted).And(\"publicIpfsHash\").Eq(cidHash)\n\n\trawFiles, err := m.threads.Find(metaCtx, *dbID, receivedFileModelName, query, &ReceivedFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawFiles == nil {\n\t\treturn []*ReceivedFileSchema{}, nil\n\t}\n\n\tfiles := rawFiles.([]*ReceivedFileSchema)\n\treturn files, nil\n}\n\nfunc (m *model) initReceivedFileModel(ctx context.Context) (context.Context, *thread.ID, error) {\n\tmetaCtx, dbID, err := m.getMetaThreadContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif err := m.threads.NewCollection(metaCtx, *dbID, GetReceivedFileCollectionConfig()); err != nil {\n\t\tlog.Debug(\"initReceivedFileModel: collection already exists\")\n\t}\n\n\treturn metaCtx, dbID, nil\n}\n\nfunc GetReceivedFileCollectionConfig() db.CollectionConfig {\n\treturn db.CollectionConfig{\n\t\tName:   receivedFileModelName,\n\t\tSchema: util.SchemaFromInstance(&ReceivedFileSchema{}, false),\n\t}\n}\n"
  },
  {
    "path": "core/textile/model/received_file_test.go",
    "content": "package model\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestReceivedFileSchema_IsPublicLinkReceived_ShouldBeFalse_For_InvitationId(t *testing.T) {\n\tschema := ReceivedFileSchema{\n\t\tReceivedFileViaInvitationSchema: ReceivedFileViaInvitationSchema{\n\t\t\tDbID:          \"some-db-id\",\n\t\t\tBucket:        \"personal-mirror\",\n\t\t\tPath:          \"/\",\n\t\t\tInvitationId:  \"some-invitation-id\",\n\t\t\tBucketKey:     \"\",\n\t\t\tEncryptionKey: []byte(\"\"),\n\t\t},\n\t}\n\n\tassert.False(t, schema.IsPublicLinkReceived(), \"received file should not be public\")\n}\n"
  },
  {
    "path": "core/textile/model/search.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/search\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\ntype SearchItemType string\n\nconst (\n\tFileItem                 SearchItemType = \"FILE\"\n\tDirectoryItem            SearchItemType = \"DIRECTORY\"\n\tDefaultSearchResultLimit int            = 20\n)\n\ntype SearchIndexRecord search.IndexRecord\n\nfunc (m *model) InitSearchIndexCollection(ctx context.Context) error {\n\tlog.Debug(\"Model.InitSearchIndexCollection: Initializing db\")\n\treturn m.fsearch.Start()\n}\n\nfunc (m *model) UpdateSearchIndexRecord(\n\tctx context.Context,\n\tname, itemPath string,\n\titemType SearchItemType,\n\tbucketSlug, dbId string,\n) (*SearchIndexRecord, error) {\n\tlog.Debug(\"Model.UpdateSearchIndexRecord: Initializing db\")\n\tif instance, err := m.fsearch.InsertFileData(ctx, &search.InsertIndexRecord{\n\t\tItemName:      name,\n\t\tItemExtension: strings.Replace(path.Ext(name), \".\", \"\", -1),\n\t\tItemPath:      itemPath,\n\t\tItemType:      string(itemType),\n\t\tBucketSlug:    bucketSlug,\n\t\tDbId:          dbId,\n\t}); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn (*SearchIndexRecord)(instance), nil\n\t}\n}\n\nfunc (m *model) QuerySearchIndex(ctx context.Context, query string) ([]*SearchIndexRecord, error) {\n\tres, err := m.fsearch.QueryFileData(ctx, query, DefaultSearchResultLimit)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]*SearchIndexRecord, len(res))\n\tfor i, item := range res {\n\t\tresult[i] = (*SearchIndexRecord)(item)\n\t}\n\n\treturn result, nil\n}\n\n// DeleteSearchIndexRecords updates the fsearch index by deleting records that match the name and path.\nfunc (m *model) DeleteSearchIndexRecord(ctx context.Context, name, path, bucketSlug, dbId string) error {\n\treturn m.fsearch.DeleteFileData(ctx, &search.DeleteIndexRecord{\n\t\tItemName:   name,\n\t\tItemPath:   path,\n\t\tBucketSlug: bucketSlug,\n\t\tDbId:       dbId,\n\t})\n}\n"
  },
  {
    "path": "core/textile/model/sent_file.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/go-threads/api/client\"\n\tcore \"github.com/textileio/go-threads/core/db\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\t\"github.com/textileio/go-threads/util\"\n)\n\ntype SentFileViaInvitationSchema struct {\n\tDbID          string `json:\"dbId\"`\n\tBucket        string `json:\"bucket\"`\n\tPath          string `json:\"path\"`\n\tInvitationId  string `json:\"invitationId\"`\n\tBucketKey     string `json:\"bucketKey\"`\n\tEncryptionKey []byte `json:\"encryptionKey\"`\n}\n\n// SentFileSchema represents data of files shared by the user\ntype SentFileSchema struct {\n\tID        core.InstanceID `json:\"_id\"`\n\tCreatedAt int64           `json:\"created_at\"`\n\tSentFileViaInvitationSchema\n}\n\nconst sentFileModelName = \"SentFile\"\n\nvar errSentFileNotFound = errors.New(\"Sent file not found\")\n\n// Creates the metadata for a file that has been shared by the user\nfunc (m *model) CreateSentFileViaInvitation(\n\tctx context.Context,\n\tfile domain.FullPath,\n\tinvitationID string,\n\tkey []byte,\n) (*SentFileSchema, error) {\n\tlog.Debug(fmt.Sprintf(\"Model.CreateSentFileViaInvitation: Storing sent file file=%+v\", file))\n\n\tif existingFile, err := m.FindSentFile(ctx, file.DbId, file.Bucket, file.Path); err == nil {\n\t\tlog.Debug(\"Model.CreateSentFileViaInvitation: file already in the collection\")\n\t\treturn existingFile, nil\n\t}\n\n\tnewInstance := &SentFileSchema{\n\t\tID: \"\",\n\t\tSentFileViaInvitationSchema: SentFileViaInvitationSchema{\n\t\t\tDbID:          file.DbId,\n\t\t\tBucket:        file.Bucket,\n\t\t\tPath:          file.Path,\n\t\t\tInvitationId:  invitationID,\n\t\t\tBucketKey:     file.BucketKey,\n\t\t\tEncryptionKey: key,\n\t\t},\n\t\tCreatedAt: time.Now().UnixNano(),\n\t}\n\n\treturn m.createSentFile(ctx, newInstance)\n}\n\nfunc (m *model) createSentFile(ctx context.Context, instance *SentFileSchema) (*SentFileSchema, error) {\n\tmetaCtx, metaDbID, err := m.initSentFileModel(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tinstances := client.Instances{instance}\n\tres, err := m.threads.Create(metaCtx, *metaDbID, sentFileModelName, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Model.createSentFile: stored sent file res=%+v\", res))\n\n\tid := res[0]\n\treturn &SentFileSchema{\n\t\tID:                          core.InstanceID(id),\n\t\tSentFileViaInvitationSchema: instance.SentFileViaInvitationSchema,\n\t\tCreatedAt:                   instance.CreatedAt,\n\t}, nil\n}\n\n// Finds the metadata of a file that has been shared by the user\nfunc (m *model) FindSentFile(ctx context.Context, remoteDbID, bucket, path string) (*SentFileSchema, error) {\n\tmetaCtx, dbID, err := m.initSentFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawFiles, err := m.threads.Find(metaCtx, *dbID, sentFileModelName, db.Where(\"dbId\").Eq(remoteDbID).And(\"bucket\").Eq(bucket).And(\"path\").Eq(path), &SentFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawFiles == nil {\n\t\treturn nil, errSentFileNotFound\n\t}\n\n\tfiles := rawFiles.([]*SentFileSchema)\n\tif len(files) == 0 {\n\t\treturn nil, errSentFileNotFound\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Model.FindSentFile: returning files=%+v\", files))\n\n\treturn files[0], nil\n}\n\n// Lists the metadata of files sent by the user\n// If seek == \"\", will start looking from the beginning. If it's an existing ID it will start looking from that ID.\nfunc (m *model) ListSentFiles(ctx context.Context, seek string, limit int) ([]*SentFileSchema, error) {\n\tmetaCtx, dbID, err := m.initSentFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\tquery := db.OrderByID().LimitTo(limit)\n\n\tif seek != \"\" {\n\t\tquery = query.SeekID(core.InstanceID(seek))\n\t}\n\n\trawFiles, err := m.threads.Find(metaCtx, *dbID, sentFileModelName, query, &SentFileSchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawFiles == nil {\n\t\treturn []*SentFileSchema{}, nil\n\t}\n\n\tfiles := rawFiles.([]*SentFileSchema)\n\treturn files, nil\n}\n\n// XXX: this is to reuse the builders in the sharing.go\nfunc (sf *SentFileSchema) ReceivedFileSchema() *ReceivedFileSchema {\n\treturn &ReceivedFileSchema{\n\t\tID:        sf.ID,\n\t\tCreatedAt: sf.CreatedAt,\n\t\tReceivedFileViaInvitationSchema: ReceivedFileViaInvitationSchema{\n\t\t\tDbID:          sf.DbID,\n\t\t\tBucket:        sf.Bucket,\n\t\t\tPath:          sf.Path,\n\t\t\tInvitationId:  sf.InvitationId,\n\t\t\tBucketKey:     sf.BucketKey,\n\t\t\tEncryptionKey: sf.EncryptionKey,\n\t\t},\n\t}\n}\n\nfunc (m *model) initSentFileModel(ctx context.Context) (context.Context, *thread.ID, error) {\n\tmetaCtx, dbID, err := m.getMetaThreadContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif err := m.threads.NewCollection(metaCtx, *dbID, GetSentFileCollectionConfig()); err != nil {\n\t\tlog.Debug(\"initSentFileModel: collection already exists\")\n\t}\n\n\treturn metaCtx, dbID, nil\n}\n\nfunc GetSentFileCollectionConfig() db.CollectionConfig {\n\treturn db.CollectionConfig{\n\t\tName:   sentFileModelName,\n\t\tSchema: util.SchemaFromInstance(&SentFileSchema{}, false),\n\t}\n}\n"
  },
  {
    "path": "core/textile/model/shared_public_key.go",
    "content": "package model\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/go-threads/api/client\"\n\tcore \"github.com/textileio/go-threads/core/db\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\t\"github.com/textileio/go-threads/util\"\n)\n\ntype SharedPublicKeySchema struct {\n\tID        core.InstanceID `json:\"_id\"`\n\tDbID      string          `json:\"dbId\"`\n\tPublicKey string          `json:\"public_key\"`\n\tUpdatedAt int64           `json:\"updated_at\"`\n\tCreatedAt int64           `json:\"created_at\"`\n}\n\nconst sharedPublicKeyModel = \"SharedPublicKey\"\n\nvar errSharedPublicKeyNotFound = errors.New(\"Shared public key not found\")\n\n// Creates the metadata for a shared public key\nfunc (m *model) CreateSharedPublicKey(ctx context.Context, pubKey string) (*SharedPublicKeySchema, error) {\n\tlog.Debug(\"Model.CreateSharedPublicKey: Storing shared public key \" + pubKey)\n\tif existingPublicKey, err := m.FindSharedPublicKey(ctx, pubKey); err == nil {\n\t\tlog.Debug(\"Model.CreateSharedPublicKey: Shared public key already in collection\")\n\t\treturn existingPublicKey, nil\n\t}\n\n\tlog.Debug(\"Model.CreateSharedPublicKey: Initializing db\")\n\tmetaCtx, metaDbID, err := m.initSharedPublicKey(ctx)\n\tif err != nil && metaDbID == nil {\n\t\treturn nil, err\n\t}\n\n\tnow := time.Now().UnixNano()\n\n\tnewInstance := &SharedPublicKeySchema{\n\t\tID:        \"\",\n\t\tPublicKey: pubKey,\n\t\tUpdatedAt: now,\n\t\tCreatedAt: now,\n\t}\n\n\tinstances := client.Instances{newInstance}\n\tlog.Debug(\"Model.CreateSharedPublicKey: Creating instance\")\n\n\tres, err := m.threads.Create(metaCtx, *metaDbID, sharedPublicKeyModel, instances)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debug(\"Model.CreateSharedPublicKey: stored shared public key \" + newInstance.PublicKey)\n\n\tid := res[0]\n\treturn &SharedPublicKeySchema{\n\t\tID:        core.InstanceID(id),\n\t\tDbID:      newInstance.DbID,\n\t\tPublicKey: newInstance.PublicKey,\n\t\tUpdatedAt: newInstance.UpdatedAt,\n\t\tCreatedAt: newInstance.CreatedAt,\n\t}, nil\n}\n\n// Finds the metadata of a shared public key\nfunc (m *model) FindSharedPublicKey(ctx context.Context, pubKey string) (*SharedPublicKeySchema, error) {\n\tmetaCtx, dbID, err := m.initReceivedFileModel(ctx)\n\tif err != nil || dbID == nil {\n\t\treturn nil, err\n\t}\n\n\trawKeys, err := m.threads.Find(metaCtx, *dbID, sharedPublicKeyModel, db.Where(\"public_key\").Eq(pubKey), &SharedPublicKeySchema{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rawKeys == nil {\n\t\treturn nil, errReceivedFileNotFound\n\t}\n\n\tfiles := rawKeys.([]*SharedPublicKeySchema)\n\tif len(files) == 0 {\n\t\treturn nil, errReceivedFileNotFound\n\t}\n\tlog.Debug(\"Model.FindReceivedFile: returning shared public key \" + files[0].PublicKey)\n\treturn files[0], nil\n}\n\nfunc (m *model) initSharedPublicKey(ctx context.Context) (context.Context, *thread.ID, error) {\n\tmetaCtx, dbID, err := m.getMetaThreadContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tmanagedKey, err := m.kc.GetManagedThreadKey(metaThreadName)\n\tif err != nil {\n\t\tlog.Error(\"error getting managed thread key\", err)\n\t\treturn nil, nil, err\n\t}\n\n\tif err = m.threads.NewDB(metaCtx, *dbID, db.WithNewManagedThreadKey(managedKey)); err != nil {\n\t\tlog.Debug(\"initSharedPublicKey: db already exists\")\n\t}\n\tif err := m.threads.NewCollection(metaCtx, *dbID, GetSharedPublicKeyCollectionConfig()); err != nil {\n\t\tlog.Debug(\"initSharedPublicKey: collection already exists\")\n\t}\n\n\treturn metaCtx, dbID, nil\n}\n\nconst listSharedPublicKeysLimit = 128\n\nfunc (m *model) ListSharedPublicKeys(ctx context.Context) ([]*SharedPublicKeySchema, error) {\n\tmetaCtx, dbID, err := m.initSharedPublicKey(ctx)\n\tif err != nil && dbID == nil {\n\t\treturn nil, err\n\t}\n\n\tquery := &db.Query{}\n\tquery.Limit = listSharedPublicKeysLimit\n\tquery.Sort.FieldPath = \"CreatedAt\"\n\tquery.Sort.Desc = false\n\n\trawKeys, err := m.threads.Find(metaCtx, *dbID, sharedPublicKeyModel, query, &SharedPublicKeySchema{})\n\tif rawKeys == nil {\n\t\treturn []*SharedPublicKeySchema{}, nil\n\t}\n\tkeys := rawKeys.([]*SharedPublicKeySchema)\n\treturn keys, nil\n}\n\nfunc GetSharedPublicKeyCollectionConfig() db.CollectionConfig {\n\treturn db.CollectionConfig{\n\t\tName:   sharedPublicKeyModel,\n\t\tSchema: util.SchemaFromInstance(&SharedPublicKeySchema{}, false),\n\t}\n}\n"
  },
  {
    "path": "core/textile/notifier/notifier.go",
    "content": "package notifier\n\nimport (\n\t\"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\t\"github.com/ipfs/interface-go-ipfs-core/path\"\n)\n\ntype Notifier struct {\n\ts sync.Synchronizer\n}\n\nfunc New(s sync.Synchronizer) *Notifier {\n\treturn &Notifier{\n\t\ts: s,\n\t}\n}\n\nfunc (n *Notifier) OnUploadFile(bucketSlug string, bucketPath string, result path.Resolved, root path.Path) {\n\tn.s.NotifyItemAdded(bucketSlug, bucketPath)\n}\n"
  },
  {
    "path": "core/textile/public.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/opentracing/opentracing-go\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\n\t\"github.com/FleekHQ/space-daemon/core/ipfs\"\n\n\t\"github.com/ipfs/go-cid\"\n\t\"github.com/pkg/errors\"\n\tapi_buckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n)\n\n// Get a public bucket on hub. Public bucket has no encryption and its content should be accessible directly via ipfs/ipns\n// Only use this bucket for items that is okay to be publicly shared\nfunc (tc *textileClient) GetPublicShareBucket(ctx context.Context) (Bucket, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"TextileClient.GetPublicShareBucket\")\n\tdefer span.Finish()\n\n\tif err := tc.requiresRunning(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.getOrCreatePublicBucket(ctx, defaultPublicShareBucketSlug)\n}\n\nfunc (tc *textileClient) createDefaultPublicBucket(ctx context.Context) (Bucket, error) {\n\tctx, dbId, err := tc.getPublicShareBucketContext(ctx, defaultPublicShareBucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbucketRoot, err := tc.createPublicBucket(ctx, *dbId, defaultPublicShareBucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewB := bucket.New(\n\t\tbucketRoot,\n\t\ttc.getPublicShareBucketContext,\n\t\ttc.hb,\n\t)\n\n\treturn newB, nil\n}\n\nfunc (tc *textileClient) getOrCreatePublicBucket(ctx context.Context, bucketSlug string) (Bucket, error) {\n\tctx, dbId, err := tc.getPublicShareBucketContext(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// find if bucket exists\n\tbuckets, err := tc.hb.List(ctx)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to get public bucket\")\n\t}\n\n\tif buckets != nil {\n\t\tfor _, bucketRoot := range buckets.Roots {\n\t\t\tif bucketRoot.Name == bucketSlug {\n\t\t\t\treturn bucket.New(\n\t\t\t\t\tbucketRoot,\n\t\t\t\t\ttc.getPublicShareBucketContext,\n\t\t\t\t\ttc.hb,\n\t\t\t\t), nil\n\t\t\t}\n\t\t}\n\t}\n\n\t// else create bucketRoot\n\tbucketRoot, err := tc.createPublicBucket(ctx, *dbId, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewB := bucket.New(\n\t\tbucketRoot,\n\t\ttc.getPublicShareBucketContext,\n\t\ttc.hb,\n\t)\n\n\treturn newB, nil\n}\n\nfunc (tc *textileClient) getPublicShareBucketContext(ctx context.Context, bucketSlug string) (context.Context, *thread.ID, error) {\n\tdbId, err := tc.getPublicShareThread(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tctx, err = utils.GetThreadContext(ctx, bucketSlug, dbId, true, tc.kc, tc.hubAuth, nil)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn ctx, &dbId, nil\n}\n\n// Creates a public bucket for current user.\nfunc (tc *textileClient) createPublicBucket(ctx context.Context, dbId thread.ID, bucketSlug string) (*api_buckets_pb.Root, error) {\n\tlog.Debug(\"Creating a new public bucket\")\n\n\thubCtx, _, err := tc.getBucketContext(ctx, utils.CastDbIDToString(dbId), bucketSlug, true, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb, err := tc.hb.Create(hubCtx, bc.WithName(bucketSlug), bc.WithPrivate(false))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b.Root, nil\n}\n\nconst publicShareThreadStoreKey = \"publicSharedThreadKey\"\n\n// Creates a remote hub thread for the public sharing bucket\nfunc (tc *textileClient) getPublicShareThread(ctx context.Context) (thread.ID, error) {\n\t// check if db id already exists\n\tstoredDbId, err := tc.store.Get([]byte(publicShareThreadStoreKey))\n\tif err == nil {\n\t\treturn thread.Cast(storedDbId)\n\t}\n\n\t// else create new db\n\tctx, err = tc.getHubCtx(ctx)\n\tif err != nil {\n\t\treturn thread.Undef, err\n\t}\n\n\tdbId := thread.NewIDV1(thread.Raw, 32)\n\n\tif err := tc.ht.NewDB(ctx, dbId); err != nil {\n\t\treturn thread.Undef, err\n\t}\n\tlog.Debug(\"Public share thread created\")\n\n\terr = tc.store.Set([]byte(publicShareThreadStoreKey), []byte(dbId))\n\tif err != nil {\n\t\treturn thread.Undef, errors.Wrap(err, \"failed to persist public share thread\")\n\t}\n\n\treturn dbId, nil\n}\n\n// DownloadPublicGatewayItem download a cid content from the hubs public gateway\nfunc (tc *textileClient) DownloadPublicItem(ctx context.Context, cid cid.Cid) (io.ReadCloser, error) {\n\tgatewayUrl := tc.cfg.GetString(config.TextileHubGatewayUrl, \"https://hub.textile.io\")\n\treturn ipfs.DownloadIpfsItemViaGateway(ctx, gatewayUrl, cid)\n}\n"
  },
  {
    "path": "core/textile/search.go",
    "content": "package textile\n\nimport \"context\"\n\nfunc (tc *textileClient) initSearchIndex(ctx context.Context) error {\n\terr := tc.GetModel().InitSearchIndexCollection(ctx)\n\treturn err\n}\n"
  },
  {
    "path": "core/textile/secure_bucket_client.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/ipfs\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/common\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket/crypto\"\n\n\tma \"github.com/multiformats/go-multiaddr\"\n\tmanet \"github.com/multiformats/go-multiaddr/net\"\n\n\t\"github.com/ipfs/go-cid\"\n\tipfsfiles \"github.com/ipfs/go-ipfs-files\"\n\tiface \"github.com/ipfs/interface-go-ipfs-core\"\n\t\"github.com/ipfs/interface-go-ipfs-core/options\"\n\t\"github.com/ipfs/interface-go-ipfs-core/path\"\n\tthreadsClient \"github.com/textileio/go-threads/api/client\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbucketsClient \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbucketspb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/buckets\"\n)\n\nvar textileRelPathRegex = regexp.MustCompile(`/ip[f|n]s/[^/]*(?P<relPath>/.*)`)\n\n// SecureBucketClient implements the BucketsClient Interface\n// It encrypts data being pushed to the underlying textile client\n// and also decrypts response from the underlying textile client\ntype SecureBucketClient struct {\n\tclient     *bucketsClient.Client\n\tkc         keychain.Keychain\n\tst         store.Store\n\tthreads    *threadsClient.Client\n\tipfsClient iface.CoreAPI\n\tisRemote   bool\n\tcfg        config.Config\n}\n\nfunc NewSecureBucketsClient(\n\tclient *bucketsClient.Client,\n\tkc keychain.Keychain,\n\tst store.Store,\n\tthreads *threadsClient.Client,\n\tipfsClient iface.CoreAPI,\n\tisRemote bool,\n\tcfg config.Config,\n) *SecureBucketClient {\n\treturn &SecureBucketClient{\n\t\tclient:     client,\n\t\tkc:         kc,\n\t\tst:         st,\n\t\tthreads:    threads,\n\t\tipfsClient: ipfsClient,\n\t\tisRemote:   isRemote,\n\t\tcfg:        cfg,\n\t}\n}\n\nfunc (s *SecureBucketClient) PushPath(ctx context.Context, key, path string, reader io.Reader, opts ...bc.Option) (result path.Resolved, root path.Resolved, err error) {\n\tpath = cleanBucketPath(path)\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// encrypt path before uploading\n\tencryptedPath, encryptedReader, err := s.encryptPathData(ctx, encryptionKey, path, reader)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn s.client.PushPath(ctx, key, encryptedPath, encryptedReader)\n\n\t// For now ignoring parsing results since it not being used downstream\n\t// but putting a TODO here in the meantime\n}\n\nfunc (s *SecureBucketClient) PushPathAccessRoles(ctx context.Context, key, path string, roles map[string]buckets.Role) error {\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tencryptedPath, _, err := s.encryptPathData(ctx, encryptionKey, path, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn s.client.PushPathAccessRoles(ctx, key, encryptedPath, roles)\n}\n\nfunc (s *SecureBucketClient) PullPathAccessRoles(ctx context.Context, key, path string) (map[string]buckets.Role, error) {\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tencryptedPath, _, err := s.encryptPathData(ctx, encryptionKey, path, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn s.client.PullPathAccessRoles(ctx, key, encryptedPath)\n}\n\nfunc (s *SecureBucketClient) PullPath(ctx context.Context, key, path string, writer io.Writer, opts ...bc.Option) error {\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tencryptedPath, _, err := s.encryptPathData(ctx, encryptionKey, path, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terrs := make(chan error)\n\tpipeReader, pipeWriter := io.Pipe()\n\n\t// pipe the writes from buckets to reader to be decrypted\n\n\tgo func() {\n\t\tdefer pipeWriter.Close()\n\t\tif err := s.racePullFile(ctx, key, encryptedPath, pipeWriter, opts...); err != nil {\n\t\t\terrs <- err\n\t\t}\n\t}()\n\tgo func() {\n\t\tdefer close(errs)\n\t\t_, r, err := s.decryptPathData(ctx, encryptionKey, \"\", pipeReader)\n\t\tif err != nil {\n\t\t\terrs <- err\n\t\t\treturn\n\t\t}\n\t\tdefer r.Close()\n\t\t// copy decrypted reads to original writer\n\t\tif _, err := io.Copy(writer, r); err != nil {\n\t\t\terrs <- err\n\t\t\treturn\n\t\t}\n\t}()\n\terr = <-errs\n\treturn err\n}\n\nfunc (s *SecureBucketClient) overwriteDecryptedItem(ctx context.Context, item *bucketspb.PathItem) error {\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif utils.IsMetaFileName(item.Name) {\n\t\treturn nil\n\t}\n\t// decrypt file name\n\titem.Name, _, err = s.decryptPathData(ctx, encryptionKey, item.Name, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// decrypts file path\n\tmatchedPaths := textileRelPathRegex.FindStringSubmatch(item.Path)\n\tif len(matchedPaths) > 1 {\n\t\titem.Path, _, err = s.decryptPathData(ctx, encryptionKey, matchedPaths[1], nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Item size is generally (content size + hmac (64 bytes))\n\tif item.Size >= 64 {\n\t\titem.Size = item.Size - 64\n\t}\n\n\treturn nil\n}\n\nfunc (s *SecureBucketClient) ListIpfsPath(ctx context.Context, pth path.Path) (*bucketspb.ListIpfsPathResponse, error) {\n\treturn s.client.ListIpfsPath(ctx, pth)\n}\n\nfunc (s *SecureBucketClient) ListPath(ctx context.Context, key, path string) (*bucketspb.ListPathResponse, error) {\n\tpath = cleanBucketPath(path)\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tencryptedPath, _, err := s.encryptPathData(ctx, encryptionKey, path, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err := s.client.ListPath(ctx, key, encryptedPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decrypt result items\n\tfor _, item := range result.Item.Items {\n\t\terr = s.overwriteDecryptedItem(ctx, item)\n\t\tif err != nil {\n\t\t\t// Don't error on a single file not decrypted\n\t\t\tlog.Debug(fmt.Sprintf(\"Error decrypting a file: %s\", err.Error()))\n\t\t}\n\t}\n\n\t// decrypt root item\n\terr = s.overwriteDecryptedItem(ctx, result.Item)\n\tif err != nil {\n\t\t// Don't error on a single file not decrypted\n\t\tlog.Debug(fmt.Sprintf(\"Error decrypting a file: %s\", err.Error()))\n\t}\n\n\treturn result, nil\n}\n\nfunc (s *SecureBucketClient) RemovePath(ctx context.Context, key, path string, opts ...bc.Option) (path.Resolved, error) {\n\tpath = cleanBucketPath(path)\n\tencryptionKey, err := s.getBucketEncryptionKey(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// encrypt path before submitting delete\n\tencryptedPath, _, err := s.encryptPathData(ctx, encryptionKey, path, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn s.client.RemovePath(ctx, key, encryptedPath, opts...)\n}\n\nfunc (s *SecureBucketClient) getBucketEncryptionKey(ctx context.Context) ([]byte, error) {\n\tif key, exists := common.BucketEncryptionKeyFromContext(ctx); exists {\n\t\treturn key, nil\n\t}\n\treturn nil, errors.New(\"bucket encryption key missing\")\n}\n\nfunc (s *SecureBucketClient) encryptPathData(\n\tctx context.Context,\n\tkey []byte,\n\tpath string,\n\tdataReader io.Reader,\n) (string, io.Reader, error) {\n\treturn crypto.EncryptPathItems(key, path, dataReader)\n}\n\nfunc (s *SecureBucketClient) decryptPathData(\n\tctx context.Context,\n\tkey []byte,\n\tpath string,\n\tdataReader io.Reader,\n) (string, io.ReadCloser, error) {\n\treturn crypto.DecryptPathItems(key, path, dataReader)\n}\n\n// Cleans path used to access data in buckets\n// Currently only removes prefix path if exists.\n// would later include logic to normalize paths from other operating systems like windows\nfunc cleanBucketPath(path string) string {\n\treturn strings.TrimPrefix(path, \"/\")\n}\n\ntype pathPullingFn func(context.Context, string, string, io.Writer, ...bc.Option) (bool, error)\n\ntype pullSuccessResponse struct {\n\tfile        *os.File\n\tshouldCache bool\n}\n\nfunc getTempFileName(encPath string) string {\n\ttempFilePath := sha256.Sum256([]byte(encPath))\n\treturn hex.EncodeToString(tempFilePath[:])\n}\n\nfunc (s *SecureBucketClient) racePullFile(ctx context.Context, key, encPath string, w io.Writer, opts ...bc.Option) error {\n\tpullers := []pathPullingFn{s.pullFileFromLocal, s.pullFileFromDHT, s.pullFileFromClient}\n\n\tvar pullSuccessClosed uint32\n\tvar pullSuccessMutex sync.Mutex\n\n\tpullSuccess := make(chan *pullSuccessResponse)\n\n\tdefer func() {\n\t\tpullSuccessMutex.Lock()\n\t\tdefer pullSuccessMutex.Unlock()\n\n\t\tatomic.StoreUint32(&pullSuccessClosed, 1)\n\t\tclose(pullSuccess)\n\t}()\n\n\terrc := make(chan error)\n\n\tctxWithCancel, cancelPulls := context.WithCancel(ctx)\n\tpendingFns := len(pullers)\n\terroredFns := 0\n\n\tfor _, fn := range pullers {\n\t\tf, err := ioutil.TempFile(\"\", \"*-\"+getTempFileName(encPath))\n\t\tif err != nil {\n\t\t\tcancelPulls()\n\t\t\treturn err\n\t\t}\n\t\tdefer f.Close()\n\t\tdefer os.Remove(f.Name())\n\n\t\tgo func(fn pathPullingFn, f *os.File) {\n\t\t\tshouldCache, err := fn(ctxWithCancel, key, encPath, f, opts...)\n\t\t\tif err != nil {\n\t\t\t\terrc <- err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tchanRes := &pullSuccessResponse{\n\t\t\t\tfile:        f,\n\t\t\t\tshouldCache: shouldCache,\n\t\t\t}\n\n\t\t\tif ctxWithCancel.Err() != nil {\n\t\t\t\terrc <- ctxWithCancel.Err()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpullSuccessMutex.Lock()\n\t\t\tdefer pullSuccessMutex.Unlock()\n\n\t\t\tif atomic.LoadUint32(&pullSuccessClosed) == 0 {\n\t\t\t\tpullSuccess <- chanRes\n\t\t\t}\n\n\t\t\terrc <- nil\n\t\t}(fn, f)\n\t}\n\n\tvar pullErr error\n\n\t// Wait for either all pullers to fail or for one to succeed\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase err := <-errc:\n\t\t\t\tpendingFns--\n\n\t\t\t\tif err != nil {\n\t\t\t\t\terroredFns++\n\t\t\t\t\tpullErr = err\n\t\t\t\t}\n\t\t\t\tif pendingFns <= 0 && erroredFns >= len(pullers) {\n\t\t\t\t\t// All functions failed. Stop waiting\n\t\t\t\t\tpullSuccess <- nil\n\t\t\t\t}\n\n\t\t\t\tif pendingFns <= 0 {\n\t\t\t\t\tclose(errc)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\tpullResponse := <-pullSuccess\n\tcancelPulls()\n\n\t// Return error if all pull functions failed\n\tif erroredFns >= len(pullers) || pullResponse == nil {\n\t\treturn pullErr\n\t}\n\n\tfinalFile := pullResponse.file\n\tshouldCache := pullResponse.shouldCache\n\n\t// Copy pulled file to upstream writer\n\tresErrc := make(chan error)\n\tdefer close(resErrc)\n\tgo func() {\n\t\tfrom, err := os.Open(finalFile.Name())\n\t\tif err != nil {\n\t\t\tresErrc <- err\n\t\t\treturn\n\t\t}\n\t\tdefer from.Close()\n\n\t\t_, err = io.Copy(w, from)\n\t\tresErrc <- err\n\t}()\n\n\t// Copy pulled file to local cache\n\tcacheErrc := make(chan error)\n\tdefer close(cacheErrc)\n\tgo func() {\n\t\tvar err error\n\t\tif !shouldCache {\n\t\t\tcacheErrc <- nil\n\t\t\treturn\n\t\t}\n\t\tfrom, err := os.Open(finalFile.Name())\n\t\tif err != nil {\n\t\t\tcacheErrc <- err\n\t\t\treturn\n\t\t}\n\t\tdefer from.Close()\n\n\t\tp, err := s.ipfsClient.Unixfs().Add(\n\t\t\tctx,\n\t\t\tipfsfiles.NewReaderFile(from),\n\t\t\toptions.Unixfs.Pin(false), // Turn to true when we enable DHT discovery\n\t\t\toptions.Unixfs.Progress(false),\n\t\t\toptions.Unixfs.CidVersion(1),\n\t\t)\n\t\tif err != nil {\n\t\t\tcacheErrc <- err\n\t\t\treturn\n\t\t}\n\n\t\tbucketPath, err := s.client.ListPath(ctx, key, encPath)\n\t\tif err != nil {\n\t\t\tcacheErrc <- err\n\t\t\treturn\n\t\t}\n\t\tencCid := bucketPath.Item.Cid\n\n\t\tcidBinary := p.Cid().Bytes()\n\t\terr = s.st.Set(getFileCacheKey(encCid), cidBinary)\n\n\t\tcacheErrc <- err\n\t}()\n\n\tif err := <-resErrc; err != nil {\n\t\treturn err\n\t}\n\n\tif err := <-cacheErrc; err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nconst FileCachePrefix = \"file_cache\"\n\nfunc getFileCacheKey(encCid string) []byte {\n\treturn []byte(FileCachePrefix + \":\" + encCid)\n}\n\nfunc (s *SecureBucketClient) pullFileFromClient(ctx context.Context, key, encPath string, w io.Writer, opts ...bc.Option) (shouldCache bool, err error) {\n\tshouldCache = true\n\tif s.isRemote == false {\n\t\t// File already in local bucket\n\t\tshouldCache = false\n\t}\n\n\tif err = s.client.PullPath(ctx, key, encPath, w, opts...); err != nil {\n\t\treturn false, err\n\t}\n\treturn shouldCache, nil\n}\n\nvar errNoLocalClient = errors.New(\"No cache client available\")\n\nfunc (s *SecureBucketClient) pullFileFromLocal(ctx context.Context, key, encPath string, w io.Writer, opts ...bc.Option) (shouldCache bool, err error) {\n\tshouldCache = false\n\n\tbucketPath, err := s.client.ListPath(ctx, key, encPath)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tencCid := bucketPath.Item.Cid\n\n\tcidBinary, err := s.st.Get(getFileCacheKey(encCid))\n\tif cidBinary == nil || err != nil {\n\t\treturn false, errors.New(\"CID not stored in local cache\")\n\t}\n\n\t_, c, err := cid.CidFromBytes(cidBinary)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tnode, err := s.ipfsClient.Unixfs().Get(ctx, path.New(c.String()))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tdefer node.Close()\n\n\tfile := ipfsfiles.ToFile(node)\n\tif file == nil {\n\t\treturn false, errors.New(\"File is a directory\")\n\t}\n\n\tif _, err := io.Copy(w, file); err != nil {\n\t\treturn false, err\n\t}\n\n\treturn shouldCache, nil\n}\n\nfunc (s *SecureBucketClient) pullFileFromDHT(ctx context.Context, key, encPath string, w io.Writer, opts ...bc.Option) (shouldCache bool, err error) {\n\tshouldCache = false\n\n\tbucketPath, err := s.client.ListPath(ctx, key, encPath)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tencCid := bucketPath.Item.Cid\n\n\tcid, err := cid.Decode(encCid)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tipfsAddr := s.cfg.GetString(config.Ipfsaddr, \"/ip4/127.0.0.1/tcp/5001\")\n\n\tmaddr, err := ma.NewMultiaddr(ipfsAddr)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"Unable to parse IPFS Multiaddr: %s\", ipfsAddr), err)\n\t\treturn false, err\n\t}\n\n\t_, host, err := manet.DialArgs(maddr)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"Unable to dial IPFS Multiaddr: %+v\", maddr), err)\n\t\treturn false, err\n\t}\n\n\treader, err := ipfs.DownloadIpfsItem(ctx, host, cid)\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"Unable to download IPFS CID %s from host %s\", cid.String(), host), err)\n\t\treturn false, err\n\t}\n\n\tif _, err := io.Copy(w, reader); err != nil {\n\t\treturn false, err\n\t}\n\n\treturn shouldCache, nil\n}\n\nconst cacheBucketThreadName = \"cache_bucket\"\n"
  },
  {
    "path": "core/textile/sharing.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/util/address\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tcrypto \"github.com/libp2p/go-libp2p-crypto\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/textile/v2/buckets\"\n)\n\nfunc (tc *textileClient) ManageShareFilesViaPublicKey(\n\tctx context.Context,\n\tpaths []domain.FullPath,\n\tpubkeys []crypto.PubKey,\n\tkeys [][]byte,\n\trole domain.SharedFilesRoleAction,\n) error {\n\tvar err error\n\tctx, err = tc.getHubCtx(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar bucketRole buckets.Role\n\tswitch role {\n\tcase domain.ReadWriteRoleAction:\n\t\t// NOTE: setting to admin because receiving user\n\t\t// should be able to see members and reshare\n\t\t// as well\n\t\tbucketRole = buckets.Admin\n\tcase domain.DeleteRoleAction:\n\t\tbucketRole = buckets.None\n\tdefault:\n\t\treturn errors.New(\"unsupported shared files role\")\n\t}\n\n\tfor i, pth := range paths {\n\t\tctx, _, err = tc.getBucketContext(ctx, pth.DbId, pth.Bucket, true, keys[i])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlog.Info(\"Adding roles\", \"path:\"+pth.Path, \"role:\"+bucketRole.String())\n\t\troles := make(map[string]buckets.Role)\n\t\tfor _, pk := range pubkeys {\n\t\t\ttpk := thread.NewLibp2pPubKey(pk)\n\t\t\troles[tpk.String()] = bucketRole\n\t\t}\n\n\t\tsbc := tc.getSecureBucketsClient(tc.hb)\n\n\t\terr := sbc.PushPathAccessRoles(ctx, pth.BucketKey, pth.Path, roles)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nvar errInvitationNotPending = errors.New(\"invitation is no more pending\")\nvar errInvitationAlreadyAccepted = errors.New(\"invitation is already accepted\")\nvar errInvitationAlreadyRejected = errors.New(\"invitation is already rejected\")\n\nfunc (tc *textileClient) AcceptSharedFilesInvitation(\n\tctx context.Context,\n\tinvitation domain.Invitation,\n) (domain.Invitation, error) {\n\tif invitation.Status == domain.ACCEPTED {\n\t\treturn domain.Invitation{}, errInvitationAlreadyAccepted\n\t}\n\n\tif invitation.Status != domain.PENDING {\n\t\treturn domain.Invitation{}, errInvitationNotPending\n\t}\n\n\terr := tc.createReceivedFiles(ctx, invitation, true)\n\tif err != nil {\n\t\treturn domain.Invitation{}, err\n\t}\n\tinvitation.Status = domain.ACCEPTED\n\n\treturn invitation, nil\n}\n\nfunc (tc *textileClient) RejectSharedFilesInvitation(\n\tctx context.Context,\n\tinvitation domain.Invitation,\n) (domain.Invitation, error) {\n\tif invitation.Status == domain.REJECTED {\n\t\treturn domain.Invitation{}, errInvitationAlreadyRejected\n\t}\n\n\tif invitation.Status != domain.PENDING {\n\t\treturn domain.Invitation{}, errInvitationNotPending\n\t}\n\n\terr := tc.createReceivedFiles(ctx, invitation, false)\n\tif err != nil {\n\t\treturn domain.Invitation{}, err\n\t}\n\tinvitation.Status = domain.REJECTED\n\n\treturn invitation, nil\n}\n\nfunc (tc *textileClient) createReceivedFiles(\n\tctx context.Context,\n\tinvitation domain.Invitation,\n\taccepted bool,\n) error {\n\tif len(invitation.ItemPaths) != len(invitation.Keys) {\n\t\treturn errors.New(\"size of encryption keys does not match all items shared\")\n\t}\n\n\t// TODO: Make this is call a transaction on threads so any failure can be easily reverted\n\n\tvar allErr error\n\tfor i, path := range invitation.ItemPaths {\n\t\tencryptionKeys := []byte(\"\")\n\t\tif accepted {\n\t\t\tencryptionKeys = invitation.Keys[i]\n\t\t}\n\t\treceivedFile, err := tc.GetModel().CreateReceivedFileViaInvitation(ctx, path, invitation.InvitationID, accepted, encryptionKeys, invitation.InviterPublicKey)\n\n\t\t// compose each create error\n\t\tif err != nil {\n\t\t\tif allErr == nil {\n\t\t\t\tallErr = errors.Wrap(err, \"Failed to accept some invitations\")\n\t\t\t}\n\t\t\tallErr = errors.Wrap(err, allErr.Error())\n\t\t} else {\n\t\t\tif accepted {\n\t\t\t\ttc.sync.NotifyIndexItemAdded(receivedFile.Bucket, receivedFile.Path, receivedFile.DbID)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn allErr\n}\n\nfunc (tc *textileClient) AcceptSharedFileLink(\n\tctx context.Context,\n\tcidHash, password, filename, fileSize string,\n) (*domain.SharedDirEntry, error) {\n\treceivedFile, err := tc.GetModel().CreateReceivedFileViaPublicLink(ctx, cidHash, password, filename, fileSize, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tc.buildPublicLinkSharedDirEntry(ctx, receivedFile)\n}\n\nfunc (tc *textileClient) GetPublicReceivedFile(\n\tctx context.Context,\n\tcidHash string,\n\taccepted bool,\n) (*domain.SharedDirEntry, string, error) {\n\tfiles, err := tc.GetModel().ListReceivedPublicFiles(ctx, cidHash, accepted)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tif len(files) == 0 {\n\t\treturn nil, \"\", errors.New(\"not found\")\n\t}\n\n\tentry, err := tc.buildPublicLinkSharedDirEntry(ctx, files[0])\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\treturn entry, files[0].FilePassword, nil\n}\n\nfunc (tc *textileClient) GetReceivedFiles(\n\tctx context.Context,\n\taccepted bool,\n\tseek string,\n\tlimit int,\n) ([]*domain.SharedDirEntry, string, error) {\n\tfiles, err := tc.GetModel().ListReceivedFiles(ctx, accepted, seek, limit)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\titems := []*domain.SharedDirEntry{}\n\n\tif len(files) == 0 {\n\t\treturn items, \"\", nil\n\t}\n\n\tvar res *domain.SharedDirEntry\n\tfor _, file := range files {\n\t\tif file.IsPublicLinkReceived() {\n\t\t\tres, err = tc.buildPublicLinkSharedDirEntry(ctx, file)\n\t\t} else {\n\t\t\tres, err = tc.buildInvitationSharedDirEntry(ctx, file, false)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, \"\", err\n\t\t}\n\t\titems = append(items, res)\n\t}\n\n\toffset := files[len(files)-1].ID.String()\n\n\treturn items, offset, nil\n}\n\nfunc (tc *textileClient) GetSentFiles(\n\tctx context.Context,\n\tseek string,\n\tlimit int,\n) ([]*domain.SharedDirEntry, string, error) {\n\tfiles, err := tc.GetModel().ListSentFiles(ctx, seek, limit)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\titems := []*domain.SharedDirEntry{}\n\n\tif len(files) == 0 {\n\t\treturn items, \"\", nil\n\t}\n\n\tvar res *domain.SharedDirEntry\n\tfor _, file := range files {\n\t\tres, err = tc.buildInvitationSharedDirEntry(ctx, file.ReceivedFileSchema(), true)\n\n\t\tif err != nil {\n\t\t\treturn nil, \"\", err\n\t\t}\n\t\titems = append(items, res)\n\t}\n\n\toffset := files[len(files)-1].ID.String()\n\n\treturn items, offset, nil\n}\n\nfunc (tc *textileClient) buildPublicLinkSharedDirEntry(\n\tctx context.Context,\n\tfile *model.ReceivedFileSchema,\n) (*domain.SharedDirEntry, error) {\n\tres := &domain.SharedDirEntry{\n\t\tFileInfo: domain.FileInfo{\n\t\t\tIpfsHash:         file.PublicIpfsHash,\n\t\t\tLocallyAvailable: false,\n\t\t\tBackedUp:         true,\n\t\t\tBackupInProgress: false,\n\t\t\tDirEntry: domain.DirEntry{\n\t\t\t\tPath:          file.FileName,\n\t\t\t\tIsDir:         false,\n\t\t\t\tName:          file.FileName,\n\t\t\t\tSizeInBytes:   file.FileSize,\n\t\t\t\tFileExtension: strings.Replace(filepath.Ext(file.FileName), \".\", \"\", -1),\n\t\t\t\tCreated:       time.Unix(0, file.CreatedAt).Format(time.RFC3339),\n\t\t\t\tUpdated:       time.Unix(0, file.CreatedAt).Format(time.RFC3339),\n\t\t\t},\n\t\t},\n\t\tMembers:      []domain.Member{},\n\t\tIsPublicLink: true,\n\t\tSharedBy:     file.SharedBy,\n\t}\n\n\treturn res, nil\n}\n\nfunc (tc *textileClient) buildInvitationSharedDirEntry(\n\tctx context.Context,\n\tfile *model.ReceivedFileSchema,\n\tisSentFiles bool,\n) (*domain.SharedDirEntry, error) {\n\tctx, _, err := tc.getBucketContext(ctx, file.DbID, file.Bucket, true, file.EncryptionKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsbc := tc.getSecureBucketsClient(tc.hb)\n\n\tf, err := sbc.ListPath(ctx, file.BucketKey, file.Path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tipfsHash := f.Item.Cid\n\tname := f.Item.Name\n\tisDir := false\n\tsize := f.GetItem().Size\n\text := strings.Replace(filepath.Ext(name), \".\", \"\", -1)\n\tupdatedAt := f.GetItem().Metadata.UpdatedAt\n\n\trs, err := sbc.PullPathAccessRoles(ctx, file.BucketKey, file.Path)\n\tif err != nil {\n\t\t// TEMP: returning empty members list until we\n\t\t// fix it on textile side\n\t\t//return nil, \"\", err\n\t\trs = make(map[string]buckets.Role)\n\t}\n\n\tmembers := make([]domain.Member, 0)\n\tfor pubk, _ := range rs {\n\t\tkey := &thread.Libp2pPubKey{}\n\n\t\terr = key.UnmarshalString(pubk)\n\t\tif err != nil {\n\t\t\tlog.Error(fmt.Sprintf(\"key.UnmarshalString(pubk=%+v)\", pubk), err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tpk := key.PubKey\n\n\t\tb, err := pk.Raw()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmembers = append(members, domain.Member{\n\t\t\tAddress:   address.DeriveAddress(pk),\n\t\t\tPublicKey: hex.EncodeToString(b),\n\t\t})\n\t}\n\n\tfileBucket := file.Bucket\n\tfileDbID := file.DbID\n\n\tif isSentFiles {\n\t\tfileBucket = defaultPersonalBucketSlug\n\t\tfileDbID = \"\"\n\t}\n\n\tres := &domain.SharedDirEntry{\n\t\tBucket: fileBucket,\n\t\tDbID:   fileDbID,\n\t\tFileInfo: domain.FileInfo{\n\t\t\tIpfsHash:         ipfsHash,\n\t\t\tLocallyAvailable: isSentFiles,\n\t\t\tBackedUp:         true,\n\n\t\t\t// TODO: Reflect correct state when we add local updates syncing to remote\n\t\t\tBackupInProgress:  false,\n\t\t\tRestoreInProgress: false,\n\n\t\t\tDirEntry: domain.DirEntry{\n\t\t\t\tPath:          file.Path,\n\t\t\t\tIsDir:         isDir,\n\t\t\t\tName:          name,\n\t\t\t\tSizeInBytes:   strconv.FormatInt(size, 10),\n\t\t\t\tFileExtension: ext,\n\t\t\t\tCreated:       time.Unix(0, file.CreatedAt).Format(time.RFC3339),\n\t\t\t\tUpdated:       time.Unix(0, updatedAt).Format(time.RFC3339),\n\t\t\t},\n\t\t},\n\t\tSharedBy: file.SharedBy,\n\t\tMembers:  members,\n\t}\n\n\treturn res, nil\n}\n\nfunc (tc *textileClient) GetPathAccessRoles(ctx context.Context, b Bucket, path string) ([]domain.Member, error) {\n\tvar err error\n\tvar bucketSlug, bucketKey string\n\n\tbucketSlug = b.Slug()\n\n\tbucket, err := tc.GetModel().FindBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbucketKey = bucket.RemoteBucketKey\n\n\thubCtx, _, err := tc.getBucketContext(ctx, bucket.RemoteDbID, bucketSlug, true, bucket.EncryptionKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsbc := tc.getSecureBucketsClient(tc.hb)\n\n\trs, err := sbc.PullPathAccessRoles(hubCtx, bucketKey, path)\n\tif err != nil {\n\t\t// log.Error(fmt.Sprintf(\"PullPathAccessRoles not resolved (bucketKey=%s bucketSlug=%s path=%s)\", bucketKey, bucketSlug, path), err)\n\t\treturn []domain.Member{}, nil\n\t}\n\n\t// log.Debug(fmt.Sprintf(\"PullPathAccessRoles roles=%+v\", rs))\n\n\tmembers := make([]domain.Member, 0)\n\tfor pubk, _ := range rs {\n\t\tkey := &thread.Libp2pPubKey{}\n\n\t\terr = key.UnmarshalString(pubk)\n\t\tif err != nil {\n\t\t\tlog.Error(fmt.Sprintf(\"key.UnmarshalString(pubk=%+v)\", pubk), err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tpk := key.PubKey\n\n\t\tb, err := pk.Raw()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmembers = append(members, domain.Member{\n\t\t\tAddress:   address.DeriveAddress(pk),\n\t\t\tPublicKey: hex.EncodeToString(b),\n\t\t})\n\t}\n\n\treturn members, nil\n}\n\n// return true if file was shared\n// XXX: export this func?\nfunc (tc *textileClient) isSharedFile(ctx context.Context, bucket Bucket, path string) bool {\n\tsbc := tc.getSecureBucketsClient(tc.hb)\n\n\troles, err := sbc.PullPathAccessRoles(ctx, bucket.Key(), path)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tpk, err := tc.kc.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn false\n\t}\n\n\ttpk := thread.NewLibp2pPubKey(pk)\n\n\t// shared means other roles than the user\n\tdelete(roles, tpk.String())\n\n\treturn len(roles) > 0\n}\n"
  },
  {
    "path": "core/textile/sync/mirror.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\tbucketsClient \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tapi_buckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/buckets\"\n)\n\nconst mirrorThreadKeyName = \"mirrorV1\"\n\nfunc (s *synchronizer) setMirrorFileBackup(ctx context.Context, path, bucketSlug string, isInProgress bool) error {\n\tmf, err := s.model.FindMirrorFileByPathAndBucketSlug(ctx, path, bucketSlug)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif mf != nil {\n\t\t// update\n\t\tmf.Backup = !isInProgress\n\t\tmf.BackupInProgress = isInProgress\n\n\t\t_, err = s.model.UpdateMirrorFile(ctx, mf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\t// create\n\t\tmf := &domain.MirrorFile{\n\t\t\tPath:             path,\n\t\t\tBucketSlug:       bucketSlug,\n\t\t\tBackup:           !isInProgress,\n\t\t\tBackupInProgress: isInProgress,\n\t\t\tShared:           false,\n\t\t}\n\n\t\t_, err := s.model.CreateMirrorFile(ctx, mf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// unset mirror file as backup\nfunc (s *synchronizer) unsetMirrorFileBackup(ctx context.Context, path, bucketSlug string) error {\n\tmf, err := s.model.FindMirrorFileByPathAndBucketSlug(ctx, path, bucketSlug)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif mf == nil {\n\t\tlog.Warn(fmt.Sprintf(\"mirror file (path=%+v bucketSlug=%+v) does not exist\", path, bucketSlug))\n\t\treturn nil\n\t}\n\n\t// do not delete the instance because it might be shared\n\tmf.Backup = false\n\tmf.BackupInProgress = false\n\n\tif _, err = s.model.UpdateMirrorFile(ctx, mf); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) addCurrentUserAsFileOwner(ctx context.Context, bucket, path string) error {\n\tbucketModel, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\troles := make(map[string]buckets.Role)\n\tpk, err := s.kc.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn err\n\t}\n\ttpk := thread.NewLibp2pPubKey(pk)\n\troles[tpk.String()] = buckets.Admin\n\n\tmirror, err := s.getMirrorBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbucketsClient := mirror.GetClient()\n\tbucketCtx, _, err := s.getBucketCtx(ctx, bucketModel.RemoteDbID, bucketModel.RemoteBucketSlug, true, bucketModel.EncryptionKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn bucketsClient.PushPathAccessRoles(bucketCtx, mirror.GetData().Key, path, roles)\n}\n\n// Creates a mirror bucket.\nfunc (s *synchronizer) createMirrorBucket(ctx context.Context, slug string, enckey []byte) (*model.MirrorBucketSchema, error) {\n\tnewSlug := slug + \"_mirror\"\n\tlog.Debug(\"Creating a new mirror bucket with slug \" + newSlug)\n\tdbID, err := s.createMirrorThread(ctx, newSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thubCtx, _, err := s.getBucketCtx(ctx, utils.CastDbIDToString(*dbID), newSlug, true, enckey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\texistingBuckets, err := s.hubBuckets.List(hubCtx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar root *api_buckets_pb.Root\n\n\tfor _, b := range existingBuckets.Roots {\n\t\tif b.Name == newSlug {\n\t\t\tlog.Debug(\"Mirror bucket with slug \" + newSlug + \" already exists\")\n\t\t\troot = b\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif root == nil {\n\t\tcreateResp, err := s.hubBuckets.Create(hubCtx, bucketsClient.WithName(newSlug))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\troot = createResp.Root\n\t}\n\n\treturn &model.MirrorBucketSchema{\n\t\tRemoteDbID:       utils.CastDbIDToString(*dbID),\n\t\tRemoteBucketKey:  root.Key,\n\t\tRemoteBucketSlug: newSlug,\n\t\tHubAddr:          s.cfg.GetString(config.TextileHubTarget, \"\"),\n\t}, nil\n}\n\n// Creates a remote hub thread for the mirror bucket\nfunc (s *synchronizer) createMirrorThread(ctx context.Context, slug string) (*thread.ID, error) {\n\tlog.Debug(\"createMirrorThread: Generating a new threadID ...\")\n\tvar err error\n\tctx, err = s.hubAuth.GetHubContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdbID, err := utils.NewDeterministicThreadID(s.kc, utils.MirrorBucketVariantGen(slug))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmanagedKey, err := s.kc.GetManagedThreadKey(mirrorThreadKeyName + \"_\" + slug)\n\tif err != nil {\n\t\tlog.Error(\"error getting managed thread key\", err)\n\t\treturn nil, err\n\t}\n\n\t// If dbID is not found, GetDBInfo returns \"thread not found\" error\n\tinfo, err := s.hubThreads.GetDBInfo(ctx, dbID)\n\tif err == nil {\n\t\tlog.Debug(\"createMirrorThread: Db already exists with name \" + info.Name)\n\t\treturn &dbID, nil\n\t}\n\n\tlog.Debug(\"createMirrorThread: Creating Thread DB for bucket at db \" + dbID.String())\n\tif err := s.hubThreads.NewDB(ctx, dbID, db.WithNewManagedThreadKey(managedKey)); err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debug(\"createMirrorThread: Thread DB Created\")\n\treturn &dbID, nil\n}\n"
  },
  {
    "path": "core/textile/sync/pinning.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nfunc (s *synchronizer) uploadFileToRemote(ctx context.Context, bucket, path string) error {\n\tmirrorBucket, err := s.getMirrorBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlocalBucket, err := s.getBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn s.uploadFileToBucket(ctx, localBucket, mirrorBucket, path)\n}\n\nfunc (s *synchronizer) uploadFileToBucket(ctx context.Context, sourceBucket, targetBucket bucket.BucketInterface, path string) error {\n\n\tpipeReader, pipeWriter := io.Pipe()\n\tdefer pipeReader.Close()\n\n\terrc := make(chan error, 1)\n\t// go routine for piping\n\tgo func() {\n\t\tdefer close(errc)\n\t\tdefer pipeWriter.Close()\n\n\t\tif err := sourceBucket.GetFile(ctx, path, pipeWriter); err != nil {\n\t\t\terrc <- err\n\t\t\treturn\n\t\t}\n\n\t\terrc <- nil\n\t}()\n\n\tif _, _, err := targetBucket.UploadFile(ctx, path, pipeReader); err != nil {\n\t\treturn err\n\t}\n\n\tif err := <-errc; err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.addCurrentUserAsFileOwner(ctx, targetBucket.Slug(), path); err != nil {\n\t\t// not returning since we dont want to halt the whole process\n\t\t// also acl will still work since they are the owner\n\t\t// of the thread so this is more for showing members view\n\t\tlog.Error(\"Unable to push path access roles for owner\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) downloadFile(ctx context.Context, sourceBucket, targetBucket bucket.BucketInterface, path string) error {\n\n\tpipeReader, pipeWriter := io.Pipe()\n\tdefer pipeReader.Close()\n\n\terrc := make(chan error, 1)\n\t// go routine for piping\n\tgo func() {\n\t\tdefer close(errc)\n\t\tdefer pipeWriter.Close()\n\n\t\tif err := sourceBucket.GetFile(ctx, path, pipeWriter); err != nil {\n\t\t\terrc <- err\n\t\t\treturn\n\t\t}\n\n\t\terrc <- nil\n\t}()\n\n\tif _, _, err := targetBucket.DownloadFile(ctx, path, pipeReader); err != nil {\n\t\treturn err\n\t}\n\n\tif err := <-errc; err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.addCurrentUserAsFileOwner(ctx, targetBucket.Slug(), path); err != nil {\n\t\t// not returning since we dont want to halt the whole process\n\t\t// also acl will still work since they are the owner\n\t\t// of the thread so this is more for showing members view\n\t\tlog.Error(\"Unable to push path access roles for owner\", err)\n\t}\n\n\treturn nil\n}\n\n// backup all files in a bucket\nfunc (s *synchronizer) uploadAllFilesInPath(ctx context.Context, bucket, path string) error {\n\tlocalBucket, err := s.getBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdir, err := localBucket.ListDirectory(ctx, path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, item := range dir.Item.Items {\n\t\tif utils.IsMetaFileName(item.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif item.IsDir {\n\t\t\terr := s.uploadAllFilesInPath(ctx, bucket, item.Path)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// If the current item is a file, we add it to the queue so that it both gets pinned and synced\n\t\ts.NotifyItemAdded(bucket, item.Path)\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) deleteFileFromRemote(ctx context.Context, bucket, path string) (err error) {\n\tmirrorBucket, err := s.getMirrorBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = mirrorBucket.DeleteDirOrFile(ctx, path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) deleteAllFilesInPath(ctx context.Context, bucket, path string) error {\n\tlocalBucket, err := s.getBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdir, err := localBucket.ListDirectory(ctx, path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, item := range dir.Item.Items {\n\t\tif utils.IsMetaFileName(item.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif item.IsDir {\n\t\t\terr := s.deleteAllFilesInPath(ctx, bucket, item.Path)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// If the current item is a file, we add it to the queue so that it both gets pinned and synced\n\t\ts.NotifyItemRemoved(bucket, item.Path)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/textile/sync/queue.go",
    "content": "package sync\n\nimport (\n\t\"container/list\"\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nconst QueueStoreKey = \"TextileSyncTaskQueue\"\n\ntype marshalledQueue struct {\n\tQueueAsSlice     []Task `json:\"queueAsSlice\"`\n\tFileQueueAsSlice []Task `json:\"fileQueueAsSlice\"`\n}\n\nfunc (s *synchronizer) enqueueTask(task *Task, queue *list.List) {\n\tif s.isTaskEnqueued(task) == false {\n\t\tqueue.PushBack(task)\n\t\ts.queueHashMap[task.ID] = task\n\t}\n}\n\nfunc (s *synchronizer) enqueueTaskAtFront(task *Task, queue *list.List) {\n\tif s.isTaskEnqueued(task) == false {\n\t\tqueue.PushFront(task)\n\t\ts.queueHashMap[task.ID] = task\n\t}\n}\n\nfunc (s *synchronizer) dequeueTask(queue *list.List) *Task {\n\tqueueItem := queue.Front()\n\ts.taskQueue.Remove(queueItem)\n\n\ttask := queueItem.Value.(*Task)\n\tdelete(s.queueHashMap, task.ID)\n\n\treturn task\n}\n\nfunc (s *synchronizer) storeQueue() error {\n\t// Store main queue\n\tqueueAsSlice := []Task{}\n\tcurrEl := s.taskQueue.Front()\n\n\tfor currEl != nil {\n\t\tqueueAsSlice = append(queueAsSlice, *currEl.Value.(*Task))\n\t\tcurrEl = currEl.Next()\n\t}\n\n\t// Store file pinning queue\n\tfileQueueAsSlice := []Task{}\n\tcurrEl = s.filePinningQueue.Front()\n\n\tfor currEl != nil {\n\t\tfileQueueAsSlice = append(fileQueueAsSlice, *currEl.Value.(*Task))\n\t\tcurrEl = currEl.Next()\n\t}\n\n\tobjToMarshal := &marshalledQueue{\n\t\tQueueAsSlice:     queueAsSlice,\n\t\tFileQueueAsSlice: fileQueueAsSlice,\n\t}\n\n\tmarshalled, err := json.Marshal(objToMarshal)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = s.st.Set([]byte(QueueStoreKey), marshalled)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) restoreQueue() error {\n\tqueueMutex1 := s.queueMutexMap[s.taskQueue]\n\tqueueMutex2 := s.queueMutexMap[s.filePinningQueue]\n\tqueueMutex1.Lock()\n\tqueueMutex2.Lock()\n\tdefer queueMutex1.Unlock()\n\tdefer queueMutex2.Unlock()\n\n\tdata, err := s.st.Get([]byte(QueueStoreKey))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tqueue := &marshalledQueue{}\n\terr = json.Unmarshal(data, queue)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, el := range queue.QueueAsSlice {\n\t\ts.enqueueTask(&el, s.taskQueue)\n\t}\n\n\tfor _, el := range queue.FileQueueAsSlice {\n\t\ts.enqueueTask(&el, s.filePinningQueue)\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) isTaskEnqueued(task *Task) bool {\n\texistingTask := s.queueHashMap[task.ID]\n\tif existingTask == nil {\n\t\treturn false\n\t}\n\n\tisPending := existingTask.State == taskQueued || existingTask.State == taskPending\n\tif isPending {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (s *synchronizer) queueString(queue *list.List) string {\n\tqueueName := \"buckets\"\n\tif queue == s.filePinningQueue {\n\t\tqueueName = \"file pinning\"\n\t}\n\n\tfailed, queued, pending := 0, 0, 0\n\n\tfor curr := queue.Front(); curr != nil; curr = curr.Next() {\n\t\ttask := curr.Value.(*Task)\n\n\t\tswitch task.State {\n\t\tcase taskPending:\n\t\t\tpending++\n\t\tcase taskFailed:\n\t\t\tfailed++\n\t\tcase taskQueued:\n\t\t\tqueued++\n\t\t}\n\t}\n\n\treturn fmt.Sprintf(\"Textile sync [%s]: Total: %d, Queued: %d, Pending: %d, Failed: %d\", queueName, queue.Len(), queued, pending, failed)\n}\n"
  },
  {
    "path": "core/textile/sync/restore.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tapi_buckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n)\n\n// return the targetBucket if path is newer there, srcBucket otherwise\nfunc (s *synchronizer) newerBucketPath(ctx context.Context, srcBucket, targetBucket bucket.BucketInterface, path string) (bucket.BucketInterface, error) {\n\ttargetUpdatedAt, err := targetBucket.UpdatedAt(ctx, path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsrcUpdatedAt, err := srcBucket.UpdatedAt(ctx, path)\n\tif err != nil {\n\t\t// Path might not exist in src bucket\n\t\treturn targetBucket, nil\n\t}\n\n\tif srcUpdatedAt >= targetUpdatedAt {\n\t\treturn srcBucket, nil\n\t}\n\n\treturn targetBucket, nil\n}\n\n// restore bucket by downloading files to the local from the mirror bucket\nfunc (s *synchronizer) restoreBucket(ctx context.Context, bucketSlug string) error {\n\n\tlocalBucket, err := s.getBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\tlog.Error(\"Error in getBucket\", err)\n\t\treturn err\n\t}\n\n\tmirrorBucket, err := s.getMirrorBucket(ctx, bucketSlug)\n\tif err != nil {\n\t\tlog.Error(\"Error in getMirrorBucket\", err)\n\t\treturn err\n\t}\n\n\titerator := func(c context.Context, b *bucket.Bucket, itemPath string) error {\n\t\texists, _ := localBucket.FileExists(c, itemPath)\n\n\t\tif exists {\n\t\t\tnewerBucket, err := s.newerBucketPath(c, localBucket, mirrorBucket, itemPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif newerBucket == localBucket {\n\t\t\t\t// do not overwrite: mirror is not newer\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tbucketModel, err := s.model.FindBucket(ctx, bucketSlug)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\titem, err := mirrorBucket.ListDirectory(ctx, itemPath)\n\t\tif s.eventNotifier != nil && err == nil {\n\t\t\tinfo := utils.MapDirEntryToFileInfo(api_buckets_pb.ListPathResponse(*item), itemPath)\n\t\t\tinfo.BackedUp = true\n\t\t\tinfo.LocallyAvailable = exists\n\t\t\tinfo.RestoreInProgress = true\n\t\t\ts.eventNotifier.SendFileEvent(events.NewFileEvent(info, events.FileRestoring, bucketSlug, bucketModel.DbID))\n\t\t}\n\n\t\ts.NotifyFileRestore(bucketSlug, itemPath)\n\t\treturn nil\n\t}\n\n\tif _, err = mirrorBucket.Each(ctx, \"\", iterator, true); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/textile/sync/sync.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n)\n\ntype EventNotifier interface {\n\tSendFileEvent(event events.FileEvent)\n}\n\ntype Synchronizer interface {\n\tNotifyItemAdded(bucket, path string)\n\tNotifyItemRemoved(bucket, path string)\n\tNotifyBucketCreated(bucket string, enckey []byte)\n\tNotifyBucketBackupOn(bucket string)\n\tNotifyBucketBackupOff(bucket string)\n\tNotifyBucketRestore(bucket string)\n\tNotifyFileRestore(bucket, path string)\n\tNotifyBucketStartup(bucket string)\n\tNotifyIndexItemAdded(bucket, path, dbId string)\n\tStart(ctx context.Context)\n\tRestoreQueue() error\n\tShutdown()\n\tString() string\n\tAttachNotifier(EventNotifier)\n}\n"
  },
  {
    "path": "core/textile/sync/sync_test.go",
    "content": "package sync_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\tsy \"sync\"\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/textileio/go-threads/core/thread\"\n)\n\nvar (\n\tmockStore      *mocks.Store\n\tmockClient     *mocks.Client\n\tmockModel      *mocks.Model\n\tmockKeychain   *mocks.Keychain\n\tmockHubAuth    *mocks.HubAuth\n\tmockCfg        *mocks.Config\n\tmockRemoteFile = &textile.GetBucketForRemoteFileInput{\n\t\tBucket: \"\",\n\t\tDbID:   \"\",\n\t\tPath:   \"\",\n\t}\n)\n\nfunc initSync(t *testing.T) sync.Synchronizer {\n\tmockStore = new(mocks.Store)\n\tmockModel = new(mocks.Model)\n\tmockKeychain = new(mocks.Keychain)\n\tmockHubAuth = new(mocks.HubAuth)\n\tmockCfg = new(mocks.Config)\n\tmockClient = new(mocks.Client)\n\n\tmockStore.On(\"IsOpen\").Return(true)\n\n\tgetLocalBucketFn := func(ctx context.Context, slug string) (bucket.BucketInterface, error) {\n\t\treturn mockClient.GetBucket(ctx, slug, nil)\n\t}\n\n\tgetMirrorBucketFn := func(ctx context.Context, slug string) (bucket.BucketInterface, error) {\n\t\treturn mockClient.GetBucket(ctx, slug, mockRemoteFile)\n\t}\n\n\taddListenerFn := func(ctx context.Context, slug string) error {\n\t\treturn nil\n\t}\n\n\tgetBucketCtxFn := func(ctx context.Context, sDbID string, bucketSlug string, ishub bool, enckey []byte) (context.Context, *thread.ID, error) {\n\t\treturn ctx, nil, nil\n\t}\n\n\ts := sync.New(mockStore, mockModel, mockKeychain, mockHubAuth, nil, nil, nil, mockCfg, getMirrorBucketFn, getLocalBucketFn, getBucketCtxFn, addListenerFn)\n\n\treturn s\n}\n\nvar mutex = &sy.Mutex{}\n\nfunc TestSync_ProcessTask(t *testing.T) {\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\n\ts := initSync(t)\n\tctx := context.Background()\n\n\ts.NotifyItemAdded(\"Bucket\", \"path\")\n\n\t// Makes the processAddItem and processPinFilefail right away\n\tmockModel.On(\"FindBucket\", mock.Anything, mock.Anything).Return(nil, errors.New(\"some error\"))\n\t// mockClient.On(\"GetBucket\", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New(\"some error\"))\n\n\tmockStore.On(\"Set\", mock.Anything, mock.Anything).Return(nil)\n\n\ts.Start(ctx)\n\n\ts.Shutdown()\n\n\texpectedState := \"Textile sync [file pinning]: Total: 0, Queued: 0, Pending: 0, Failed: 0\\nTextile sync [buckets]: Total: 1, Queued: 1, Pending: 0, Failed: 0\\n\"\n\n\tassert.Equal(t, expectedState, s.String())\n\tmockModel.AssertExpectations(t)\n\tmockClient.AssertExpectations(t)\n}\n\nfunc TestSync_Restore(t *testing.T) {\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\n\ts := initSync(t)\n\tctx := context.Background()\n\n\ts.NotifyItemAdded(\"Bucket\", \"path\")\n\n\t// Makes the processAddItem and processPinFilefail right away\n\tmockModel.On(\"FindBucket\", mock.Anything, mock.Anything).Return(nil, errors.New(\"some error\"))\n\tmockClient.On(\"GetBucket\", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New(\"some error\"))\n\n\tmockStore.On(\"Set\", []byte(sync.QueueStoreKey), mock.Anything).Return(nil)\n\n\ts.Start(ctx)\n\n\ts.Shutdown()\n\n\togMockStore := mockStore\n\n\ts2 := initSync(t)\n\n\t// Make Store.Get return the data set previously\n\tstoreArgs := ogMockStore.Calls[0].Arguments\n\tbytes := storeArgs.Get(1)\n\tmockStore.On(\"Get\", []byte(sync.QueueStoreKey)).Return(bytes, nil)\n\n\terr := s2.RestoreQueue()\n\n\tmockModel.On(\"FindBucket\", mock.Anything, mock.Anything).Return(nil, errors.New(\"some error\"))\n\tmockClient.On(\"GetBucket\", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New(\"some error\"))\n\tmockStore.On(\"Set\", []byte(sync.QueueStoreKey), mock.Anything).Return(nil)\n\n\t// Note we are not calling NotifyItemAdded therefore the state must be picked from the Restore func\n\ts2.Start(ctx)\n\n\ts2.Shutdown()\n\n\tassert.Nil(t, err)\n\tassert.Equal(t, s.String(), s2.String())\n}\n"
  },
  {
    "path": "core/textile/sync/synchronizer.go",
    "content": "package sync\n\nimport (\n\t\"container/list\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tthreadsClient \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tnc \"github.com/textileio/go-threads/net/api/client\"\n\tbucketsClient \"github.com/textileio/textile/v2/api/bucketsd/client\"\n)\n\ntype GetMirrorBucketFn func(ctx context.Context, slug string) (bucket.BucketInterface, error)\ntype GetBucketFn func(ctx context.Context, slug string) (bucket.BucketInterface, error)\ntype GetBucketCtxFn func(ctx context.Context, sDbID string, bucketSlug string, ishub bool, enckey []byte) (context.Context, *thread.ID, error)\ntype AddBucketListenerFn func(ctx context.Context, bucketSlug string) error\n\nconst maxParallelTasks = 16\n\ntype synchronizer struct {\n\ttaskQueue         *list.List\n\tfilePinningQueue  *list.List\n\tqueueHashMap      map[string]*Task\n\tst                store.Store\n\tmodel             model.Model\n\tsyncNeeded        chan (bool)\n\tshuttingDownMap   map[*list.List]chan (bool)\n\tqueueMutexMap     map[*list.List]*sync.Mutex\n\tgetMirrorBucket   GetMirrorBucketFn\n\tgetBucket         GetBucketFn\n\tgetBucketCtx      GetBucketCtxFn\n\taddBucketListener AddBucketListenerFn\n\tkc                keychain.Keychain\n\thubAuth           hub.HubAuth\n\thubBuckets        *bucketsClient.Client\n\thubThreads        *threadsClient.Client\n\tcfg               config.Config\n\tnetc              *nc.Client\n\tqueueWg           *sync.WaitGroup\n\teventNotifier     EventNotifier\n\tisRunning         bool\n}\n\n// Creates a new Synchronizer\nfunc New(\n\tst store.Store,\n\tmodel model.Model,\n\tkc keychain.Keychain,\n\thubAuth hub.HubAuth,\n\thb *bucketsClient.Client,\n\tht *threadsClient.Client,\n\tnetc *nc.Client,\n\tcfg config.Config,\n\tgetMirrorBucket GetMirrorBucketFn,\n\tgetBucket GetBucketFn,\n\tgetBucketCtx GetBucketCtxFn,\n\taddBucketListenerFn AddBucketListenerFn,\n) *synchronizer {\n\ttaskQueue := list.New()\n\tfilePinningQueue := list.New()\n\n\tqueueMutexMap := make(map[*list.List]*sync.Mutex)\n\tqueueMutexMap[taskQueue] = &sync.Mutex{}\n\tqueueMutexMap[filePinningQueue] = &sync.Mutex{}\n\n\tshuttingDownMap := make(map[*list.List]chan bool)\n\tshuttingDownMap[taskQueue] = make(chan bool)\n\tshuttingDownMap[filePinningQueue] = make(chan bool)\n\n\tqueueWg := &sync.WaitGroup{}\n\n\treturn &synchronizer{\n\t\ttaskQueue:         taskQueue,\n\t\tfilePinningQueue:  filePinningQueue,\n\t\tqueueHashMap:      make(map[string]*Task),\n\t\tst:                st,\n\t\tmodel:             model,\n\t\tsyncNeeded:        make(chan bool),\n\t\tshuttingDownMap:   shuttingDownMap,\n\t\tqueueMutexMap:     queueMutexMap,\n\t\tgetMirrorBucket:   getMirrorBucket,\n\t\tgetBucket:         getBucket,\n\t\tgetBucketCtx:      getBucketCtx,\n\t\taddBucketListener: addBucketListenerFn,\n\t\tkc:                kc,\n\t\thubAuth:           hubAuth,\n\t\thubBuckets:        hb,\n\t\thubThreads:        ht,\n\t\tcfg:               cfg,\n\t\tnetc:              netc,\n\t\tqueueWg:           queueWg,\n\t\tisRunning:         false,\n\t}\n}\n\n// Notify Textile synchronizer that an add item operation needs to be synced\nfunc (s *synchronizer) NotifyItemAdded(bucket, path string) {\n\tt := newTask(addItemTask, []string{bucket, path})\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\n// Notify Textile synchronizer that a remove item operation needs to be synced\nfunc (s *synchronizer) NotifyItemRemoved(bucket, path string) {\n\tt := newTask(removeItemTask, []string{bucket, path})\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyBucketCreated(bucket string, enckey []byte) {\n\tt := newTask(createBucketTask, []string{bucket, hex.EncodeToString(enckey)})\n\ts.enqueueTask(t, s.taskQueue)\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyBucketBackupOn(bucket string) {\n\tt := newTask(bucketBackupOnTask, []string{bucket})\n\tt.Parallelizable = true\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyBucketBackupOff(bucket string) {\n\tt := newTask(bucketBackupOffTask, []string{bucket})\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyBucketRestore(bucket string) {\n\tt := newTask(bucketRestoreTask, []string{bucket})\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyFileRestore(bucket, path string) {\n\tt := newTask(restoreFileTask, []string{bucket, path})\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyBucketStartup(bucket string) {\n\ts.NotifyBucketRestore(bucket)\n\ts.NotifyBucketBackupOn(bucket) // does nothing if !bucket.Backup\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) NotifyIndexItemAdded(bucket, path, dbId string) {\n\tt := newTask(addIndexItemTask, []string{bucket, path, dbId})\n\tt.Parallelizable = true\n\tt.MaxRetries = 2\n\ts.enqueueTask(t, s.taskQueue)\n\n\ts.notifySyncNeeded()\n}\n\nfunc (s *synchronizer) notifySyncNeeded() {\n\tif !s.isRunning {\n\t\treturn\n\t}\n\n\tselect {\n\tcase s.syncNeeded <- true:\n\tdefault:\n\t}\n}\n\n// Starts the synchronizer, which will constantly be checking if there are syncing tasks pending\nfunc (s *synchronizer) Start(ctx context.Context) {\n\ts.queueWg.Add(2)\n\ts.isRunning = true\n\t// Sync loop\n\tgo func() {\n\t\ts.startSyncLoop(ctx, s.taskQueue)\n\t\ts.queueWg.Done()\n\t}()\n\tgo func() {\n\t\ts.startSyncLoop(ctx, s.filePinningQueue)\n\t\ts.queueWg.Done()\n\t}()\n}\n\n// Restores a previously initialized queue\nfunc (s *synchronizer) RestoreQueue() error {\n\tif err := s.restoreQueue(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) startSyncLoop(ctx context.Context, queue *list.List) {\n\tqueueMutex := s.queueMutexMap[queue]\n\t// Initial sync\n\tqueueMutex.Lock()\n\ts.sync(ctx, queue)\n\tqueueMutex.Unlock()\n\nLoop:\n\tfor {\n\t\tqueueMutex.Lock()\n\t\ttimeAfterNextSync := 30 * time.Second\n\n\t\tselect {\n\t\tcase <-time.After(timeAfterNextSync):\n\t\t\ts.sync(ctx, queue)\n\n\t\tcase <-s.syncNeeded:\n\t\t\ts.sync(ctx, queue)\n\n\t\t// Break execution in case of shutdown\n\t\tcase <-ctx.Done():\n\t\t\tqueueMutex.Unlock()\n\t\t\ts.Shutdown()\n\t\t\tbreak Loop\n\t\tcase <-s.shuttingDownMap[queue]:\n\t\t\tqueueMutex.Unlock()\n\t\t\tbreak Loop\n\t\t}\n\n\t\tqueueMutex.Unlock()\n\t}\n}\n\nfunc (s *synchronizer) Shutdown() {\n\n\ts.shuttingDownMap[s.taskQueue] <- true\n\ts.shuttingDownMap[s.filePinningQueue] <- true\n\ts.queueWg.Wait()\n\n\tif err := s.storeQueue(); err != nil {\n\t\tlog.Error(\"Error while storing Textile task queue state\", err)\n\t}\n\n\ts.isRunning = false\n\tclose(s.shuttingDownMap[s.taskQueue])\n\tclose(s.shuttingDownMap[s.filePinningQueue])\n\tclose(s.syncNeeded)\n}\n\nfunc (s *synchronizer) String() string {\n\tqueues := []*list.List{s.filePinningQueue, s.taskQueue}\n\n\tres := \"\"\n\tfor _, q := range queues {\n\t\tres = res + s.queueString(q) + \"\\n\"\n\t}\n\n\treturn res\n}\n\nvar errMaxRetriesSurpassed = errors.New(\"max retries surpassed\")\n\nfunc (s *synchronizer) executeTask(ctx context.Context, t *Task) error {\n\tvar err error\n\n\tswitch t.Type {\n\tcase addItemTask:\n\t\terr = s.processAddItem(ctx, t)\n\tcase removeItemTask:\n\t\terr = s.processRemoveItem(ctx, t)\n\tcase pinFileTask:\n\t\terr = s.processPinFile(ctx, t)\n\tcase unpinFileTask:\n\t\terr = s.processUnpinFile(ctx, t)\n\tcase createBucketTask:\n\t\terr = s.processCreateBucket(ctx, t)\n\tcase bucketBackupOnTask:\n\t\terr = s.processBucketBackupOn(ctx, t)\n\tcase bucketBackupOffTask:\n\t\terr = s.processBucketBackupOff(ctx, t)\n\tcase bucketRestoreTask:\n\t\terr = s.processBucketRestoreTask(ctx, t)\n\tcase restoreFileTask:\n\t\terr = s.processRestoreFile(ctx, t)\n\tcase addIndexItemTask:\n\t\terr = s.processAddIndexItemTask(ctx, t)\n\tcase removeIndexItemTask:\n\t\terr = s.processRemoveIndexItemTask(ctx, t)\n\tdefault:\n\t\tlog.Warn(\"Unexpected action on Textile sync, executeTask\")\n\t}\n\n\tif err != nil {\n\t\tt.State = taskFailed\n\t\tt.Retries++\n\n\t\t// Remove from queue if it surpassed the max amount of retries\n\t\tif t.MaxRetries != -1 && t.Retries > t.MaxRetries {\n\t\t\tt.State = taskDequeued\n\t\t\treturn errMaxRetriesSurpassed\n\t\t}\n\n\t\t// Retry task\n\t\tt.State = taskQueued\n\t} else {\n\t\tt.State = taskSucceeded\n\t}\n\n\treturn err\n}\n\nfunc (s *synchronizer) sync(ctx context.Context, queue *list.List) error {\n\tqueueName := \"buckets\"\n\tif queue == s.filePinningQueue {\n\t\tqueueName = \"file pinning\"\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Textile sync [%s]: Sync start\", queueName))\n\tlog.Debug(s.queueString(queue))\n\n\tparallelTaskCount := 0\n\tptWg := sync.WaitGroup{}\n\n\tfor curr := queue.Front(); curr != nil; curr = curr.Next() {\n\t\ttask := curr.Value.(*Task)\n\n\t\tif task.State != taskQueued {\n\t\t\t// If task is already in process or finished, skip\n\t\t\tcontinue\n\t\t}\n\t\tlog.Debug(fmt.Sprintf(\"Textile sync [%s]: Processing task %s\", queueName, task.Type))\n\t\ttask.State = taskPending\n\n\t\thandleExecResult := func(err error) {\n\t\t\tif err == nil {\n\t\t\t\t// Task completed successfully\n\t\t\t\tlog.Debug(fmt.Sprintf(\"Textile sync [%s]: task completed succesfully\", queueName))\n\t\t\t} else {\n\t\t\t\tlog.Error(fmt.Sprintf(\"Textile sync [%s]: task failed\", queueName), err)\n\t\t\t}\n\t\t}\n\n\t\tif task.Parallelizable && parallelTaskCount < maxParallelTasks {\n\t\t\tparallelTaskCount++\n\t\t\tptWg.Add(1)\n\n\t\t\tgo func() {\n\t\t\t\terr := s.executeTask(ctx, task)\n\t\t\t\thandleExecResult(err)\n\t\t\t\tparallelTaskCount--\n\t\t\t\tptWg.Done()\n\t\t\t}()\n\t\t} else {\n\t\t\terr := s.executeTask(ctx, task)\n\t\t\thandleExecResult(err)\n\n\t\t\tif err != nil {\n\t\t\t\t// Break from the loop (avoid executing next tasks)\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tptWg.Wait()\n\n\t// Remove successful and dequeued tasks from queue\n\tcurr := queue.Front()\n\tfor curr != nil {\n\t\ttask := curr.Value.(*Task)\n\t\tnext := curr.Next()\n\n\t\tswitch task.State {\n\t\tcase taskDequeued:\n\t\t\tqueue.Remove(curr)\n\t\tcase taskSucceeded:\n\t\t\tqueue.Remove(curr)\n\t\tdefault:\n\t\t}\n\n\t\tcurr = next\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Textile sync [%s]: Sync end\", queueName))\n\n\treturn nil\n}\n\nfunc (s *synchronizer) AttachNotifier(notif EventNotifier) {\n\ts.eventNotifier = notif\n}\n"
  },
  {
    "path": "core/textile/sync/task-executors.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\n\t\"path\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\tapi_buckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n)\n\nfunc checkTaskType(t *Task, tp taskType) error {\n\tif tp != t.Type {\n\t\treturn errors.New(\"expected different task type at Textile synchronizer\")\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) processAddItem(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, addItemTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\tpath := task.Args[1]\n\n\tbucketModel, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmirrorFile, err := s.model.FindMirrorFileByPathAndBucketSlug(ctx, path, bucket)\n\n\tif bucketModel.Backup && mirrorFile == nil {\n\t\tif err := s.setMirrorFileBackup(ctx, path, bucket, true); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tlocalBucket, err := s.getBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\titem, err := localBucket.ListDirectory(ctx, path)\n\tif s.eventNotifier != nil && err == nil {\n\t\tinfo := utils.MapDirEntryToFileInfo(api_buckets_pb.ListPathResponse(*item), path)\n\t\tinfo.LocallyAvailable = true\n\t\tinfo.BackupInProgress = true\n\t\ts.eventNotifier.SendFileEvent(events.NewFileEvent(info, events.FileBackupInProgress, bucket, bucketModel.DbID))\n\t}\n\n\tpft := newTask(pinFileTask, []string{bucket, path})\n\ts.enqueueTask(pft, s.filePinningQueue)\n\ts.notifySyncNeeded()\n\n\ts.NotifyIndexItemAdded(bucket, path, \"\")\n\n\treturn nil\n}\n\nfunc (s *synchronizer) processRemoveItem(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, removeItemTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\tpath := task.Args[1]\n\n\tuft := newTask(unpinFileTask, []string{bucket, path})\n\ts.enqueueTask(uft, s.filePinningQueue)\n\n\trIndexTask := newTask(removeIndexItemTask, []string{bucket, path, \"\"})\n\ts.enqueueTask(rIndexTask, s.taskQueue)\n\n\ts.notifySyncNeeded()\n\n\tif err := s.unsetMirrorFileBackup(ctx, path, bucket); err != nil {\n\t\treturn err\n\t}\n\n\terr := s.deleteFileFromRemote(ctx, bucket, path)\n\n\treturn err\n}\n\nfunc (s *synchronizer) processPinFile(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, pinFileTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\tpath := task.Args[1]\n\n\tif err := s.uploadFileToRemote(ctx, bucket, path); err != nil {\n\t\treturn err\n\t}\n\n\ts.setMirrorFileBackup(ctx, path, bucket, false)\n\n\tlocalBucket, err := s.getBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbucketModel, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\titem, err := localBucket.ListDirectory(ctx, path)\n\tif s.eventNotifier != nil && err == nil {\n\t\tinfo := utils.MapDirEntryToFileInfo(api_buckets_pb.ListPathResponse(*item), path)\n\t\tinfo.LocallyAvailable = true\n\t\tinfo.BackedUp = true\n\t\ts.eventNotifier.SendFileEvent(events.NewFileEvent(info, events.FileBackupReady, bucket, bucketModel.DbID))\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) processUnpinFile(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, unpinFileTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\tpath := task.Args[1]\n\n\terr := s.deleteFileFromRemote(ctx, bucket, path)\n\n\treturn err\n}\n\nfunc (s *synchronizer) processCreateBucket(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, createBucketTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\tenckey, err := hex.DecodeString(task.Args[1])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmirror, err := s.createMirrorBucket(ctx, bucket, enckey)\n\tif mirror != nil {\n\t\t_, err = s.model.CreateMirrorBucket(ctx, bucket, mirror)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := s.addBucketListener(ctx, bucket); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) processBucketBackupOn(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, bucketBackupOnTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\n\tbucketModel, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// race\n\tif bucketModel.Backup == false {\n\t\treturn nil\n\t}\n\n\tdbID, err := utils.ParseDbIDFromString(bucketModel.DbID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.replicateThreadToHub(ctx, dbID); err != nil {\n\t\treturn err\n\t}\n\n\treturn s.uploadAllFilesInPath(ctx, bucket, \"\")\n}\n\nfunc (s *synchronizer) processBucketBackupOff(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, bucketBackupOffTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\n\tbucketModel, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// race\n\tif bucketModel.Backup == true {\n\t\treturn nil\n\t}\n\n\tdbID, err := utils.ParseDbIDFromString(bucketModel.DbID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.dereplicateThreadFromHub(ctx, dbID); err != nil {\n\t\treturn err\n\t}\n\n\treturn s.deleteAllFilesInPath(ctx, bucket, \"\")\n}\n\nfunc (s *synchronizer) processBucketRestoreTask(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, bucketRestoreTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\n\tbucketSchema, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif bucketSchema.RemoteDbID == \"\" {\n\t\tt := newTask(createBucketTask, []string{bucket, hex.EncodeToString(bucketSchema.EncryptionKey)})\n\t\ts.enqueueTaskAtFront(t, s.taskQueue)\n\t\treturn errors.New(\"trying to restore a bucket that has not been replicated. Recreating mirror bucket.\")\n\t}\n\n\tif err := s.restoreBucket(ctx, bucket); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) processRestoreFile(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, restoreFileTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\tpath := task.Args[1]\n\n\tlocalBucket, err := s.getBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmirrorBucket, err := s.getMirrorBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewerBucket, err := s.newerBucketPath(ctx, localBucket, mirrorBucket, path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif newerBucket == localBucket {\n\t\t// do not overwrite: mirror is not newer\n\t\treturn nil\n\t}\n\n\t// TODO: use timestamp or CID for check\n\n\tif err = s.downloadFile(ctx, mirrorBucket, localBucket, path); err != nil {\n\t\treturn err\n\t}\n\n\tbucketModel, err := s.model.FindBucket(ctx, bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\titem, err := mirrorBucket.ListDirectory(ctx, path)\n\tif s.eventNotifier != nil && err == nil {\n\t\tinfo := utils.MapDirEntryToFileInfo(api_buckets_pb.ListPathResponse(*item), path)\n\t\tinfo.LocallyAvailable = true\n\t\tinfo.BackedUp = true\n\t\ts.eventNotifier.SendFileEvent(events.NewFileEvent(info, events.FileRestored, bucket, bucketModel.DbID))\n\t}\n\n\treturn err\n}\n\nfunc (s *synchronizer) processAddIndexItemTask(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, addIndexItemTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\titemPath := task.Args[1]\n\tdbId := task.Args[2]\n\n\tif dbId != \"\" {\n\t\t// handle shared file instances\n\t\tfile, err := s.model.FindReceivedFile(ctx, dbId, itemPath, bucket)\n\t\tif err != nil {\n\t\t\tlog.Error(\n\t\t\t\t\"ProcessIndexItemTask: unable to find shared file\",\n\t\t\t\terr,\n\t\t\t\t\"dbId:\"+dbId, \"itemPath:\"+itemPath, \"bucket:\"+bucket,\n\t\t\t)\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = s.model.UpdateSearchIndexRecord(ctx, file.FileName, file.Path, model.FileItem, file.Bucket, dbId)\n\t\tif err != nil {\n\t\t\tlog.Error(\n\t\t\t\t\"ProcessIndexItemTask: failed to index shared file\",\n\t\t\t\terr,\n\t\t\t)\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\terg, ctx := errgroup.WithContext(ctx)\n\t\t// index file\n\t\terg.Go(func() error {\n\t\t\tfileName := path.Base(itemPath)\n\t\t\t_, err := s.model.UpdateSearchIndexRecord(ctx, fileName, itemPath, model.FileItem, bucket, \"\")\n\t\t\tif err != nil {\n\t\t\t\tlog.Error(\n\t\t\t\t\t\"ProcessIndexItemTask: failed to index file\",\n\t\t\t\t\terr,\n\t\t\t\t)\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\n\t\t// index parent dir\n\t\terg.Go(func() error {\n\t\t\tparentPath := path.Dir(itemPath)\n\t\t\tif parentPath == \"/\" {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tdirName := path.Base(parentPath)\n\t\t\t_, err := s.model.UpdateSearchIndexRecord(ctx, dirName, parentPath, model.DirectoryItem, bucket, \"\")\n\t\t\tif err != nil {\n\t\t\t\tlog.Error(\n\t\t\t\t\t\"ProcessIndexItemTask: failed to index directory\",\n\t\t\t\t\terr,\n\t\t\t\t)\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\n\t\terr := erg.Wait()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *synchronizer) processRemoveIndexItemTask(ctx context.Context, task *Task) error {\n\tif err := checkTaskType(task, removeIndexItemTask); err != nil {\n\t\treturn err\n\t}\n\n\tbucket := task.Args[0]\n\titemPath := task.Args[1]\n\tdbId := task.Args[2]\n\tfileName := path.Base(itemPath)\n\n\treturn s.model.DeleteSearchIndexRecord(ctx, fileName, itemPath, bucket, dbId)\n}\n"
  },
  {
    "path": "core/textile/sync/task.go",
    "content": "package sync\n\nimport (\n\t\"strings\"\n)\n\ntype taskType string\n\nconst (\n\taddItemTask         taskType = \"ADD_ITEM\"\n\tremoveItemTask      taskType = \"REMOVE_ITEM\"\n\tcreateBucketTask    taskType = \"CREATE_BUCKET\"\n\tpinFileTask         taskType = \"PIN_FILE\"\n\tunpinFileTask       taskType = \"UNPIN_FILE\"\n\tbucketBackupOnTask  taskType = \"TOGGLE_BACKUP_ON\"\n\tbucketBackupOffTask taskType = \"TOGGLE_BACKUP_OFF\"\n\tbucketRestoreTask   taskType = \"BUCKET_RESTORE\"\n\trestoreFileTask     taskType = \"RESTORE_FILE\"\n\taddIndexItemTask    taskType = \"ADD_INDEX_ITEM\"\n\tremoveIndexItemTask taskType = \"REMOVE_INDEX_ITEM\"\n)\n\ntype taskState string\n\nconst (\n\ttaskQueued    taskState = \"QUEUED\"\n\ttaskPending   taskState = \"PENDING\"\n\ttaskSucceeded taskState = \"SUCCESS\"\n\ttaskFailed    taskState = \"FAILED\"\n\ttaskDequeued  taskState = \"DEQUEUED\"\n)\n\ntype Task struct {\n\tID             string    `json:\"id\"`\n\tState          taskState `json:\"state\"`\n\tType           taskType  `json:\"type\"`\n\tArgs           []string  `json:\"args\"`\n\tParallelizable bool      `json:\"parallelizable\"`\n\n\t// Set to -1 for infinite retries\n\tMaxRetries int `json:\"maxRetries\"`\n\tRetries    int `json:\"retries\"`\n}\n\nfunc newTask(t taskType, args []string) *Task {\n\tid := string(t) + \"_\" + strings.Join(args, \"_\")\n\n\treturn &Task{\n\t\tID:             id,\n\t\tState:          taskQueued,\n\t\tType:           t,\n\t\tArgs:           args,\n\t\tParallelizable: false,\n\t\tMaxRetries:     -1,\n\t\tRetries:        0,\n\t}\n}\n"
  },
  {
    "path": "core/textile/sync/threads.go",
    "content": "package sync\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/textile/v2/cmd\"\n)\n\n// replicate a local thread on the hub\nfunc (s *synchronizer) replicateThreadToHub(ctx context.Context, dbID *thread.ID) error {\n\n\thubma := s.cfg.GetString(config.TextileHubMa, \"\")\n\tif hubma == \"\" {\n\t\treturn fmt.Errorf(\"no textile hub set\")\n\t}\n\n\t_, err := s.netc.AddReplicator(ctx, *dbID, cmd.AddrFromStr(hubma))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// dereplicate a local thread from the hub\nfunc (s *synchronizer) dereplicateThreadFromHub(ctx context.Context, dbID *thread.ID) error {\n\n\t// TODO\n\n\treturn nil\n}\n"
  },
  {
    "path": "core/textile/textile.go",
    "content": "package textile\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/ipfs/go-cid\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/model\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/textileio/go-threads/db\"\n\n\tbuckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/api/usersd/client\"\n\n\tthreadsClient \"github.com/textileio/go-threads/api/client\"\n)\n\nconst (\n\thubTarget                       = \"127.0.0.1:3006\"\n\tthreadsTarget                   = \"127.0.0.1:3006\"\n\tdefaultPersonalBucketSlug       = \"personal\"\n\tdefaultCacheBucketSlug          = \"personal_cache\"\n\tdefaultPersonalMirrorBucketSlug = \"personal_mirror\"\n\tdefaultPublicShareBucketSlug    = \"personal_public\"\n)\n\ntype BucketRoot buckets_pb.Root\n\ntype Bucket interface {\n\tbucket.BucketInterface\n}\n\ntype Client interface {\n\tIsRunning() bool\n\tIsInitialized() bool\n\tIsHealthy() bool\n\tGetDefaultBucket(ctx context.Context) (Bucket, error)\n\tGetBucket(ctx context.Context, slug string, remoteFile *GetBucketForRemoteFileInput) (Bucket, error)\n\tGetThreadsConnection() (*threadsClient.Client, error)\n\tGetModel() model.Model\n\tListBuckets(ctx context.Context) ([]Bucket, error)\n\tShareBucket(ctx context.Context, bucketSlug string) (*db.Info, error)\n\tJoinBucket(ctx context.Context, slug string, ti *domain.ThreadInfo) (bool, error)\n\tCreateBucket(ctx context.Context, bucketSlug string) (Bucket, error)\n\tToggleBucketBackup(ctx context.Context, bucketSlug string, bucketBackup bool) (bool, error)\n\tBucketBackupRestore(ctx context.Context, bucketSlug string) error\n\tSendMessage(ctx context.Context, recipient crypto.PubKey, body []byte) (*client.Message, error)\n\tShutdown() error\n\tWaitForReady() chan bool\n\tWaitForHealthy() chan error\n\tWaitForInitialized() chan bool\n\tStart(ctx context.Context, cfg config.Config) error\n\tGetMailAsNotifications(ctx context.Context, seek string, limit int) ([]*domain.Notification, error)\n\tManageShareFilesViaPublicKey(\n\t\tctx context.Context,\n\t\tpaths []domain.FullPath,\n\t\tpubkeys []crypto.PubKey,\n\t\tkeys [][]byte,\n\t\trole domain.SharedFilesRoleAction,\n\t) error\n\tAcceptSharedFilesInvitation(ctx context.Context, invitation domain.Invitation) (domain.Invitation, error)\n\tRejectSharedFilesInvitation(ctx context.Context, invitation domain.Invitation) (domain.Invitation, error)\n\tAcceptSharedFileLink(\n\t\tctx context.Context,\n\t\tcidHash, password, filename, fileSize string,\n\t) (*domain.SharedDirEntry, error)\n\tRemoveKeys(ctx context.Context) error\n\tAttachMailboxNotifier(notif GrpcMailboxNotifier)\n\tAttachSynchronizerNotifier(notif sync.EventNotifier)\n\tGetReceivedFiles(ctx context.Context, accepted bool, seek string, limit int) ([]*domain.SharedDirEntry, string, error)\n\tGetPublicReceivedFile(ctx context.Context, cidHash string, accepted bool) (*domain.SharedDirEntry, string, error)\n\tGetSentFiles(ctx context.Context, seek string, limit int) ([]*domain.SharedDirEntry, string, error)\n\tGetPathAccessRoles(ctx context.Context, b Bucket, path string) ([]domain.Member, error)\n\tGetPublicShareBucket(ctx context.Context) (Bucket, error)\n\tDownloadPublicItem(ctx context.Context, cid cid.Cid) (io.ReadCloser, error)\n\tGetFailedHealthchecks() int\n\tDeleteAccount(ctx context.Context) error\n\tListen(ctx context.Context, dbID, threadName string) (<-chan threadsClient.ListenEvent, error)\n\tRestoreDB(ctx context.Context) error\n\tDisableSync()\n}\n\ntype Buckd interface {\n\tStop() error\n\tStart(ctx context.Context) error\n}\n\ntype Listener interface {\n\tListen(context.Context) error\n\tClose()\n}\n"
  },
  {
    "path": "core/textile/utils/utils.go",
    "content": "package utils\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/sha512\"\n\t\"encoding/base32\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\tcrypto \"github.com/libp2p/go-libp2p-crypto\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\tnc \"github.com/textileio/go-threads/net/api/client\"\n\tbucketsproto \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"golang.org/x/crypto/pbkdf2\"\n)\n\nfunc CastDbIDToString(dbID thread.ID) string {\n\tbytes := dbID.Bytes()\n\treturn base32.StdEncoding.EncodeToString(bytes)\n}\n\nfunc ParseDbIDFromString(dbID string) (*thread.ID, error) {\n\tbytes, err := base32.StdEncoding.DecodeString(dbID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tid, err := thread.Cast(bytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &id, nil\n}\n\ntype DeterministicThreadVariant string\n\nconst (\n\tMetathreadThreadVariant DeterministicThreadVariant = \"metathread\"\n\tMirrorBucketVariant     DeterministicThreadVariant = \"mirror_bucket\"\n)\n\nfunc MirrorBucketVariantGen(mirrorBucketSlug string) DeterministicThreadVariant {\n\treturn DeterministicThreadVariant(string(MirrorBucketVariant) + \":\" + mirrorBucketSlug)\n}\n\nfunc NewDeterministicThreadID(kc keychain.Keychain, threadVariant DeterministicThreadVariant) (thread.ID, error) {\n\tsize := 32\n\tvariant := thread.Raw\n\n\tpriv, _, err := kc.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn thread.ID([]byte{}), err\n\t}\n\n\tprivInBytes, err := priv.Raw()\n\tif err != nil {\n\t\treturn thread.ID([]byte{}), err\n\t}\n\n\t// Do a key derivation based on the private key, a constant nonce, and the thread variant\n\tnum := pbkdf2.Key(privInBytes, []byte(\"threadID\"+threadVariant), 256, size, sha512.New)\n\tif err != nil {\n\t\treturn thread.ID([]byte{}), err\n\t}\n\n\t// The following code just concats the key derived from the private key (num)\n\t// with some constants such as the thread version and the textile thread variant\n\tnumlen := len(num)\n\t// two 8 bytes (max) numbers plus num\n\tbuf := make([]byte, 2*binary.MaxVarintLen64+numlen)\n\tn := binary.PutUvarint(buf, thread.V1)\n\tn += binary.PutUvarint(buf[n:], uint64(variant))\n\tcn := copy(buf[n:], num)\n\tif cn != numlen {\n\t\tpanic(\"copy length is inconsistent\")\n\t}\n\n\treturn thread.ID(buf[:n+numlen]), nil\n}\n\nfunc getThreadName(userPubKey []byte, bucketSlug string) string {\n\treturn hex.EncodeToString(userPubKey) + \"-\" + bucketSlug\n}\n\n// Readies a context to access a thread given its name and dbid\nfunc GetThreadContext(parentCtx context.Context, threadName string, dbID thread.ID, hub bool, kc keychain.Keychain, hubAuth hub.HubAuth, threadsClient *tc.Client) (context.Context, error) {\n\tvar err error\n\tctx := parentCtx\n\n\t// Some threads will be on the hub and some will be local, this flag lets you specify\n\t// where it is\n\tif hub {\n\t\tctx, err = hubAuth.GetHubContext(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tvar publicKey crypto.PubKey\n\tvar privKey crypto.PrivKey\n\tif privKey, publicKey, err = kc.GetStoredKeyPairInLibP2PFormat(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar pubKeyInBytes []byte\n\tif pubKeyInBytes, err = publicKey.Bytes(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif threadsClient != nil {\n\t\ttok, err := threadsClient.GetToken(ctx, thread.NewLibp2pIdentity(privKey))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tctx = thread.NewTokenContext(ctx, tok)\n\t}\n\n\tctx = common.NewThreadNameContext(ctx, getThreadName(pubKeyInBytes, threadName))\n\tctx = common.NewThreadIDContext(ctx, dbID)\n\n\treturn ctx, nil\n}\n\n// randBytes returns random bytes in a byte slice of size.\nfunc RandBytes(size int) ([]byte, error) {\n\tb := make([]byte, size)\n\t_, err := rand.Read(b)\n\treturn b, err\n}\n\nvar metaFileNames = map[string]bool{\n\t\".textileseed\": true,\n\t\".textile\":     true,\n\t\".DS_Store\":    true,\n\t\".Trashes\":     true,\n\t\".localized\":   true,\n}\n\nfunc IsMetaFileName(pathOrName string) bool {\n\t_, name := filepath.Split(pathOrName)\n\n\treturn metaFileNames[name]\n}\n\nconst threadIDStoreKey = \"thread_id\"\n\n// Returns the store key for a thread ID. It uses the keychain to obtain the public key, since the store key depends on it.\nfunc getDeterministicthreadStoreKey(kc keychain.Keychain, variant DeterministicThreadVariant) ([]byte, error) {\n\tpub, err := kc.GetStoredPublicKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpubInBytes, err := pub.Raw()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := []byte(threadIDStoreKey + \"_\" + string(variant))\n\tresult = append(result, pubInBytes...)\n\n\treturn result, nil\n}\n\n// Finds or creates a thread that's based on the user private key and the specified variant\n// Using the same private key, variant and thread name will always end up generating the same key\nfunc FindOrCreateDeterministicThread(\n\tctx context.Context,\n\tvariant DeterministicThreadVariant,\n\tthreadName string,\n\tkc keychain.Keychain,\n\tst store.Store,\n\tthreads *tc.Client,\n\tcfg config.Config,\n\tnetc *nc.Client,\n\thnetc *nc.Client,\n\thubAuth hub.HubAuth,\n\tshouldForceRestore bool,\n\tdbCollectionConfigs []db.CollectionConfig,\n) (*thread.ID, error) {\n\tstoreKey, err := getDeterministicthreadStoreKey(kc, variant)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpk, _, err := kc.GetStoredKeyPairInLibP2PFormat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif val, _ := st.Get(storeKey); val != nil {\n\t\t// Cast the stored dbID from bytes to thread.ID\n\t\tif dbID, err := thread.Cast(val); err != nil {\n\t\t\treturn nil, err\n\t\t} else {\n\t\t\treturn &dbID, nil\n\t\t}\n\t}\n\n\t// thread id does not exist yet\n\n\t// We need to create an ID that's derived deterministically from the user private key\n\t// The reason for this is that the user needs to be able to restore the exact ID when moving across devices.\n\t// The only consideration is that we must try to avoid dbID collisions with other users.\n\tdbID, err := NewDeterministicThreadID(kc, variant)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdbIDInBytes := dbID.Bytes()\n\n\tmanagedKey, err := kc.GetManagedThreadKey(threadName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tthreadCtx, err := GetThreadContext(ctx, threadName, dbID, false, kc, nil, threads)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thubmaStr := cfg.GetString(config.TextileHubMa, \"\")\n\thubma := cmd.AddrFromStr(hubmaStr)\n\n\thubmaWithThreadID := hubmaStr + \"/thread/\" + dbID.String()\n\n\thubCtx, err := hubAuth.GetHubContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, err = hnetc.GetThread(hubCtx, dbID)\n\treplThreadExists := err == nil\n\tif !replThreadExists && shouldForceRestore {\n\t\treturn nil, err\n\t}\n\tif replThreadExists {\n\t\t// Try to join remote db in case it was already replicated\n\t\terr = threads.NewDBFromAddr(\n\t\t\tthreadCtx,\n\t\t\tcmd.AddrFromStr(hubmaWithThreadID),\n\t\t\tmanagedKey,\n\t\t\tdb.WithNewManagedBackfillBlock(true),\n\t\t\tdb.WithNewManagedThreadKey(managedKey),\n\t\t\tdb.WithNewManagedName(threadName),\n\t\t\tdb.WithNewManagedLogKey(pk),\n\t\t\tdb.WithNewManagedCollections(\n\t\t\t\tdbCollectionConfigs...,\n\t\t\t),\n\t\t)\n\t\tif err == nil || err.Error() == \"rpc error: code = Unknown desc = db already exists\" || err.Error() == \"rpc error: code = Unknown desc = log already exists\" {\n\t\t\treturn successfulThreadCreation(st, &dbID, dbIDInBytes, storeKey)\n\t\t} else if shouldForceRestore == true {\n\t\t\tlog.Error(\"Textile threads require forced restore but there was a restoration issue\", err)\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\terr = threads.NewDB(threadCtx, dbID, db.WithNewManagedLogKey(pk), db.WithNewManagedThreadKey(managedKey), db.WithNewManagedName(threadName))\n\tif err != nil && err.Error() != \"rpc error: code = Unknown desc = db already exists\" {\n\t\treturn nil, err\n\t}\n\n\tif _, err := netc.AddReplicator(threadCtx, dbID, hubma); err == nil {\n\t\treturn successfulThreadCreation(st, &dbID, dbIDInBytes, storeKey)\n\t} else {\n\t\tlog.Error(\"error while replicating metathread\", err)\n\t}\n\n\treturn &dbID, nil\n}\n\nfunc successfulThreadCreation(st store.Store, dbID *thread.ID, dbIDInBytes, storeKey []byte) (*thread.ID, error) {\n\tif err := st.Set(storeKey, dbIDInBytes); err != nil {\n\t\tnewErr := errors.New(\"error while storing thread id: check your local space db accessibility\")\n\t\treturn nil, newErr\n\t}\n\n\treturn dbID, nil\n}\n\nfunc MapDirEntryToFileInfo(entry bucketsproto.ListPathResponse, itemPath string) domain.FileInfo {\n\titem := entry.Item\n\tinfo := domain.FileInfo{\n\t\tDirEntry: domain.DirEntry{\n\t\t\tPath:          itemPath,\n\t\t\tIsDir:         item.IsDir,\n\t\t\tName:          item.Name,\n\t\t\tSizeInBytes:   strconv.FormatInt(item.Size, 10),\n\t\t\tFileExtension: strings.Replace(filepath.Ext(item.Name), \".\", \"\", -1),\n\t\t\t// FIXME: real created at needed\n\t\t\tCreated: time.Unix(0, item.Metadata.UpdatedAt).Format(time.RFC3339),\n\t\t\tUpdated: time.Unix(0, item.Metadata.UpdatedAt).Format(time.RFC3339),\n\t\t\tMembers: []domain.Member{},\n\t\t},\n\t\tIpfsHash:          item.Cid,\n\t\tBackedUp:          false,\n\t\tLocallyAvailable:  false,\n\t\tBackupInProgress:  false,\n\t\tRestoreInProgress: false,\n\t}\n\n\treturn info\n}\n"
  },
  {
    "path": "core/textile/utils/utils_test.go",
    "content": "package utils_test\n\nimport (\n\t\"encoding/hex\"\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-daemon/mocks\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar (\n\tmockStore    *mocks.Store\n\tmockKeychain *mocks.Keychain\n\tmockPubKey   crypto.PubKey\n\tmockPrivKey  crypto.PrivKey\n)\n\nfunc initMocks(t *testing.T) {\n\tmockStore = new(mocks.Store)\n\tmockStore.On(\"IsOpen\").Return(true)\n\n\tmockKeychain = new(mocks.Keychain)\n\n\tmockPubKeyHex := \"67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"\n\tmockPrivKeyHex := \"dd55f8921f90fdf31c6ef9ad86bd90605602fd7d32dc8ea66ab72deb6a82821c67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a9\"\n\n\tpubKeyBytes, _ := hex.DecodeString(mockPubKeyHex)\n\tprivKeyBytes, _ := hex.DecodeString(mockPrivKeyHex)\n\tmockPubKey, _ = crypto.UnmarshalEd25519PublicKey(pubKeyBytes)\n\tmockPrivKey, _ = crypto.UnmarshalEd25519PrivateKey(privKeyBytes)\n}\n\nfunc TestUtils_NewDeterministicThreadID(t *testing.T) {\n\tinitMocks(t)\n\n\tmockKeychain.On(\n\t\t\"GetStoredKeyPairInLibP2PFormat\",\n\t).Return(mockPrivKey, mockPubKey, nil)\n\n\tthreadID, err := utils.NewDeterministicThreadID(mockKeychain, utils.MetathreadThreadVariant)\n\tassert.Nil(t, err)\n\tthreadIDCopy, err := utils.NewDeterministicThreadID(mockKeychain, utils.MetathreadThreadVariant)\n\tassert.Nil(t, err)\n\n\t// Generate a thread ID from a different private key (changed the last char)\n\tmockPrivKeyHex := \"dd55f8921f90fdf31c6ef9ad86bd90605602fd7d32dc8ea66ab72deb6a82821c67730a6678566ead5911d71304854daddb1fe98a396551a4be01de65da01f3a8\"\n\tprivKeyBytes, _ := hex.DecodeString(mockPrivKeyHex)\n\tdiffPrivKey, _ := crypto.UnmarshalEd25519PrivateKey(privKeyBytes)\n\tnewMockKeychain := new(mocks.Keychain)\n\tnewMockKeychain.On(\n\t\t\"GetStoredKeyPairInLibP2PFormat\",\n\t).Return(diffPrivKey, nil, nil)\n\n\tdiffThreadID, err := utils.NewDeterministicThreadID(newMockKeychain, utils.MetathreadThreadVariant)\n\tassert.Nil(t, err)\n\n\tassert.Equal(t, threadID, threadIDCopy)\n\tassert.NotEqual(t, threadID, diffThreadID)\n}\n"
  },
  {
    "path": "core/util/address/PROTOCOL.md",
    "content": "# Protocols\n\n## Address derivation\n\nPublic keys are created using `ed25519` elliptic curve algorithm. An address is a hash of the public key to obtain a smaller length representation of it. To derive the address, we:\n\n1- Take the SHA3-256 hash of the public key (end up with 32 bytes string).\n\n2- Drop the first 14 bytes of the hash\n\n3- Convert the remaining 18 bytes to hex and prepend `0x`. (38 characters in total)\n\n"
  },
  {
    "path": "core/util/address/address.go",
    "content": "package address\n\nimport (\n\t\"encoding/hex\"\n\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"golang.org/x/crypto/sha3\"\n)\n\n// Returns the address representation of a public key\n// If the public key  is malformed it returns an empty string\nfunc DeriveAddress(pubKey crypto.PubKey) string {\n\tpubBytes, err := pubKey.Raw()\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\thf := sha3.New256()\n\thf.Write(pubBytes)\n\n\t// Get the hex representation of the SHA3-256 hash\n\thexHash := hex.EncodeToString(hf.Sum(nil))\n\n\t// Drop the first 14 bytes (28 characters)\n\ttrimmed := hexHash[28:]\n\n\treturn \"0x\" + trimmed\n}\n"
  },
  {
    "path": "core/util/paths.go",
    "content": "package util\n\nimport (\n\t\"os\"\n\ts \"strings\"\n\n\t\"github.com/mitchellh/go-homedir\"\n)\n\n// ResolvePath resolves a path into its full qualified path\n// alias like `~` is  expanded based on the current user\nfunc ResolvePath(path string) (string, error) {\n\tfullPath := path\n\tif home, err := homedir.Dir(); err == nil {\n\t\t// If the path contains ~, we replace it with the actual home directory\n\t\tfullPath = s.Replace(path, \"~\", home, -1)\n\t} else {\n\t\treturn \"\", err\n\t}\n\n\treturn fullPath, nil\n}\n\n// DirEntryExists check if the file or directory with the given path exits.\nfunc DirEntryExists(filename string) bool {\n\tfi, err := os.Lstat(filename)\n\tif fi != nil || (err != nil && !os.IsNotExist(err)) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "core/util/rlimit/rlimit_unix.go",
    "content": "// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris\n\npackage rlimit\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"syscall\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\n// Sets rlimit to the maximum allowed value in UNIX systems\nfunc SetRLimit() {\n\tvar rLimit syscall.Rlimit\n\n\terr := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)\n\tif err != nil {\n\t\tlog.Error(\"Error Getting Rlimit. Please run `ulimit -n 1000` from a privileged user to avoid issues when running the space daemon.\", err)\n\t\treturn\n\t}\n\tlog.Debug(fmt.Sprintf(\"Got Rlimit: Cur: %d, Max: %d\", rLimit.Cur, rLimit.Max))\n\n\t// Max allowed value is 10240 even when rLimit.Max can go beyond that\n\trLimit.Cur = uint64(math.Min(10240, float64(rLimit.Max)))\n\n\terr = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)\n\tif err != nil {\n\t\tlog.Error(\"Error setting Rlimit. Please run `ulimit -n 1000` from a privileged user to avoid issues when running the space daemon.\", err)\n\t\treturn\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Set Rlimit: Cur: %d, Max: %d\", rLimit.Cur, rLimit.Max))\n}\n"
  },
  {
    "path": "core/util/rlimit/rlimit_windows.go",
    "content": "package rlimit\n\n// Rlimit not supported on windows\nfunc SetRLimit() {\n\treturn\n}\n"
  },
  {
    "path": "core/vault/vault.go",
    "content": "package vault\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"crypto/sha512\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"golang.org/x/crypto/pbkdf2\"\n)\n\ntype vault struct {\n\tvaultAPIURL     string\n\tvaultSaltSecret string\n}\n\ntype VaultItemType string\n\n// Vault item types\nconst (\n\tPrivateKeyWithMnemonic VaultItemType = \"PrivateKeyWithMnemonic\"\n)\n\ntype VkVersion string\n\nconst (\n\tVkVersion1 VkVersion = \"V1\"\n)\n\n// AES requires key length equal to 16, 24 or 32 bytes\nconst vaultKeyLength = 32\n\ntype VaultItem struct {\n\tItemType VaultItemType\n\tValue    string\n}\n\ntype storeVaultRequest struct {\n\tVault string `json:\"vault\"`\n\tVsk   string `json:\"vsk\"`\n\tType  string `json:\"type\"`\n}\n\ntype StoredVault struct {\n\tVault string\n\tVsk   string\n}\n\ntype retrieveVaultRequest struct {\n\tVsk  string `json:\"vsk\"`\n\tType string `json:\"type\"`\n}\n\ntype retrieveVaultResponse struct {\n\tEncryptedVault string `json:\"encryptedVault\"`\n}\n\ntype Vault interface {\n\tStore(uuid string, passphrase string, backupType domain.KeyBackupType, apiToken string, items []VaultItem) (*StoredVault, error)\n\tRetrieve(uuid string, passphrase string, backupType domain.KeyBackupType) ([]VaultItem, error)\n}\n\nfunc New(vaultAPIURL string, vaultSaltSecret string) *vault {\n\treturn &vault{\n\t\tvaultAPIURL:     vaultAPIURL,\n\t\tvaultSaltSecret: vaultSaltSecret,\n\t}\n}\n\nfunc (v *vault) Store(uuid string, passphrase string, backupType domain.KeyBackupType, apiToken string, items []VaultItem) (*StoredVault, error) {\n\t// Generate vault file\n\tvf, err := json.Marshal(items)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Compute vault key\n\tvk := v.computeVk(uuid, passphrase, VkVersion1)\n\n\t// Encrypt vault file using vault key\n\tencVf, err := encrypt(vf, vk)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Compute vault service key\n\tvsk := v.computeVsk(vk, passphrase, VkVersion1)\n\n\t// Submit encrypted file and vsk to vault service\n\tstoreRequest := &storeVaultRequest{\n\t\tVault: base64.RawStdEncoding.EncodeToString(encVf),\n\t\tVsk:   base64.RawStdEncoding.EncodeToString(vsk),\n\t\tType:  domain.KeyBackupType(backupType).String(),\n\t}\n\treqJSON, err := json.Marshal(storeRequest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &http.Client{\n\t\tCheckRedirect: http.DefaultClient.CheckRedirect,\n\t}\n\treq, err := http.NewRequest(\"POST\", v.vaultAPIURL+\"/vaults\", bytes.NewBuffer(reqJSON))\n\treq.Header.Add(\"Authorization\", apiToken)\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\t_, err = parseAPIResponse(resp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := &StoredVault{\n\t\tVault: storeRequest.Vault,\n\t\tVsk:   storeRequest.Vsk,\n\t}\n\treturn result, nil\n}\n\nfunc (v *vault) Retrieve(uuid string, passphrase string, backupType domain.KeyBackupType) ([]VaultItem, error) {\n\t// Compute vault key\n\tvk := v.computeVk(uuid, passphrase, VkVersion1)\n\n\t// Compute vault service key\n\tvsk := v.computeVsk(vk, passphrase, VkVersion1)\n\n\t// Send retrieve request to vault service\n\treqJSON, err := json.Marshal(&retrieveVaultRequest{\n\t\tVsk:  base64.RawStdEncoding.EncodeToString(vsk),\n\t\tType: domain.KeyBackupType(backupType).String(),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresp, err := http.Post(\n\t\tv.vaultAPIURL+\"/vaults/\"+uuid,\n\t\t\"application/json\",\n\t\tbytes.NewBuffer(reqJSON),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := parseAPIResponse(resp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar parsedBody retrieveVaultResponse\n\terr = json.Unmarshal(body, &parsedBody)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Decrypt encrypted vault file\n\tencVfBase64 := parsedBody.EncryptedVault\n\tencVf, err := base64.RawStdEncoding.DecodeString(encVfBase64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvf, err := decrypt(encVf, vk)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar items []VaultItem\n\terr = json.Unmarshal(vf, &items)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn items, nil\n}\n\nfunc (v *vault) computeVk(uuid string, pass string, version VkVersion) []byte {\n\t// In the future, we can increase iterations by doing a switch and mapping\n\t// version to a given amount of iterations.\n\n\t// version = V1 defaults to 100.000 iterations\n\titerations := 100000\n\n\treturn pbkdf2.Key([]byte(pass), []byte(string(version)+v.vaultSaltSecret+uuid), iterations, vaultKeyLength, sha512.New)\n}\n\nfunc (v *vault) computeVsk(vk []byte, pass string, version VkVersion) []byte {\n\titerations := 100000\n\n\treturn pbkdf2.Key(vk, []byte(string(version)+v.vaultSaltSecret+pass), iterations, vaultKeyLength, sha512.New)\n}\n\nfunc encrypt(data []byte, key []byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnonce := make([]byte, gcm.NonceSize())\n\t_, err = io.ReadFull(rand.Reader, nonce)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn gcm.Seal(nonce, nonce, data, nil), nil\n}\n\nfunc decrypt(ciphertext []byte, key []byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(ciphertext) < gcm.NonceSize() {\n\t\treturn nil, errors.New(\"malformed ciphertext\")\n\t}\n\n\treturn gcm.Open(nil,\n\t\tciphertext[:gcm.NonceSize()],\n\t\tciphertext[gcm.NonceSize():],\n\t\tnil,\n\t)\n}\n\nfunc parseAPIResponse(resp *http.Response) ([]byte, error) {\n\tbody, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode < 200 || resp.StatusCode >= 400 {\n\t\tvar returnedErr domain.APIError\n\t\terr = json.Unmarshal(body, &returnedErr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif returnedErr.Message != \"\" {\n\t\t\treturn nil, errors.New(returnedErr.Message)\n\t\t}\n\n\t\treturn nil, errors.New(\"Unexpected API error\")\n\t}\n\n\treturn body, nil\n}\n"
  },
  {
    "path": "core/vault/vault_test.go",
    "content": "package vault_test\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/vault\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst testSaltSecret = \"someSecret\"\nconst testUuid = \"c907e7ef-7b36-4ab1-8a56-f788d7526a2c\"\nconst testPassphrase = \"banana1234\"\nconst testAPIToken = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdWJrZXkiOiJhZTRiMmFiNjU4ZmJiNzcyMjE0MDRkNjU3YzZiNzQyZDJlZjdjNTI2YjZhNWE5YzIwMGNjZjkzZmNhMWRjZTYzIiwidXVpZCI6ImM5MDdlN2VmLTdiMzYtNGFiMS04YTU2LWY3ODhkNzUyNmEyYyIsImlhdCI6MTU5ODI4NTA0MSwiZXhwIjoxNjAwODc3MDQxfQ.dgp8UhWCLjsU0SjxXwSb3g0jEurt2jAKPaY3B_eO-qE\"\n\nfunc TestVault_StoreAndRetrieve(t *testing.T) {\n\ttestVaultItems := []vault.VaultItem{\n\t\t{\n\t\t\tItemType: vault.PrivateKeyWithMnemonic,\n\t\t\tValue:    \"SomePrivateKey\",\n\t\t},\n\t}\n\n\tstoreVaultMock := func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = w.Write([]byte(`{}`))\n\t}\n\n\ttestBackupType := domain.PASSWORD\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/vaults\", storeVaultMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\tserver := serverMock()\n\tdefer server.Close()\n\n\tv := vault.New(\n\t\t// \"https://f4nmmmkstb.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t\ttestSaltSecret,\n\t)\n\n\tstoreRequest, err := v.Store(testUuid, testPassphrase, testBackupType, testAPIToken, testVaultItems)\n\n\tassert.Nil(t, err)\n\tif err != nil {\n\t\treturn\n\t}\n\tassert.NotNil(t, storeRequest)\n\tassert.NotNil(t, storeRequest.Vault)\n\tassert.NotEqual(t, \"\", storeRequest.Vault)\n\tassert.NotNil(t, storeRequest.Vsk)\n\tassert.NotEqual(t, \"\", storeRequest.Vsk)\n\n\tretrieveVaultMock := func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = w.Write([]byte(`{\"encryptedVault\": \"` + storeRequest.Vault + `\"}`))\n\t}\n\n\tserverMock2 := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/vaults/\"+testUuid, retrieveVaultMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\tserver2 := serverMock2()\n\tdefer server2.Close()\n\n\tv2 := vault.New(\n\t\t// \"https://f4nmmmkstb.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver2.URL,\n\t\ttestSaltSecret,\n\t)\n\n\tretrievedItems, err := v2.Retrieve(testUuid, testPassphrase, domain.PASSWORD)\n\tassert.Nil(t, err)\n\tif err != nil {\n\t\treturn\n\t}\n\tassert.NotNil(t, retrievedItems)\n\n\t// Assert response matches what we initially vaulted\n\tassert.Equal(t, testVaultItems[0].ItemType, retrievedItems[0].ItemType)\n\tassert.Equal(t, testVaultItems[0].Value, retrievedItems[0].Value)\n}\n\nfunc TestVault_StoreServerError(t *testing.T) {\n\ttestVaultItems := []vault.VaultItem{\n\t\t{\n\t\t\tItemType: vault.PrivateKeyWithMnemonic,\n\t\t\tValue:    \"SomePrivateKey\",\n\t\t},\n\t}\n\n\ttestBackupType := domain.PASSWORD\n\n\tstoreVaultMock := func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t_, _ = w.Write([]byte(`{ \"message\": \"Unauthorized Error: Authorization token is invalid.\"}`))\n\t}\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/vaults\", storeVaultMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\tserver := serverMock()\n\tdefer server.Close()\n\n\tv := vault.New(\n\t\t// \"https://f4nmmmkstb.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t\ttestSaltSecret,\n\t)\n\n\tstoreRequest, err := v.Store(testUuid, testPassphrase, testBackupType, testAPIToken, testVaultItems)\n\n\tassert.NotNil(t, err)\n\tassert.Nil(t, storeRequest)\n}\n\nfunc TestVault_RetrieveServerError(t *testing.T) {\n\tretrieveVaultMock := func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t_, _ = w.Write([]byte(`{ \"message\": \"Unauthorized Error: Incorrect uuid or password.\"}`))\n\t}\n\n\tserverMock := func() *httptest.Server {\n\t\thandler := http.NewServeMux()\n\t\thandler.HandleFunc(\"/vaults/\"+testUuid, retrieveVaultMock)\n\n\t\tsrv := httptest.NewServer(handler)\n\n\t\treturn srv\n\t}\n\tserver := serverMock()\n\tdefer server.Close()\n\n\tv := vault.New(\n\t\t// \"https://f4nmmmkstb.execute-api.us-west-2.amazonaws.com/dev\", // UNCOMMENT TO TEST REAL SERVER\n\t\tserver.URL,\n\t\ttestSaltSecret,\n\t)\n\n\tretrievedItems, err := v.Retrieve(testUuid, testPassphrase, domain.PASSWORD)\n\n\tassert.NotNil(t, err)\n\tassert.Nil(t, retrievedItems)\n}\n"
  },
  {
    "path": "core/watcher/blacklist.go",
    "content": "//+build !windows\n\npackage watcher\n\nimport (\n\t\"os\"\n)\n\n// isBlacklisted return true if the file or path is not a supported entry\n// to trigger file watcher event handler\nfunc isBlacklisted(path string, fileInfo os.FileInfo) bool {\n\treturn fileInfo.Name()[0:1] == \".\"\n}\n"
  },
  {
    "path": "core/watcher/blacklist_windows.go",
    "content": "package watcher\n\nimport (\n\t\"os\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\n// isBlacklisted return true if the file or path is not a supported entry\n// to trigger file watcher event handler\nfunc isBlacklisted(path string, fileInfo os.FileInfo) bool {\n\tpointer, err := windows.UTF16PtrFromString(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\tattributes, err := windows.GetFileAttributes(pointer)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn attributes&windows.FILE_ATTRIBUTE_HIDDEN != 0\n}\n"
  },
  {
    "path": "core/watcher/handler.go",
    "content": "package watcher\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\n// EventHandler\ntype EventHandler interface {\n\tOnCreate(ctx context.Context, path string, fileInfo os.FileInfo)\n\tOnRemove(ctx context.Context, path string, fileInfo os.FileInfo)\n\tOnWrite(ctx context.Context, path string, fileInfo os.FileInfo)\n\tOnRename(ctx context.Context, path string, fileInfo os.FileInfo, oldPath string)\n\tOnMove(ctx context.Context, path string, fileInfo os.FileInfo, oldPath string)\n}\n\n// Implements EventHandler and defaults to logging actions performed\ntype defaultWatcherHandler struct{}\n\nfunc (h *defaultWatcherHandler) OnCreate(\n\tctx context.Context,\n\tpath string,\n\tfileInfo os.FileInfo,\n) {\n\tlog.Info(\"Default Watcher Handler: OnCreate\", fmt.Sprintf(\"path:%s\", path), fmt.Sprintf(\"fileInfo:%v\", fileInfo))\n}\n\nfunc (h *defaultWatcherHandler) OnRemove(\n\tctx context.Context,\n\tpath string,\n\tfileInfo os.FileInfo,\n) {\n\tlog.Info(\"Default Watcher Handler: OnRemove\", fmt.Sprintf(\"path:%s\", path), fmt.Sprintf(\"fileInfo:%v\", fileInfo))\n}\n\nfunc (h *defaultWatcherHandler) OnWrite(\n\tctx context.Context,\n\tpath string,\n\tfileInfo os.FileInfo,\n) {\n\tlog.Info(\"Default Watcher Handler: OnWrite\", fmt.Sprintf(\"path:%s\", path), fmt.Sprintf(\"fileInfo:%v\", fileInfo))\n}\n\nfunc (h *defaultWatcherHandler) OnRename(\n\tctx context.Context,\n\tpath string,\n\tfileInfo os.FileInfo,\n\toldPath string,\n) {\n\tlog.Info(\n\t\t\"Default Watcher Handler: OnRename\",\n\t\tfmt.Sprintf(\"path:%s\", path),\n\t\tfmt.Sprintf(\"fileInfo:%v\", fileInfo),\n\t\tfmt.Sprintf(\"path:%s\", oldPath),\n\t)\n}\n\nfunc (h *defaultWatcherHandler) OnMove(\n\tctx context.Context,\n\tpath string,\n\tfileInfo os.FileInfo,\n\toldPath string,\n) {\n\tlog.Info(\n\t\t\"Default Watcher Handler: OnMove\",\n\t\tfmt.Sprintf(\"path:%s\", path),\n\t\tfmt.Sprintf(\"fileInfo:%v\", fileInfo),\n\t\tfmt.Sprintf(\"path:%s\", oldPath),\n\t)\n}\n"
  },
  {
    "path": "core/watcher/options.go",
    "content": "package watcher\n\ntype watcherOptions struct {\n\tpaths []string\n}\n\n// Option configuration for the FileWatcher\n// Use exported Option factory functions\ntype Option func(option *watcherOptions)\n\n// WithPaths configures the list of paths the file watcher would be watching recursively.\n// For best results do not include two paths withing the same directory\nfunc WithPaths(path ...string) Option {\n\treturn func(option *watcherOptions) {\n\t\tfor _, p := range path {\n\t\t\toption.paths = append(option.paths, p)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "core/watcher/watcher.go",
    "content": "package watcher\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\ts \"strings\"\n\t\"sync\"\n\n\tfsutils \"github.com/FleekHQ/space-daemon/core/space/services\"\n\t\"github.com/mitchellh/go-homedir\"\n\n\t\"time\"\n\n\t\"github.com/radovskyb/watcher\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nvar (\n\tErrFolderPathNotFound = errors.New(\"could not find a folder path for watcher\")\n)\n\ntype FolderWatcher interface {\n\tRegisterHandler(handler EventHandler)\n\tAddFile(path string) error\n\tWatch(ctx context.Context) error\n\tClose()\n}\n\ntype folderWatcher struct {\n\tw *watcher.Watcher\n\n\tlock        sync.Mutex\n\tpublishLock sync.RWMutex\n\toptions     watcherOptions\n\tstarted     bool\n\tclosed      bool\n\thandlers    []EventHandler\n}\n\n// New creates an new instance of folder watcher\nfunc New(configs ...Option) (*folderWatcher, error) {\n\toptions := watcherOptions{}\n\tfor _, config := range configs {\n\t\tconfig(&options)\n\t}\n\n\tw := watcher.New()\n\n\tfor _, path := range options.paths {\n\t\tif home, err := homedir.Dir(); err == nil {\n\t\t\t// If the root directory contains ~, we replace it with the actual home directory\n\t\t\tpath = s.Replace(path, \"~\", home, -1)\n\t\t}\n\n\t\tif path == \"\" {\n\t\t\tlog.Fatal(ErrFolderPathNotFound)\n\t\t\treturn nil, ErrFolderPathNotFound\n\t\t}\n\n\t\terr := w.AddRecursive(path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &folderWatcher{\n\t\tw:       w,\n\t\toptions: options,\n\t}, nil\n}\n\nfunc (fw *folderWatcher) RegisterHandler(handler EventHandler) {\n\tfw.publishLock.Lock()\n\tdefer fw.publishLock.Unlock()\n\tfw.handlers = append(fw.handlers, handler)\n}\n\nfunc (fw *folderWatcher) AddFile(path string) error {\n\tif fsutils.IsPathDir(path) {\n\t\treturn errors.New(fmt.Sprintf(\"unable to watch path %s folder is not supporter\", path))\n\t}\n\terr := fw.w.Add(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn err\n}\n\n// Watch will start listening of changes on the folderWatcher path and trigger the handler with any update events\n// This is a block operation\nfunc (fw *folderWatcher) Watch(ctx context.Context) error {\n\tfw.setToStarted()\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-fw.w.Closed:\n\t\t\t\tlog.Debug(\"Watcher graceful shutdown triggered\")\n\t\t\t\treturn\n\t\t\tcase <-ctx.Done():\n\t\t\t\tfw.Close()\n\t\t\tcase event, ok := <-fw.w.Event:\n\t\t\t\tif ok {\n\t\t\t\t\tif len(fw.handlers) == 0 {\n\t\t\t\t\t\tfw.publishEventToHandler(ctx, &defaultWatcherHandler{}, event)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfw.publishEvent(ctx, event)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase err, ok := <-fw.w.Error:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlog.Fatal(err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tlog.Debug(\"Starting watcher\", fmt.Sprintf(\"filePath:%s\", fw.options.paths))\n\t// This is blocking\n\terr := fw.w.Start(time.Millisecond * 100)\n\tfw.started = false\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (fw *folderWatcher) setToStarted() {\n\tfw.lock.Lock()\n\tdefer fw.lock.Unlock()\n\tif fw.started {\n\t\treturn\n\t}\n\tfw.started = true\n}\n\nfunc (fw *folderWatcher) publishEvent(ctx context.Context, event watcher.Event) {\n\tfw.publishLock.RLock()\n\tdefer fw.publishLock.RUnlock()\n\n\tfor _, handler := range fw.handlers {\n\t\tfw.publishEventToHandler(ctx, handler, event)\n\t}\n}\n\nfunc (fw *folderWatcher) publishEventToHandler(\n\tctx context.Context,\n\thandler EventHandler,\n\tevent watcher.Event,\n) {\n\tif isBlacklisted(event.Path, event.FileInfo) {\n\t\tlog.Debug(\"Skipping blacklisted file/folder event\")\n\t\treturn\n\t}\n\n\tswitch event.Op {\n\tcase watcher.Create:\n\t\thandler.OnCreate(ctx, event.Path, event.FileInfo)\n\tcase watcher.Remove:\n\t\thandler.OnRemove(ctx, event.Path, event.FileInfo)\n\tcase watcher.Write:\n\t\thandler.OnWrite(ctx, event.Path, event.FileInfo)\n\tcase watcher.Rename:\n\t\thandler.OnRename(ctx, event.Path, event.FileInfo, event.OldPath)\n\tcase watcher.Move:\n\t\thandler.OnMove(ctx, event.Path, event.FileInfo, event.OldPath)\n\t}\n}\n\n// Close will stop the watching operation and unblock watch calls\nfunc (fw *folderWatcher) Close() {\n\tfw.lock.Lock()\n\tdefer fw.lock.Unlock()\n\n\tif !fw.started || fw.closed {\n\t\treturn\n\t}\n\n\tfw.closed = true\n\tfw.w.Close()\n}\n\nfunc (fw *folderWatcher) Shutdown() error {\n\tfw.Close()\n\treturn nil\n}\n"
  },
  {
    "path": "core/watcher/watcher_test.go",
    "content": "package watcher\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/mock\"\n\n\tw \"github.com/radovskyb/watcher\"\n)\n\n// TODO: Use mockery to create mocks interface implementations\ntype handlerMock struct {\n\tmock.Mock\n}\n\nfunc (h *handlerMock) OnCreate(ctx context.Context, path string, fileInfo os.FileInfo) {\n\th.Called(ctx, path, fileInfo)\n}\n\nfunc (h *handlerMock) OnRemove(ctx context.Context, path string, fileInfo os.FileInfo) {\n\th.Called(ctx, path, fileInfo)\n}\n\nfunc (h *handlerMock) OnWrite(ctx context.Context, path string, fileInfo os.FileInfo) {\n\th.Called(ctx, path, fileInfo)\n}\n\nfunc (h *handlerMock) OnRename(ctx context.Context, path string, fileInfo os.FileInfo, oldPath string) {\n\th.Called(ctx, path, fileInfo, oldPath)\n}\n\nfunc (h *handlerMock) OnMove(ctx context.Context, path string, fileInfo os.FileInfo, oldPath string) {\n\th.Called(ctx, path, fileInfo, oldPath)\n}\n\nfunc isTriggeredEvent(info os.FileInfo) bool {\n\treturn info.Name() == \"triggered event\"\n}\n\nfunc startWatcher(t *testing.T, watchPaths ...string) (context.Context, FolderWatcher, error) {\n\tctx := context.Background()\n\twatcher, err := New(WithPaths(watchPaths...))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// execute\n\tgo func() {\n\t\terr = watcher.Watch(ctx)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}()\n\n\treturn ctx, watcher, nil\n}\n\nfunc TestFolderWatcher_Watch_Triggers_Handler_OnCreate(t *testing.T) {\n\t// setup\n\t_, watcher, err := startWatcher(t)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\thandler := new(handlerMock)\n\thandler.On(\"OnCreate\", mock.Anything, \"-\", mock.MatchedBy(isTriggeredEvent)).Return()\n\twatcher.RegisterHandler(handler)\n\n\t// trigger event\n\twatcher.(*folderWatcher).w.TriggerEvent(w.Create, nil)\n\n\t// wait a few ms for async event to trigger handler\n\t<-time.After(time.Millisecond * 100)\n\n\t// assert\n\thandler.AssertNumberOfCalls(t, \"OnCreate\", 1)\n\thandler.AssertExpectations(t)\n\n\t// cleanup\n\twatcher.Close()\n}\n\nfunc TestFolderWatcher_Watch_Triggers_Handler_OnRemove(t *testing.T) {\n\t// setup\n\t_, watcher, err := startWatcher(t)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\thandler := new(handlerMock)\n\thandler.On(\"OnRemove\", mock.Anything, \"-\", mock.MatchedBy(isTriggeredEvent)).Return()\n\twatcher.RegisterHandler(handler)\n\n\t// trigger event\n\twatcher.(*folderWatcher).w.TriggerEvent(w.Remove, nil)\n\n\t// wait a few ms for async event to trigger handler\n\t<-time.After(time.Millisecond * 100)\n\n\t// assert\n\thandler.AssertNumberOfCalls(t, \"OnRemove\", 1)\n\thandler.AssertExpectations(t)\n\n\t// cleanup\n\twatcher.Close()\n}\n"
  },
  {
    "path": "coverage/.gitkeep",
    "content": ""
  },
  {
    "path": "devtools/googleapis/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "devtools/googleapis/README.grpc-gateway",
    "content": "Google APIs\n============\n\nProject: Google APIs\nURL: https://github.com/google/googleapis\nRevision: 3544ab16c3342d790b00764251e348705991ea4b\nLicense: Apache License 2.0\n\n\nImported Files\n---------------\n\n- google/api/annotations.proto\n- google/api/http.proto\n- google/api/httpbody.proto\n\n\nGenerated Files\n----------------\n\nThey are generated from the .proto files by protoc-gen-go.\n- google/api/annotations.pb.go\n- google/api/http.pb.go\n"
  },
  {
    "path": "devtools/googleapis/google/api/annotations.proto",
    "content": "// Copyright (c) 2015, Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/api/http.proto\";\nimport \"google/protobuf/descriptor.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"AnnotationsProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\nextend google.protobuf.MethodOptions {\n  // See `HttpRule`.\n  HttpRule http = 72295728;\n}\n"
  },
  {
    "path": "devtools/googleapis/google/api/http.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"HttpProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\n\n// Defines the HTTP configuration for an API service. It contains a list of\n// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method\n// to one or more HTTP REST API methods.\nmessage Http {\n  // A list of HTTP configuration rules that apply to individual API methods.\n  //\n  // **NOTE:** All service configuration rules follow \"last one wins\" order.\n  repeated HttpRule rules = 1;\n\n  // When set to true, URL path parmeters will be fully URI-decoded except in\n  // cases of single segment matches in reserved expansion, where \"%2F\" will be\n  // left encoded.\n  //\n  // The default behavior is to not decode RFC 6570 reserved characters in multi\n  // segment matches.\n  bool fully_decode_reserved_expansion = 2;\n}\n\n// `HttpRule` defines the mapping of an RPC method to one or more HTTP\n// REST API methods. The mapping specifies how different portions of the RPC\n// request message are mapped to URL path, URL query parameters, and\n// HTTP request body. The mapping is typically specified as an\n// `google.api.http` annotation on the RPC method,\n// see \"google/api/annotations.proto\" for details.\n//\n// The mapping consists of a field specifying the path template and\n// method kind.  The path template can refer to fields in the request\n// message, as in the example below which describes a REST GET\n// operation on a resource collection of messages:\n//\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http).get = \"/v1/messages/{message_id}/{sub.subfield}\";\n//       }\n//     }\n//     message GetMessageRequest {\n//       message SubMessage {\n//         string subfield = 1;\n//       }\n//       string message_id = 1; // mapped to the URL\n//       SubMessage sub = 2;    // `sub.subfield` is url-mapped\n//     }\n//     message Message {\n//       string text = 1; // content of the resource\n//     }\n//\n// The same http annotation can alternatively be expressed inside the\n// `GRPC API Configuration` YAML file.\n//\n//     http:\n//       rules:\n//         - selector: <proto_package_name>.Messaging.GetMessage\n//           get: /v1/messages/{message_id}/{sub.subfield}\n//\n// This definition enables an automatic, bidrectional mapping of HTTP\n// JSON to RPC. Example:\n//\n// HTTP | RPC\n// -----|-----\n// `GET /v1/messages/123456/foo`  | `GetMessage(message_id: \"123456\" sub: SubMessage(subfield: \"foo\"))`\n//\n// In general, not only fields but also field paths can be referenced\n// from a path pattern. Fields mapped to the path pattern cannot be\n// repeated and must have a primitive (non-message) type.\n//\n// Any fields in the request message which are not bound by the path\n// pattern automatically become (optional) HTTP query\n// parameters. Assume the following definition of the request message:\n//\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http).get = \"/v1/messages/{message_id}\";\n//       }\n//     }\n//     message GetMessageRequest {\n//       message SubMessage {\n//         string subfield = 1;\n//       }\n//       string message_id = 1; // mapped to the URL\n//       int64 revision = 2;    // becomes a parameter\n//       SubMessage sub = 3;    // `sub.subfield` becomes a parameter\n//     }\n//\n//\n// This enables a HTTP JSON to RPC mapping as below:\n//\n// HTTP | RPC\n// -----|-----\n// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: \"123456\" revision: 2 sub: SubMessage(subfield: \"foo\"))`\n//\n// Note that fields which are mapped to HTTP parameters must have a\n// primitive type or a repeated primitive type. Message types are not\n// allowed. In the case of a repeated type, the parameter can be\n// repeated in the URL, as in `...?param=A&param=B`.\n//\n// For HTTP method kinds which allow a request body, the `body` field\n// specifies the mapping. Consider a REST update method on the\n// message resource collection:\n//\n//\n//     service Messaging {\n//       rpc UpdateMessage(UpdateMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//           put: \"/v1/messages/{message_id}\"\n//           body: \"message\"\n//         };\n//       }\n//     }\n//     message UpdateMessageRequest {\n//       string message_id = 1; // mapped to the URL\n//       Message message = 2;   // mapped to the body\n//     }\n//\n//\n// The following HTTP JSON to RPC mapping is enabled, where the\n// representation of the JSON in the request body is determined by\n// protos JSON encoding:\n//\n// HTTP | RPC\n// -----|-----\n// `PUT /v1/messages/123456 { \"text\": \"Hi!\" }` | `UpdateMessage(message_id: \"123456\" message { text: \"Hi!\" })`\n//\n// The special name `*` can be used in the body mapping to define that\n// every field not bound by the path template should be mapped to the\n// request body.  This enables the following alternative definition of\n// the update method:\n//\n//     service Messaging {\n//       rpc UpdateMessage(Message) returns (Message) {\n//         option (google.api.http) = {\n//           put: \"/v1/messages/{message_id}\"\n//           body: \"*\"\n//         };\n//       }\n//     }\n//     message Message {\n//       string message_id = 1;\n//       string text = 2;\n//     }\n//\n//\n// The following HTTP JSON to RPC mapping is enabled:\n//\n// HTTP | RPC\n// -----|-----\n// `PUT /v1/messages/123456 { \"text\": \"Hi!\" }` | `UpdateMessage(message_id: \"123456\" text: \"Hi!\")`\n//\n// Note that when using `*` in the body mapping, it is not possible to\n// have HTTP parameters, as all fields not bound by the path end in\n// the body. This makes this option more rarely used in practice of\n// defining REST APIs. The common usage of `*` is in custom methods\n// which don't use the URL at all for transferring data.\n//\n// It is possible to define multiple HTTP methods for one RPC by using\n// the `additional_bindings` option. Example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//           get: \"/v1/messages/{message_id}\"\n//           additional_bindings {\n//             get: \"/v1/users/{user_id}/messages/{message_id}\"\n//           }\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       string message_id = 1;\n//       string user_id = 2;\n//     }\n//\n//\n// This enables the following two alternative HTTP JSON to RPC\n// mappings:\n//\n// HTTP | RPC\n// -----|-----\n// `GET /v1/messages/123456` | `GetMessage(message_id: \"123456\")`\n// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: \"me\" message_id: \"123456\")`\n//\n// # Rules for HTTP mapping\n//\n// The rules for mapping HTTP path, query parameters, and body fields\n// to the request message are as follows:\n//\n// 1. The `body` field specifies either `*` or a field path, or is\n//    omitted. If omitted, it indicates there is no HTTP request body.\n// 2. Leaf fields (recursive expansion of nested messages in the\n//    request) can be classified into three types:\n//     (a) Matched in the URL template.\n//     (b) Covered by body (if body is `*`, everything except (a) fields;\n//         else everything under the body field)\n//     (c) All other fields.\n// 3. URL query parameters found in the HTTP request are mapped to (c) fields.\n// 4. Any body sent with an HTTP request can contain only (b) fields.\n//\n// The syntax of the path template is as follows:\n//\n//     Template = \"/\" Segments [ Verb ] ;\n//     Segments = Segment { \"/\" Segment } ;\n//     Segment  = \"*\" | \"**\" | LITERAL | Variable ;\n//     Variable = \"{\" FieldPath [ \"=\" Segments ] \"}\" ;\n//     FieldPath = IDENT { \".\" IDENT } ;\n//     Verb     = \":\" LITERAL ;\n//\n// The syntax `*` matches a single path segment. The syntax `**` matches zero\n// or more path segments, which must be the last part of the path except the\n// `Verb`. The syntax `LITERAL` matches literal text in the path.\n//\n// The syntax `Variable` matches part of the URL path as specified by its\n// template. A variable template must not contain other variables. If a variable\n// matches a single path segment, its template may be omitted, e.g. `{var}`\n// is equivalent to `{var=*}`.\n//\n// If a variable contains exactly one path segment, such as `\"{var}\"` or\n// `\"{var=*}\"`, when such a variable is expanded into a URL path, all characters\n// except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the\n// Discovery Document as `{var}`.\n//\n// If a variable contains one or more path segments, such as `\"{var=foo/*}\"`\n// or `\"{var=**}\"`, when such a variable is expanded into a URL path, all\n// characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables\n// show up in the Discovery Document as `{+var}`.\n//\n// NOTE: While the single segment variable matches the semantics of\n// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2\n// Simple String Expansion, the multi segment variable **does not** match\n// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion\n// does not expand special characters like `?` and `#`, which would lead\n// to invalid URLs.\n//\n// NOTE: the field paths in variables and in the `body` must not refer to\n// repeated fields or map fields.\nmessage HttpRule {\n  // Selects methods to which this rule applies.\n  //\n  // Refer to [selector][google.api.DocumentationRule.selector] for syntax details.\n  string selector = 1;\n\n  // Determines the URL pattern is matched by this rules. This pattern can be\n  // used with any of the {get|put|post|delete|patch} methods. A custom method\n  // can be defined using the 'custom' field.\n  oneof pattern {\n    // Used for listing and getting information about resources.\n    string get = 2;\n\n    // Used for updating a resource.\n    string put = 3;\n\n    // Used for creating a resource.\n    string post = 4;\n\n    // Used for deleting a resource.\n    string delete = 5;\n\n    // Used for updating a resource.\n    string patch = 6;\n\n    // The custom pattern is used for specifying an HTTP method that is not\n    // included in the `pattern` field, such as HEAD, or \"*\" to leave the\n    // HTTP method unspecified for this rule. The wild-card rule is useful\n    // for services that provide content to Web (HTML) clients.\n    CustomHttpPattern custom = 8;\n  }\n\n  // The name of the request field whose value is mapped to the HTTP body, or\n  // `*` for mapping all fields not captured by the path pattern to the HTTP\n  // body. NOTE: the referred field must not be a repeated field and must be\n  // present at the top-level of request message type.\n  string body = 7;\n\n  // Optional. The name of the response field whose value is mapped to the HTTP\n  // body of response. Other response fields are ignored. When\n  // not set, the response message will be used as HTTP body of response.\n  string response_body = 12;\n\n  // Additional HTTP bindings for the selector. Nested bindings must\n  // not contain an `additional_bindings` field themselves (that is,\n  // the nesting may only be one level deep).\n  repeated HttpRule additional_bindings = 11;\n}\n\n// A custom pattern is used for defining custom HTTP verb.\nmessage CustomHttpPattern {\n  // The name of this custom HTTP verb.\n  string kind = 1;\n\n  // The path matched by this custom verb.\n  string path = 2;\n}\n"
  },
  {
    "path": "devtools/googleapis/google/api/httpbody.proto",
    "content": "// Copyright 2018 Google LLC.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/protobuf/any.proto\";\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/httpbody;httpbody\";\noption java_multiple_files = true;\noption java_outer_classname = \"HttpBodyProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\n// Message that represents an arbitrary HTTP body. It should only be used for\n// payload formats that can't be represented as JSON, such as raw binary or\n// an HTML page.\n//\n//\n// This message can be used both in streaming and non-streaming API methods in\n// the request as well as the response.\n//\n// It can be used as a top-level request field, which is convenient if one\n// wants to extract parameters from either the URL or HTTP template into the\n// request fields and also want access to the raw HTTP body.\n//\n// Example:\n//\n//     message GetResourceRequest {\n//       // A unique request id.\n//       string request_id = 1;\n//\n//       // The raw HTTP body is bound to this field.\n//       google.api.HttpBody http_body = 2;\n//     }\n//\n//     service ResourceService {\n//       rpc GetResource(GetResourceRequest) returns (google.api.HttpBody);\n//       rpc UpdateResource(google.api.HttpBody) returns\n//       (google.protobuf.Empty);\n//     }\n//\n// Example with streaming methods:\n//\n//     service CaldavService {\n//       rpc GetCalendar(stream google.api.HttpBody)\n//         returns (stream google.api.HttpBody);\n//       rpc UpdateCalendar(stream google.api.HttpBody)\n//         returns (stream google.api.HttpBody);\n//     }\n//\n// Use of this type only changes how the request and response bodies are\n// handled, all other features will continue to work unchanged.\nmessage HttpBody {\n  // The HTTP Content-Type header value specifying the content type of the body.\n  string content_type = 1;\n\n  // The HTTP request/response body as raw binary.\n  bytes data = 2;\n\n  // Application specific response metadata. Must be set in the first response\n  // for streaming APIs.\n  repeated google.protobuf.Any extensions = 3;\n}"
  },
  {
    "path": "devtools/googleapis/google/rpc/code.proto",
    "content": "// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.rpc;\n\noption go_package = \"google.golang.org/genproto/googleapis/rpc/code;code\";\noption java_multiple_files = true;\noption java_outer_classname = \"CodeProto\";\noption java_package = \"com.google.rpc\";\noption objc_class_prefix = \"RPC\";\n\n\n// The canonical error codes for Google APIs.\n//\n//\n// Sometimes multiple error codes may apply.  Services should return\n// the most specific error code that applies.  For example, prefer\n// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply.\n// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`.\nenum Code {\n  // Not an error; returned on success\n  //\n  // HTTP Mapping: 200 OK\n  OK = 0;\n\n  // The operation was cancelled, typically by the caller.\n  //\n  // HTTP Mapping: 499 Client Closed Request\n  CANCELLED = 1;\n\n  // Unknown error.  For example, this error may be returned when\n  // a `Status` value received from another address space belongs to\n  // an error space that is not known in this address space.  Also\n  // errors raised by APIs that do not return enough error information\n  // may be converted to this error.\n  //\n  // HTTP Mapping: 500 Internal Server Error\n  UNKNOWN = 2;\n\n  // The client specified an invalid argument.  Note that this differs\n  // from `FAILED_PRECONDITION`.  `INVALID_ARGUMENT` indicates arguments\n  // that are problematic regardless of the state of the system\n  // (e.g., a malformed file name).\n  //\n  // HTTP Mapping: 400 Bad Request\n  INVALID_ARGUMENT = 3;\n\n  // The deadline expired before the operation could complete. For operations\n  // that change the state of the system, this error may be returned\n  // even if the operation has completed successfully.  For example, a\n  // successful response from a server could have been delayed long\n  // enough for the deadline to expire.\n  //\n  // HTTP Mapping: 504 Gateway Timeout\n  DEADLINE_EXCEEDED = 4;\n\n  // Some requested entity (e.g., file or directory) was not found.\n  //\n  // Note to server developers: if a request is denied for an entire class\n  // of users, such as gradual feature rollout or undocumented whitelist,\n  // `NOT_FOUND` may be used. If a request is denied for some users within\n  // a class of users, such as user-based access control, `PERMISSION_DENIED`\n  // must be used.\n  //\n  // HTTP Mapping: 404 Not Found\n  NOT_FOUND = 5;\n\n  // The entity that a client attempted to create (e.g., file or directory)\n  // already exists.\n  //\n  // HTTP Mapping: 409 Conflict\n  ALREADY_EXISTS = 6;\n\n  // The caller does not have permission to execute the specified\n  // operation. `PERMISSION_DENIED` must not be used for rejections\n  // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`\n  // instead for those errors). `PERMISSION_DENIED` must not be\n  // used if the caller can not be identified (use `UNAUTHENTICATED`\n  // instead for those errors). This error code does not imply the\n  // request is valid or the requested entity exists or satisfies\n  // other pre-conditions.\n  //\n  // HTTP Mapping: 403 Forbidden\n  PERMISSION_DENIED = 7;\n\n  // The request does not have valid authentication credentials for the\n  // operation.\n  //\n  // HTTP Mapping: 401 Unauthorized\n  UNAUTHENTICATED = 16;\n\n  // Some resource has been exhausted, perhaps a per-user quota, or\n  // perhaps the entire file system is out of space.\n  //\n  // HTTP Mapping: 429 Too Many Requests\n  RESOURCE_EXHAUSTED = 8;\n\n  // The operation was rejected because the system is not in a state\n  // required for the operation's execution.  For example, the directory\n  // to be deleted is non-empty, an rmdir operation is applied to\n  // a non-directory, etc.\n  //\n  // Service implementors can use the following guidelines to decide\n  // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:\n  //  (a) Use `UNAVAILABLE` if the client can retry just the failing call.\n  //  (b) Use `ABORTED` if the client should retry at a higher level\n  //      (e.g., when a client-specified test-and-set fails, indicating the\n  //      client should restart a read-modify-write sequence).\n  //  (c) Use `FAILED_PRECONDITION` if the client should not retry until\n  //      the system state has been explicitly fixed.  E.g., if an \"rmdir\"\n  //      fails because the directory is non-empty, `FAILED_PRECONDITION`\n  //      should be returned since the client should not retry unless\n  //      the files are deleted from the directory.\n  //\n  // HTTP Mapping: 400 Bad Request\n  FAILED_PRECONDITION = 9;\n\n  // The operation was aborted, typically due to a concurrency issue such as\n  // a sequencer check failure or transaction abort.\n  //\n  // See the guidelines above for deciding between `FAILED_PRECONDITION`,\n  // `ABORTED`, and `UNAVAILABLE`.\n  //\n  // HTTP Mapping: 409 Conflict\n  ABORTED = 10;\n\n  // The operation was attempted past the valid range.  E.g., seeking or\n  // reading past end-of-file.\n  //\n  // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may\n  // be fixed if the system state changes. For example, a 32-bit file\n  // system will generate `INVALID_ARGUMENT` if asked to read at an\n  // offset that is not in the range [0,2^32-1], but it will generate\n  // `OUT_OF_RANGE` if asked to read from an offset past the current\n  // file size.\n  //\n  // There is a fair bit of overlap between `FAILED_PRECONDITION` and\n  // `OUT_OF_RANGE`.  We recommend using `OUT_OF_RANGE` (the more specific\n  // error) when it applies so that callers who are iterating through\n  // a space can easily look for an `OUT_OF_RANGE` error to detect when\n  // they are done.\n  //\n  // HTTP Mapping: 400 Bad Request\n  OUT_OF_RANGE = 11;\n\n  // The operation is not implemented or is not supported/enabled in this\n  // service.\n  //\n  // HTTP Mapping: 501 Not Implemented\n  UNIMPLEMENTED = 12;\n\n  // Internal errors.  This means that some invariants expected by the\n  // underlying system have been broken.  This error code is reserved\n  // for serious errors.\n  //\n  // HTTP Mapping: 500 Internal Server Error\n  INTERNAL = 13;\n\n  // The service is currently unavailable.  This is most likely a\n  // transient condition, which can be corrected by retrying with\n  // a backoff.\n  //\n  // See the guidelines above for deciding between `FAILED_PRECONDITION`,\n  // `ABORTED`, and `UNAVAILABLE`.\n  //\n  // HTTP Mapping: 503 Service Unavailable\n  UNAVAILABLE = 14;\n\n  // Unrecoverable data loss or corruption.\n  //\n  // HTTP Mapping: 500 Internal Server Error\n  DATA_LOSS = 15;\n}\n"
  },
  {
    "path": "devtools/googleapis/google/rpc/error_details.proto",
    "content": "// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.rpc;\n\nimport \"google/protobuf/duration.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/rpc/errdetails;errdetails\";\noption java_multiple_files = true;\noption java_outer_classname = \"ErrorDetailsProto\";\noption java_package = \"com.google.rpc\";\noption objc_class_prefix = \"RPC\";\n\n\n// Describes when the clients can retry a failed request. Clients could ignore\n// the recommendation here or retry when this information is missing from error\n// responses.\n//\n// It's always recommended that clients should use exponential backoff when\n// retrying.\n//\n// Clients should wait until `retry_delay` amount of time has passed since\n// receiving the error response before retrying.  If retrying requests also\n// fail, clients should use an exponential backoff scheme to gradually increase\n// the delay between retries based on `retry_delay`, until either a maximum\n// number of retires have been reached or a maximum retry delay cap has been\n// reached.\nmessage RetryInfo {\n  // Clients should wait at least this long between retrying the same request.\n  google.protobuf.Duration retry_delay = 1;\n}\n\n// Describes additional debugging info.\nmessage DebugInfo {\n  // The stack trace entries indicating where the error occurred.\n  repeated string stack_entries = 1;\n\n  // Additional debugging information provided by the server.\n  string detail = 2;\n}\n\n// Describes how a quota check failed.\n//\n// For example if a daily limit was exceeded for the calling project,\n// a service could respond with a QuotaFailure detail containing the project\n// id and the description of the quota limit that was exceeded.  If the\n// calling project hasn't enabled the service in the developer console, then\n// a service could respond with the project id and set `service_disabled`\n// to true.\n//\n// Also see RetryDetail and Help types for other details about handling a\n// quota failure.\nmessage QuotaFailure {\n  // A message type used to describe a single quota violation.  For example, a\n  // daily quota or a custom quota that was exceeded.\n  message Violation {\n    // The subject on which the quota check failed.\n    // For example, \"clientip:<ip address of client>\" or \"project:<Google\n    // developer project id>\".\n    string subject = 1;\n\n    // A description of how the quota check failed. Clients can use this\n    // description to find more about the quota configuration in the service's\n    // public documentation, or find the relevant quota limit to adjust through\n    // developer console.\n    //\n    // For example: \"Service disabled\" or \"Daily Limit for read operations\n    // exceeded\".\n    string description = 2;\n  }\n\n  // Describes all quota violations.\n  repeated Violation violations = 1;\n}\n\n// Describes what preconditions have failed.\n//\n// For example, if an RPC failed because it required the Terms of Service to be\n// acknowledged, it could list the terms of service violation in the\n// PreconditionFailure message.\nmessage PreconditionFailure {\n  // A message type used to describe a single precondition failure.\n  message Violation {\n    // The type of PreconditionFailure. We recommend using a service-specific\n    // enum type to define the supported precondition violation types. For\n    // example, \"TOS\" for \"Terms of Service violation\".\n    string type = 1;\n\n    // The subject, relative to the type, that failed.\n    // For example, \"google.com/cloud\" relative to the \"TOS\" type would\n    // indicate which terms of service is being referenced.\n    string subject = 2;\n\n    // A description of how the precondition failed. Developers can use this\n    // description to understand how to fix the failure.\n    //\n    // For example: \"Terms of service not accepted\".\n    string description = 3;\n  }\n\n  // Describes all precondition violations.\n  repeated Violation violations = 1;\n}\n\n// Describes violations in a client request. This error type focuses on the\n// syntactic aspects of the request.\nmessage BadRequest {\n  // A message type used to describe a single bad request field.\n  message FieldViolation {\n    // A path leading to a field in the request body. The value will be a\n    // sequence of dot-separated identifiers that identify a protocol buffer\n    // field. E.g., \"field_violations.field\" would identify this field.\n    string field = 1;\n\n    // A description of why the request element is bad.\n    string description = 2;\n  }\n\n  // Describes all violations in a client request.\n  repeated FieldViolation field_violations = 1;\n}\n\n// Contains metadata about the request that clients can attach when filing a bug\n// or providing other forms of feedback.\nmessage RequestInfo {\n  // An opaque string that should only be interpreted by the service generating\n  // it. For example, it can be used to identify requests in the service's logs.\n  string request_id = 1;\n\n  // Any data that was used to serve this request. For example, an encrypted\n  // stack trace that can be sent back to the service provider for debugging.\n  string serving_data = 2;\n}\n\n// Describes the resource that is being accessed.\nmessage ResourceInfo {\n  // A name for the type of resource being accessed, e.g. \"sql table\",\n  // \"cloud storage bucket\", \"file\", \"Google calendar\"; or the type URL\n  // of the resource: e.g. \"type.googleapis.com/google.pubsub.v1.Topic\".\n  string resource_type = 1;\n\n  // The name of the resource being accessed.  For example, a shared calendar\n  // name: \"example.com_4fghdhgsrgh@group.calendar.google.com\", if the current\n  // error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED].\n  string resource_name = 2;\n\n  // The owner of the resource (optional).\n  // For example, \"user:<owner email>\" or \"project:<Google developer project\n  // id>\".\n  string owner = 3;\n\n  // Describes what error is encountered when accessing this resource.\n  // For example, updating a cloud project may require the `writer` permission\n  // on the developer console project.\n  string description = 4;\n}\n\n// Provides links to documentation or for performing an out of band action.\n//\n// For example, if a quota check failed with an error indicating the calling\n// project hasn't enabled the accessed service, this can contain a URL pointing\n// directly to the right place in the developer console to flip the bit.\nmessage Help {\n  // Describes a URL link.\n  message Link {\n    // Describes what the link offers.\n    string description = 1;\n\n    // The URL of the link.\n    string url = 2;\n  }\n\n  // URL(s) pointing to additional information on handling the current error.\n  repeated Link links = 1;\n}\n\n// Provides a localized error message that is safe to return to the user\n// which can be attached to an RPC error.\nmessage LocalizedMessage {\n  // The locale used following the specification defined at\n  // http://www.rfc-editor.org/rfc/bcp/bcp47.txt.\n  // Examples are: \"en-US\", \"fr-CH\", \"es-MX\"\n  string locale = 1;\n\n  // The localized error message in the above locale.\n  string message = 2;\n}\n"
  },
  {
    "path": "devtools/googleapis/google/rpc/status.proto",
    "content": "// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.rpc;\n\nimport \"google/protobuf/any.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/rpc/status;status\";\noption java_multiple_files = true;\noption java_outer_classname = \"StatusProto\";\noption java_package = \"com.google.rpc\";\noption objc_class_prefix = \"RPC\";\n\n\n// The `Status` type defines a logical error model that is suitable for different\n// programming environments, including REST APIs and RPC APIs. It is used by\n// [gRPC](https://github.com/grpc). The error model is designed to be:\n//\n// - Simple to use and understand for most users\n// - Flexible enough to meet unexpected needs\n//\n// # Overview\n//\n// The `Status` message contains three pieces of data: error code, error message,\n// and error details. The error code should be an enum value of\n// [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed.  The\n// error message should be a developer-facing English message that helps\n// developers *understand* and *resolve* the error. If a localized user-facing\n// error message is needed, put the localized message in the error details or\n// localize it in the client. The optional error details may contain arbitrary\n// information about the error. There is a predefined set of error detail types\n// in the package `google.rpc` that can be used for common error conditions.\n//\n// # Language mapping\n//\n// The `Status` message is the logical representation of the error model, but it\n// is not necessarily the actual wire format. When the `Status` message is\n// exposed in different client libraries and different wire protocols, it can be\n// mapped differently. For example, it will likely be mapped to some exceptions\n// in Java, but more likely mapped to some error codes in C.\n//\n// # Other uses\n//\n// The error model and the `Status` message can be used in a variety of\n// environments, either with or without APIs, to provide a\n// consistent developer experience across different environments.\n//\n// Example uses of this error model include:\n//\n// - Partial errors. If a service needs to return partial errors to the client,\n//     it may embed the `Status` in the normal response to indicate the partial\n//     errors.\n//\n// - Workflow errors. A typical workflow has multiple steps. Each step may\n//     have a `Status` message for error reporting.\n//\n// - Batch operations. If a client uses batch request and batch response, the\n//     `Status` message should be used directly inside batch response, one for\n//     each error sub-response.\n//\n// - Asynchronous operations. If an API call embeds asynchronous operation\n//     results in its response, the status of those operations should be\n//     represented directly using the `Status` message.\n//\n// - Logging. If some API errors are stored in logs, the message `Status` could\n//     be used directly after any stripping needed for security/privacy reasons.\nmessage Status {\n  // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].\n  int32 code = 1;\n\n  // A developer-facing error message, which should be in English. Any\n  // user-facing error message should be localized and sent in the\n  // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.\n  string message = 2;\n\n  // A list of messages that carry the error details.  There is a common set of\n  // message types for APIs to use.\n  repeated google.protobuf.Any details = 3;\n}\n"
  },
  {
    "path": "docs/crypto/vault.md",
    "content": "# Vault\n\nA vault is used to securely store user private keys based on a master password. It is hosted on the cloud and uses the cryptography described here to assure it can't access the data directly. It works very similarly to password managers.\n\n## Vault data model\n\n### Map uuids to public keys (uses address book service for this)\n\n| uuid | public key |\n|------|------------|\n| 1    | 0xa        |\n| 2    | 0xb        |\n| 3    | 0xc        |\n\n### Maps uuids to vaults\n\n| uuid | vault                                                                            | vskHash  |\n|------|----------------------------------------------------------------------------------|----------|\n| 1    | Encrypted({   a: somePrivateKey,   b: otherPrivateKey,   c: anotherPrivateKey }) | 0xabc... |\n\n## Vault Flows\n\n### Storing private keys\n\nThe client needs to complete a challenge to prove they have access to a given public key. Once they have proven access, the server allows replacing the vault file for a new one.\n\n#### Private key signing challenge flow:\n\n1. Client sends to the server their public key\n2. Server issues a challenge\n3. Client signs the challenge using its private key\n4. Server verifies signature matches the public key, returning a JSON Web Token (JWT)\n\n#### Storing the private key\n\n1. Client creates the vault file (`vf`), which is a JSON document that maps public keys to their private keys, but can also contain anything we want to store.\n2. Client computes its vault key (`vk`). To do this, it runs `PBKDF2(password, salt, iterations, hashingFn)`, where `password` is the master password, `salt` is the user's `uuid`, `iterations` is a high number to prevent brute force (set to 100.000 as of now), and `hashingFn` is SHA512 which is the industry standard for a secure hashing function.\n3. Using `vk`, client encrypts `vf` using AES, obtaining `vk(vf)`.\n4. Client computes the vault service key (`vsk`) by doing key derivation again: `PBKDF2(vk, password, iterations, hashingFn)`, where `password` is the master password.\n5. Client submits `vk(vf)`, `vsk` and the JWT back to the server.\n6. Server verifies the JWT and successfully stores `vk(vf)` for the user with the given uuid.\n7. Server stores `vskHash = PBKDF2(vsk, iterations, hashingFn)` using a really high value for `iterations`.\n\n#### Retrieving the private key\n\n1. Client computes `vk` and `vsk` again as in step (2) and (4) of the previous section.\n2. Client sends a retrieve request to the server with `vsk` and `uuid` as the params.\n3. Server computes `vskHash` as in (7) of the previous section.\n4. Server checks `vskHash` matches the one stored. If it does, it returns `vk(vf)`. If not, returns a \"Wrong password\" error.\n5. Client decrypts `vk(vf)` using `vk`, obtaining `vf` back and getting access to its private keys.\n\n## Takeaways\n\n- The client only needs to remember the master password and the uuid (which is obtained through a username, so it needs to remember the username).\n- The server only receives `vsk` and therefore cannot decrypt `vk(vf)` from it alone. It can bruteforce `vsk` to obtain `vk`, but given `vk` is a SHA512 hash already, it'd take a billion years.\n- If a middleman intercepts the client->server message, and somehow gets to decrypt the first layer of protection which is TLS, it can't decrypt `vk(vf)` without `vk`.\n- The server should implement rate-limitting to protect weak master passwords from being cracked.\n"
  },
  {
    "path": "docs/sharing/types-of-sharing.md",
    "content": "# Types of Sharing\n\nSharing can happen at the file level or the bucket level.  Legacy sharing was done at the bucket level so those interfaces are left for continued usage.  Space app however will now rely on file level access control and sharing hence there will be a mixed set of interfaces for sharing.\n\nIn bucket sharing, you can share an entire bucket but getting the thread info to share.  A bucket holds the file structure and pointers to each file. For each bucket, we use an additional Textile thread. This thread holds meta information around the bucket that's needed for sharing. In this doc you can read about the different types of sharing we support.\n\nIn file level sharing, a mirror copy of the bucket is made in the hub and only that shared path will be added to that bucket and access controlled via Textile hub's new file level access control feature.\n\n## Bucket sharing\n\nThe most simple sharing type. When you create a bucket (using the `CreateBucket` gRPC endpoint), a bucket with a single member, the creator of the bucket, will be created. If you use the `ShareBucket` gRPC, you can add all members you want. This is very similar to creating a team, or creating a channel in Slack.\n\n## File level sharing\n\nFor this, a set of paths are shared and like previously described, a mirror bucket is created with just the paths that are being shared copied over.  Furthermore since these files will be on the hub, a Space encryption layer is added where a new key will be used for each file.  Finally the file specific key for the paths being shared will be sent via hub inboxing so that there is a way to retreive and decrypt files shared through a hub without exposing the content to the hub.\n\n## Public File Sharing\n\nWhen calling `GeneratePublicFileLink`, the file is going to be encrypted and uploaded to IPFS. The link will point to a gateway so that anyone with the decryption key will be able to download the file.\n\nWe are evaluating also creating a bucket around this single file, so that the link can also be used to join the bucket and modify the file collaboratively.\n"
  },
  {
    "path": "examples/ipfsLite/ipfsLite.go",
    "content": "package main\n\nimport \"log\"\n\nfunc main() {\n\tlog.Println(\"hello world IPFS!\")\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/README.md",
    "content": "# textile in Go poc\n\nTemporarily, buckets APIs aren't available in local threads so using the hub for all interactions. Once that is merged into threads, then we can use local one.\n\nTo run the in-process `threadsd` example:\n1. Build `go build .`\n2. Run `./textileBucketsClient threads`\n\nTo run the bucket creation with hub example: \n1. Set the host, key and secret in set-envs. Use textile-hub-dev.fleek.co for the host. Key and secret should be the one shared in Slack or generated using the `tt` cli (see extra notes below)\n2. `source set-envs`\n3. `go build .`\n4. `./textileBucketsClient hub`\n\n### Textile CLI\n\n1. Download bundle at https://github.com/textileio/textile/releases\n2. Extract\n3. Go into extracted folder and run `./install`\n4. Run `tt init --api=textile-hub-dev.fleek.co:3006`\n5. When asked for email validation, hit http://textile-hub-dev.fleek.co:8006/confirm/textilesession to auto validate\n6. Run `tt keys create --api=textile-hub-dev.fleek.co:3006` to create keys.\n7. You can also use all the other `tt` commands pointing to our dev hub by adding the flag `--api=textile-hub-dev.fleek.co:3006`"
  },
  {
    "path": "examples/textileBucketsClient/bucket-sync/bucket-sync.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbuckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\ttb \"github.com/textileio/textile/v2/buckets\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n)\n\ntype TextileBucketRoot buckets_pb.Root\n\nfunc main() {\n\thost := os.Getenv(\"TXL_HUB_TARGET\")\n\tkey := os.Getenv(\"TXL_USER_KEY\")\n\tsecret := os.Getenv(\"TXL_USER_SECRET\")\n\n\tvar threads *tc.Client\n\tvar buckets *bc.Client\n\tvar err error\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\thubTarget := host\n\tthreadstarget := host\n\n\tif strings.Contains(host, \"443\") {\n\t\tcreds := credentials.NewTLS(&tls.Config{})\n\t\topts = append(opts, grpc.WithTransportCredentials(creds))\n\t\tauth.Secure = true\n\t} else {\n\t\topts = append(opts, grpc.WithInsecure())\n\t}\n\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\tbuckets, err = bc.NewClient(hubTarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\tthreads, err = tc.NewClient(threadstarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\tuser1, _, err := crypto.GenerateEd25519Key(rand.Reader)\n\tif err != nil {\n\t\tlog.Println(\"error creating user1\")\n\t\tlog.Fatal(err)\n\t}\n\n\tuser2, _, err := crypto.GenerateEd25519Key(rand.Reader)\n\tif err != nil {\n\t\tlog.Println(\"error creating user2\")\n\t\tlog.Fatal(err)\n\t}\n\n\t// user 1 creates bucket and adds file\n\n\tctx := context.Background()\n\tctx = common.NewAPIKeyContext(ctx, key)\n\n\tctx, err = common.CreateAPISigContext(ctx, time.Now().Add(time.Minute*2), secret)\n\tif err != nil {\n\t\tlog.Println(\"error creating APISigContext\")\n\t\tlog.Fatal(err)\n\t}\n\n\ttok, err := threads.GetToken(ctx, thread.NewLibp2pIdentity(user1))\n\tif err != nil {\n\t\tlog.Println(\"error calling GetToken\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx = thread.NewTokenContext(ctx, tok)\n\n\tbucket1name := \"testbucket1\"\n\n\tctx = common.NewThreadNameContext(ctx, bucket1name)\n\tdbID := thread.NewIDV1(thread.Raw, 32)\n\tif err := threads.NewDB(ctx, dbID); err != nil {\n\t\tlog.Println(\"error calling threads.NewDB\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx = common.NewThreadIDContext(ctx, dbID)\n\n\tbuck, err := buckets.Create(ctx, bc.WithName(bucket1name), bc.WithPrivate(true))\n\tlog.Println(\"created bucket: \" + buck.Root.Name)\n\n\tfilepath := \"file1\"\n\tf := &bytes.Buffer{}\n\tf.Write([]byte(\"hello space\"))\n\t_, _, err = buckets.PushPath(ctx, buck.Root.Key, filepath, f)\n\n\tif err != nil {\n\t\tlog.Println(\"error pushing path\")\n\t\tlog.Fatal(err)\n\t}\n\n\troles := make(map[string]tb.Role)\n\ttpk := thread.NewLibp2pPubKey(user2.GetPublic())\n\troles[tpk.String()] = tb.Admin\n\terr = buckets.PushPathAccessRoles(ctx, buck.Root.Key, filepath, roles)\n\tif err != nil {\n\t\tlog.Println(\"error sharing path\")\n\t\tlog.Fatal(err)\n\t}\n\n\t// user 2 tries to access\n\tctx1 := context.Background()\n\tctx1 = common.NewAPIKeyContext(ctx1, key)\n\tctx1, err = common.CreateAPISigContext(ctx1, time.Now().Add(time.Minute*2), secret)\n\ttok, err = threads.GetToken(ctx1, thread.NewLibp2pIdentity(user2))\n\tctx1 = thread.NewTokenContext(ctx1, tok)\n\n\tif err != nil {\n\t\tlog.Println(\"error creating context\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx1 = common.NewThreadNameContext(ctx1, bucket1name)\n\tctx1 = common.NewThreadIDContext(ctx1, dbID)\n\tvar buf bytes.Buffer\n\terr = buckets.PullPath(ctx1, buck.Root.Key, filepath, &buf)\n\tif err != nil {\n\t\tlog.Println(\"error pulling path\")\n\t\tlog.Fatal(err)\n\t}\n\n\ts := buf.String()\n\tlog.Println(\"fetch file content: \" + s)\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/buckets.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/improbable-eng/grpc-web/go/grpcweb\"\n\tconnmgr \"github.com/libp2p/go-libp2p-connmgr\"\n\tcrypto \"github.com/libp2p/go-libp2p-crypto\"\n\tma \"github.com/multiformats/go-multiaddr\"\n\t\"github.com/textileio/go-threads/api\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\ttpb \"github.com/textileio/go-threads/api/pb\"\n\ttCommon \"github.com/textileio/go-threads/common\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tnetapi \"github.com/textileio/go-threads/net/api\"\n\tnetapiclient \"github.com/textileio/go-threads/net/api/client\"\n\tnetpb \"github.com/textileio/go-threads/net/api/pb\"\n\t\"github.com/textileio/go-threads/util\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tpb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\tuc \"github.com/textileio/textile/v2/api/usersd/client\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n)\n\nconst ctxTimeout = 30\n\nfunc authCtx(duration time.Duration) (context.Context, context.CancelFunc) {\n\tctx, cancel := context.WithTimeout(context.Background(), duration)\n\treturn ctx, cancel\n}\n\n// these next 2 helpers are from the lib but wasnt\n// sure how to export them\nfunc threadCtx(duration time.Duration) (context.Context, context.CancelFunc) {\n\tctx, cancel := authCtx(duration)\n\tctx = common.NewThreadIDContext(ctx, getThreadID())\n\treturn ctx, cancel\n}\n\nfunc getThreadID() (id thread.ID) {\n\t// get from Space config instead\n\tidstr := os.Getenv(\"thread\")\n\tif idstr != \"\" {\n\t\tvar err error\n\t\tid, err = thread.Decode(idstr)\n\t\tif err != nil {\n\t\t\tcmd.Fatal(err)\n\t\t}\n\t}\n\treturn\n}\n\nfunc runThreadsLocally() {\n\thostAddr, err := ma.NewMultiaddr(\"/ip4/0.0.0.0/tcp/4006\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tapiAddr, err := ma.NewMultiaddr(\"/ip4/127.0.0.1/tcp/6006\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tapiProxyAddr, err := ma.NewMultiaddr(\"/ip4/127.0.0.1/tcp/6007\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\trepo := \".threads\"\n\tdebug := false\n\n\tn, err := tCommon.DefaultNetwork(\n\t\trepo,\n\t\ttCommon.WithNetHostAddr(hostAddr),\n\t\ttCommon.WithConnectionManager(connmgr.NewConnManager(100, 400, time.Second*20)),\n\t\ttCommon.WithNetDebug(debug))\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer n.Close()\n\tn.Bootstrap(util.DefaultBoostrapPeers())\n\tservice, err := api.NewService(n, api.Config{\n\t\tRepoPath: repo,\n\t\tDebug:    debug,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tnetService, err := netapi.NewService(n, netapi.Config{\n\t\tDebug: debug,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\ttarget, err := util.TCPAddrFromMultiAddr(apiAddr)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tptarget, err := util.TCPAddrFromMultiAddr(apiProxyAddr)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tserver := grpc.NewServer()\n\tlistener, err := net.Listen(\"tcp\", target)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tgo func() {\n\t\ttpb.RegisterAPIServer(server, service)\n\t\tnetpb.RegisterAPIServer(server, netService)\n\t\tif err := server.Serve(listener); err != nil && !errors.Is(err, grpc.ErrServerStopped) {\n\t\t\tlog.Fatalf(\"serve error: %v\", err)\n\t\t}\n\t}()\n\twebrpc := grpcweb.WrapServer(\n\t\tserver,\n\t\tgrpcweb.WithOriginFunc(func(origin string) bool {\n\t\t\treturn true\n\t\t}),\n\t\tgrpcweb.WithWebsockets(true),\n\t\tgrpcweb.WithWebsocketOriginFunc(func(req *http.Request) bool {\n\t\t\treturn true\n\t\t}))\n\tproxy := &http.Server{\n\t\tAddr: ptarget,\n\t}\n\tproxy.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif webrpc.IsGrpcWebRequest(r) ||\n\t\t\twebrpc.IsAcceptableGrpcCorsRequest(r) ||\n\t\t\twebrpc.IsGrpcWebSocketRequest(r) {\n\t\t\twebrpc.ServeHTTP(w, r)\n\t\t}\n\t})\n\tgo func() {\n\t\tif err := proxy.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n\t\t\tlog.Fatalf(\"proxy error: %v\", err)\n\t\t}\n\t}()\n\n\tdefer func() {\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Second)\n\t\tdefer cancel()\n\t\tif err := proxy.Shutdown(ctx); err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t\tserver.GracefulStop()\n\t\tif err := n.Close(); err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t}()\n\n\tfmt.Println(\"Welcome to Threads!\")\n\tfmt.Println(\"Your peer ID is \" + n.Host().ID().String())\n\n\tlog.Println(\"threadsd started\")\n\n\tselect {}\n}\n\ntype Bucket struct {\n\tKey       string `json:\"_id\"`\n\tName      string `json:\"name\"`\n\tPath      string `json:\"path\"`\n\tDNSRecord string `json:\"dns_record,omitempty\"`\n\t//Archives  Archives `json:\"archives\"`\n\tCreatedAt int64 `json:\"created_at\"`\n\tUpdatedAt int64 `json:\"updated_at\"`\n}\n\nfunc initUser(threads *tc.Client, buckets *bc.Client, users *uc.Client, netclient *netapiclient.Client, user string, bucketSlug string) *pb.CreateResponse {\n\t// only needed for hub connections\n\n\tkey := os.Getenv(\"TXL_USER_KEY\")\n\tsecret := os.Getenv(\"TXL_USER_SECRET\")\n\n\tif key == \"\" || secret == \"\" {\n\t\treturn nil\n\t}\n\n\t// TODO: this should be happening in an auth lambda\n\tctx := context.Background()\n\tctx = common.NewAPIKeyContext(ctx, key)\n\tvar apiSigCtx context.Context\n\tvar err error\n\tif apiSigCtx, err = common.CreateAPISigContext(ctx, time.Now().Add(time.Minute), secret); err != nil {\n\t\treturn nil\n\t}\n\tctx = apiSigCtx\n\n\tif err != nil {\n\t\tlog.Println(\"error creating APISigContext\")\n\t\tlog.Fatal(err)\n\t}\n\n\t// TODO: get from key manager instead\n\tsk, _, err := crypto.GenerateEd25519Key(rand.Reader)\n\n\t// TODO: CTX has to be made from session key received from lambda\n\t// ctx on next line needs to be rebuilt from the authorization from the lambda\n\ttok, err := threads.GetToken(ctx, thread.NewLibp2pIdentity(sk))\n\tctx = thread.NewTokenContext(ctx, tok)\n\n\tmid, err := users.SetupMailbox(ctx)\n\tif err != nil {\n\t\tlog.Println(\"Unable to setup sender mailbox\", err)\n\t\treturn nil\n\t}\n\tlog.Println(\"Sender Mailbox id: \", mid.String())\n\n\t// generate random recipient\n\trsk, _, err := crypto.GenerateEd25519Key(rand.Reader)\n\tid := thread.NewLibp2pIdentity(rsk)\n\n\trctx := context.Background()\n\trctx = common.NewAPIKeyContext(rctx, key)\n\tvar rapiSigCtx context.Context\n\tif rapiSigCtx, err = common.CreateAPISigContext(rctx, time.Now().Add(time.Minute), secret); err != nil {\n\t\treturn nil\n\t}\n\trctx = rapiSigCtx\n\trtok, err := threads.GetToken(rctx, thread.NewLibp2pIdentity(rsk))\n\trctx = thread.NewTokenContext(rctx, rtok)\n\n\tmid2, err := users.SetupMailbox(rctx)\n\tif err != nil {\n\t\tlog.Println(\"Unable to setup recipient mailbox\", err)\n\t\treturn nil\n\t}\n\tlog.Println(\"Recipient Mailbox id: \", mid2.String())\n\n\tmsg, err := users.SendMessage(ctx, thread.NewLibp2pIdentity(sk), id.GetPublic(), []byte(\"hello\"))\n\n\tif err != nil {\n\t\tlog.Println(\"Unable to send\", err)\n\t\treturn nil\n\t}\n\n\tlog.Println(\"msg: \" + string(msg.Body))\n\n\t// create thread\n\tctx = common.NewThreadNameContext(ctx, user+\"-\"+bucketSlug)\n\tdbID := thread.NewIDV1(thread.Raw, 32)\n\t// TODO: store threadid in config\n\tif err := threads.NewDB(ctx, dbID); err != nil {\n\t\tlog.Println(\"error calling threads.NewDB\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx = common.NewThreadIDContext(ctx, dbID)\n\t// create bucket\n\tbuck, err := buckets.Create(ctx, bc.WithName(bucketSlug), bc.WithPrivate(true))\n\tbuckets.Create(ctx, bc.WithName(bucketSlug+\"2\"), bc.WithPrivate(true))\n\n\tlog.Println(\"finished creating bucket\")\n\n\thostid, err := netclient.GetHostID(ctx)\n\tif err != nil {\n\t\tlog.Println(\"error getting HOST ID: \", err)\n\t}\n\tlog.Println(\"HOSTID: \", hostid)\n\n\tnewCtx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\topt := tc.ListenOption{}\n\n\t//listPath on a folder that doesnt exist\n\tlp, err := buckets.ListPath(ctx, buck.Root.Key, \"random/folderA/doesntexists\")\n\tif err != nil {\n\t\tlog.Println(\"error doing list path on non existent directoy: \", err)\n\t}\n\tlog.Println(\"lp1: \", lp)\n\n\tdb, err := users.ListThreads(ctx)\n\n\tif err != nil {\n\t\tfmt.Println(\"error getting list dbs\")\n\t\tfmt.Println(err)\n\t}\n\n\tfmt.Println(\"listing dbs\")\n\tfor k, v := range db.GetList() {\n\t\tfmt.Println(\"looping through thread id: \", k)\n\t\tfmt.Println(\"db info: \", v)\n\t}\n\n\temptyDirPath := strings.TrimRight(\"dummy\", \"/\") + \"/\" + \".keep\"\n\t_, _, err = buckets.PushPath(ctx, buck.Root.Key, emptyDirPath, &bytes.Buffer{})\n\n\t//listPath on a folder that exists\n\tr := strings.NewReader(\"IPFS test data for reader\")\n\tr2 := strings.NewReader(\"IPFS test data  ./tfor reader2\")\n\tbuckets.PushPath(ctx, buck.Root.Key, \"another/folderB/file1\", r)\n\tbuckets.PushPath(ctx, buck.Root.Key, \"another/folderB/file2\", r2)\n\tlp, err = buckets.ListPath(ctx, buck.Root.Key, \"another/folderB\")\n\tif err != nil {\n\t\tlog.Println(\"error doing list path on non existent directoy: \", err)\n\t}\n\tlog.Println(\"lp2: \", lp)\n\n\t// put in go routine\n\tchannel, err := threads.Listen(newCtx, dbID, []tc.ListenOption{opt})\n\n\tlog.Println(\"finished creating channel\")\n\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to call listen: %v\", err)\n\t}\n\n\tgo func() {\n\t\ttime.Sleep(time.Second)\n\t\tbuckets.Create(ctx, bc.WithName(bucketSlug+\"3\"), bc.WithPrivate(true))\n\t}()\n\n\t// a separete go routine that keeps checking if msgs are there\n\t// and calls handler function\n\tval, ok := <-channel\n\n\tif !ok {\n\t\tlog.Println(\"channel no longer active at first events\")\n\t} else {\n\t\tlog.Println(\"received from channel!!!!\")\n\t\tlog.Println(val)\n\t\tinstance := &Bucket{}\n\t\tif err = json.Unmarshal(val.Action.Instance, instance); err != nil {\n\t\t\tlog.Fatalf(\"failed to unmarshal listen result: %v\", err)\n\t\t}\n\n\t\tlog.Printf(\"instance: %+v\", *instance)\n\t}\n\n\tval, ok = <-channel\n\n\tif !ok {\n\t\tlog.Println(\"channel 2 no longer active at first events\")\n\t} else {\n\t\tlog.Println(\"received 2 from channel!!!!\")\n\t\tlog.Println(val)\n\t}\n\n\tlog.Println(\"finished creating channel\")\n\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to call listen: %v\", err)\n\t}\n\n\tval, ok = <-channel\n\n\tif !ok {\n\t\tlog.Println(\"channel no longer active at first events\")\n\t} else {\n\t\tlog.Println(\"received from channel!!!!\")\n\t\tlog.Println(val)\n\t}\n\n\tval, ok = <-channel\n\n\tif !ok {\n\t\tlog.Println(\"channel 2 no longer active at first events\")\n\t} else {\n\t\tlog.Println(\"received 2 from channel!!!!\")\n\t\tlog.Println(val)\n\t}\n\n\treturn buck\n}\n\nfunc main() {\n\tmode := os.Args[1]\n\n\tif mode == \"threads\" {\n\t\tlog.Println(\"running in process threads\")\n\t\trunThreadsLocally()\n\t\treturn\n\t}\n\n\tif mode == \"hub\" {\n\t\tvar threads *tc.Client\n\t\tvar buckets *bc.Client\n\t\t// might need these for other ops so leaving here as commented\n\t\t// out and below\n\t\tvar users *uc.Client\n\t\t// var hub *hc.Client\n\t\tvar err error\n\n\t\thost := os.Getenv(\"TXL_HUB_TARGET\")\n\t\tthreadstarget := os.Getenv(\"TXL_THREADS_TARGET\")\n\t\tfmt.Println(\"hub host: \" + host)\n\t\tfmt.Println(\"threads host: \" + threadstarget)\n\n\t\tauth := common.Credentials{}\n\t\tvar opts []grpc.DialOption\n\t\thubTarget := host\n\n\t\tif strings.Contains(host, \"443\") {\n\t\t\tcreds := credentials.NewTLS(&tls.Config{})\n\t\t\topts = append(opts, grpc.WithTransportCredentials(creds))\n\t\t\tauth.Secure = true\n\t\t} else {\n\t\t\topts = append(opts, grpc.WithInsecure())\n\t\t}\n\t\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\t\tbuckets, err = bc.NewClient(hubTarget, opts...)\n\t\tif err != nil {\n\t\t\tcmd.Fatal(err)\n\t\t}\n\t\tthreads, err = tc.NewClient(threadstarget, opts...)\n\t\tif err != nil {\n\t\t\tcmd.Fatal(err)\n\t\t}\n\n\t\tusers, err = uc.NewClient(hubTarget, opts...)\n\t\tif err != nil {\n\t\t\tcmd.Fatal(err)\n\t\t}\n\n\t\tnetclient, err := netapiclient.NewClient(host, opts...)\n\t\tif err != nil {\n\t\t\tcmd.Fatal(err)\n\t\t}\n\n\t\tlog.Println(\"Finished client init, calling user init ...\")\n\n\t\t// hub\n\t\tres := initUser(threads, buckets, users, netclient, \"test-user\", \"test-bucket\")\n\t\tlog.Println(res)\n\t}\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/create-thread-with-key/create-thread-with-key.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/ed25519\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/user\"\n\n\tma \"github.com/multiformats/go-multiaddr\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/go-threads/db\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"github.com/textileio/textile/v2/core\"\n\t\"google.golang.org/grpc\"\n)\n\nvar IpfsAddr string\nvar MongoUsr string\nvar MongoPw string\nvar MongoHost string\nvar MongoRepSet string\n\nconst exampleThreadName = \"meow\"\n\nfunc main() {\n\tIpfsAddr = os.Getenv(\"IPFS_ADDR\")\n\tMongoUsr = os.Getenv(\"MONGO_USR\")\n\tMongoPw = os.Getenv(\"MONGO_PW\")\n\tMongoHost = os.Getenv(\"MONGO_HOST\")\n\tMongoRepSet = os.Getenv(\"MONGO_REPLICA_SET\")\n\n\taddrAPI := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/3006\")\n\taddrAPIProxy := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/3007\")\n\taddrThreadsHost := cmd.AddrFromStr(\"/ip4/0.0.0.0/tcp/4006\")\n\n\taddrIpfsAPI := cmd.AddrFromStr(IpfsAddr)\n\n\taddrGatewayHost := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/8006\")\n\taddrGatewayURL := \"http://127.0.0.1:8006\"\n\n\tfmt.Println(\"mongo host: \", MongoHost)\n\taddrMongoURI := \"mongodb://\" + MongoUsr + \":\" + MongoPw + \"@\" + MongoHost + \"/?ssl=true&replicaSet=\" + MongoRepSet + \"&authSource=admin&retryWrites=true&w=majority\"\n\n\tusr, err := user.Current()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\ttextile, err := core.NewTextile(ctx, core.Config{\n\t\tRepoPath:        usr.HomeDir + \"/.buckd/repo\",\n\t\tAddrAPI:         addrAPI,\n\t\tAddrAPIProxy:    addrAPIProxy,\n\t\tAddrThreadsHost: addrThreadsHost,\n\t\tAddrIPFSAPI:     addrIpfsAPI,\n\t\tAddrGatewayHost: addrGatewayHost,\n\t\tAddrGatewayURL:  addrGatewayURL,\n\t\tAddrMongoURI:    addrMongoURI,\n\t\tAddrMongoName:   \"buckets\",\n\t\tDebug:           false,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer textile.Close(false)\n\ttextile.Bootstrap()\n\n\tfmt.Println(\"Welcome to Buckets!\")\n\tfmt.Println(\"Your peer ID is \" + textile.HostID().String())\n\n\tfmt.Println(\"starting join thread\")\n\n\taddr := os.Getenv(\"JOIN_THREAD_ADDR\")\n\tkey := os.Getenv(\"JOIN_THREAD_KEY\")\n\n\tm1, _ := ma.NewMultiaddr(addr)\n\n\tvar threads *tc.Client\n\thost := \"127.0.0.1:3006\"\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\tthreadstarget := host\n\topts = append(opts, grpc.WithInsecure())\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\tthreads, err = tc.NewClient(threadstarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\tthreadCtx := context.Background()\n\tk, err := thread.KeyFromString(key)\n\n\tpub, _, err := ed25519.GenerateKey(nil)\n\tif err != nil {\n\t\tfmt.Println(\"error generating key: \", err)\n\t\treturn\n\t}\n\n\t// no need to crypto.UnmarshalEd25519PublicKey(pub)\n\n\tmanagedKey, err := thread.KeyFromBytes(pub)\n\tif err != nil {\n\t\tfmt.Println(\"error key from bytes: \", err)\n\t\treturn\n\t}\n\n\terr = threads.NewDBFromAddr(threadCtx, m1, k, db.WithNewManagedThreadKey(managedKey))\n\tif err != nil {\n\t\tfmt.Println(\"error new db from addr: \", err)\n\t}\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/join-thread/join-thread.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/user\"\n\n\tma \"github.com/multiformats/go-multiaddr\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"github.com/textileio/textile/v2/core\"\n\t\"google.golang.org/grpc\"\n)\n\nvar IpfsAddr string\nvar MongoUsr string\nvar MongoPw string\nvar MongoHost string\nvar MongoRepSet string\n\nfunc main() {\n\tIpfsAddr = os.Getenv(\"IPFS_ADDR\")\n\tMongoUsr = os.Getenv(\"MONGO_USR\")\n\tMongoPw = os.Getenv(\"MONGO_PW\")\n\tMongoHost = os.Getenv(\"MONGO_HOST\")\n\tMongoRepSet = os.Getenv(\"MONGO_REPLICA_SET\")\n\n\taddrAPI := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/3006\")\n\taddrAPIProxy := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/3007\")\n\taddrThreadsHost := cmd.AddrFromStr(\"/ip4/0.0.0.0/tcp/4006\")\n\n\taddrIpfsAPI := cmd.AddrFromStr(IpfsAddr)\n\n\taddrGatewayHost := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/8006\")\n\taddrGatewayURL := \"http://127.0.0.1:8006\"\n\n\tfmt.Println(\"mongo host: \", MongoHost)\n\taddrMongoURI := \"mongodb://\" + MongoUsr + \":\" + MongoPw + \"@\" + MongoHost + \"/?ssl=true&replicaSet=\" + MongoRepSet + \"&authSource=admin&retryWrites=true&w=majority\"\n\n\tusr, err := user.Current()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\ttextile, err := core.NewTextile(ctx, core.Config{\n\t\tRepoPath:        usr.HomeDir + \"/.buckd/repo\",\n\t\tAddrAPI:         addrAPI,\n\t\tAddrAPIProxy:    addrAPIProxy,\n\t\tAddrThreadsHost: addrThreadsHost,\n\t\tAddrIPFSAPI:     addrIpfsAPI,\n\t\tAddrGatewayHost: addrGatewayHost,\n\t\tAddrGatewayURL:  addrGatewayURL,\n\t\tAddrMongoURI:    addrMongoURI,\n\t\tAddrMongoName:   \"buckets\",\n\t\tDebug:           false,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer textile.Close(false)\n\ttextile.Bootstrap()\n\n\tfmt.Println(\"Welcome to Buckets!\")\n\tfmt.Println(\"Your peer ID is \" + textile.HostID().String())\n\n\tfmt.Println(\"starting join thread\")\n\n\taddr := os.Getenv(\"JOIN_THREAD_ADDR\")\n\tkey := os.Getenv(\"JOIN_THREAD_KEY\")\n\n\tm1, _ := ma.NewMultiaddr(addr)\n\n\tvar threads *tc.Client\n\thost := \"127.0.0.1:3006\"\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\tthreadstarget := host\n\topts = append(opts, grpc.WithInsecure())\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\tthreads, err = tc.NewClient(threadstarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\tthreadCtx := context.Background()\n\tk, err := thread.KeyFromString(key)\n\n\terr = threads.NewDBFromAddr(threadCtx, m1, k)\n\n\tif err != nil {\n\t\tfmt.Println(\"error new db from addr: \", err)\n\t}\n\n\tdb, err := threads.ListDBs(threadCtx)\n\n\tfmt.Println(\"about to loop thru dbs: \", db)\n\n\tfor k, v := range db {\n\t\tfmt.Println(\"looping through thread id: \", k)\n\t\tfmt.Println(\"db info: \", v)\n\t}\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/local-buck/local-buck.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/user\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tnc \"github.com/textileio/go-threads/net/api/client\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"github.com/textileio/textile/v2/core\"\n\t\"google.golang.org/grpc\"\n)\n\nvar IpfsAddr string\nvar MongoUsr string\nvar MongoPw string\nvar MongoHost string\nvar MongoRepSet string\n\nfunc main() {\n\n\tIpfsAddr = os.Getenv(\"IPFS_ADDR\")\n\tMongoUsr = os.Getenv(\"MONGO_USR\")\n\tMongoPw = os.Getenv(\"MONGO_PW\")\n\tMongoHost = os.Getenv(\"MONGO_HOST\")\n\tMongoRepSet = os.Getenv(\"MONGO_REPLICA_SET\")\n\n\taddrAPI := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/3006\")\n\taddrAPIProxy := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/3007\")\n\taddrThreadsHost := cmd.AddrFromStr(\"/ip4/0.0.0.0/tcp/4006\")\n\taddrIpfsAPI := cmd.AddrFromStr(IpfsAddr)\n\n\taddrGatewayHost := cmd.AddrFromStr(\"/ip4/127.0.0.1/tcp/8006\")\n\taddrGatewayURL := \"http://127.0.0.1:8006\"\n\tfmt.Println(\"mongo host: \", MongoHost)\n\taddrMongoURI := \"mongodb://\" + MongoUsr + \":\" + MongoPw + \"@\" + MongoHost + \"/?ssl=true&replicaSet=\" + MongoRepSet + \"&authSource=admin&retryWrites=true&w=majority\"\n\n\tusr, err := user.Current()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\ttextile, err := core.NewTextile(ctx, core.Config{\n\t\tRepoPath:        usr.HomeDir + \"/.buckd/repo\",\n\t\tAddrAPI:         addrAPI,\n\t\tAddrAPIProxy:    addrAPIProxy,\n\t\tAddrThreadsHost: addrThreadsHost,\n\t\tAddrIPFSAPI:     addrIpfsAPI,\n\t\tAddrGatewayHost: addrGatewayHost,\n\t\tAddrGatewayURL:  addrGatewayURL,\n\t\tAddrMongoURI:    addrMongoURI,\n\t\tAddrMongoName:   \"buckets\",\n\t\tDebug:           false,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer textile.Close(false)\n\ttextile.Bootstrap()\n\n\tfmt.Println(\"Welcome to Buckets!\")\n\tfmt.Println(\"Your peer ID is \" + textile.HostID().String())\n\n\t// now create a bucket on that thread\n\tvar threads *tc.Client\n\tvar buckets *bc.Client\n\tvar netc *nc.Client\n\thost := \"127.0.0.1:3006\"\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\thubTarget := host\n\tthreadstarget := host\n\topts = append(opts, grpc.WithInsecure())\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\tbuckets, err = bc.NewClient(hubTarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\tthreads, err = tc.NewClient(threadstarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\tnetc, err = nc.NewClient(host, opts...)\n\n\tlog.Info(\"Finished client init, calling user init ...\")\n\n\tthreadCtx := context.Background()\n\tthreadCtx = common.NewThreadNameContext(threadCtx, \"testthreadname\")\n\tdbID := thread.NewIDV1(thread.Raw, 32)\n\tif err := threads.NewDB(threadCtx, dbID); err != nil {\n\t\tlog.Info(\"error calling threads.NewDB\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx = common.NewThreadIDContext(threadCtx, dbID)\n\n\tbuck, err := buckets.Create(ctx, bc.WithName(\"personal\"), bc.WithPrivate(true))\n\tfmt.Println(\"info: \", buck)\n\n\tdb, err := threads.ListDBs(ctx)\n\n\tfmt.Println(\"got back from listdbs\")\n\n\tfor k, v := range db {\n\t\tfmt.Println(\"looping through thread id: \", k)\n\t\tfmt.Println(\"db info - Addrs: \", v.Addrs)\n\t\tfmt.Println(\"db info - Key: \", v.Key)\n\t\tfmt.Println(\"db info - Name: \", v.Name)\n\n\t\t// replicate on hub\n\t\tpeerid, err := netc.AddReplicator(ctx, dbID, cmd.AddrFromStr(os.Getenv(\"TXL_HUB_MA\")))\n\n\t\tif err != nil {\n\t\t\tfmt.Println(\"Unable to replicate on the hub: \" + err.Error())\n\t\t}\n\n\t\tfmt.Println(\"peerid: \", peerid)\n\t}\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/open-share-file/open-share-file.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbuckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\ttb \"github.com/textileio/textile/v2/buckets\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n)\n\ntype TextileBucketRoot buckets_pb.Root\n\nfunc main() {\n\thost := os.Getenv(\"TXL_HUB_TARGET\")\n\tkey := os.Getenv(\"TXL_USER_KEY\")\n\tsecret := os.Getenv(\"TXL_USER_SECRET\")\n\n\tvar threads *tc.Client\n\tvar buckets *bc.Client\n\tvar err error\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\thubTarget := host\n\tthreadstarget := host\n\n\tif strings.Contains(host, \"443\") {\n\t\tcreds := credentials.NewTLS(&tls.Config{})\n\t\topts = append(opts, grpc.WithTransportCredentials(creds))\n\t\tauth.Secure = true\n\t} else {\n\t\topts = append(opts, grpc.WithInsecure())\n\t}\n\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\tbuckets, err = bc.NewClient(hubTarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\tthreads, err = tc.NewClient(threadstarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\tuser1, _, err := crypto.GenerateEd25519Key(rand.Reader)\n\tif err != nil {\n\t\tlog.Println(\"error creating user1\")\n\t\tlog.Fatal(err)\n\t}\n\n\tuser2, _, err := crypto.GenerateEd25519Key(rand.Reader)\n\tif err != nil {\n\t\tlog.Println(\"error creating user2\")\n\t\tlog.Fatal(err)\n\t}\n\n\t// user 1 creates bucket and adds file\n\n\tctx := context.Background()\n\tctx = common.NewAPIKeyContext(ctx, key)\n\n\tctx, err = common.CreateAPISigContext(ctx, time.Now().Add(time.Minute*2), secret)\n\tif err != nil {\n\t\tlog.Println(\"error creating APISigContext\")\n\t\tlog.Fatal(err)\n\t}\n\n\ttok, err := threads.GetToken(ctx, thread.NewLibp2pIdentity(user1))\n\tif err != nil {\n\t\tlog.Println(\"error calling GetToken\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx = thread.NewTokenContext(ctx, tok)\n\n\tbucket1name := \"testbucket1\"\n\n\tctx = common.NewThreadNameContext(ctx, bucket1name)\n\tdbID := thread.NewIDV1(thread.Raw, 32)\n\tif err := threads.NewDB(ctx, dbID); err != nil {\n\t\tlog.Println(\"error calling threads.NewDB\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx = common.NewThreadIDContext(ctx, dbID)\n\n\tbuck, err := buckets.Create(ctx, bc.WithName(bucket1name), bc.WithPrivate(true))\n\tlog.Println(\"created bucket: \" + buck.Root.Name)\n\n\tfilepath := \"file1\"\n\tf := &bytes.Buffer{}\n\tf.Write([]byte(\"hello space\"))\n\t_, _, err = buckets.PushPath(ctx, buck.Root.Key, filepath, f)\n\n\tif err != nil {\n\t\tlog.Println(\"error pushing path\")\n\t\tlog.Fatal(err)\n\t}\n\n\troles := make(map[string]tb.Role)\n\ttpk := thread.NewLibp2pPubKey(user2.GetPublic())\n\troles[tpk.String()] = tb.Admin\n\terr = buckets.PushPathAccessRoles(ctx, buck.Root.Key, filepath, roles)\n\tif err != nil {\n\t\tlog.Println(\"error sharing path\")\n\t\tlog.Fatal(err)\n\t}\n\n\t// user 2 tries to access\n\tctx1 := context.Background()\n\tctx1 = common.NewAPIKeyContext(ctx1, key)\n\tctx1, err = common.CreateAPISigContext(ctx1, time.Now().Add(time.Minute*2), secret)\n\ttok, err = threads.GetToken(ctx1, thread.NewLibp2pIdentity(user2))\n\tctx1 = thread.NewTokenContext(ctx1, tok)\n\n\tif err != nil {\n\t\tlog.Println(\"error creating context\")\n\t\tlog.Fatal(err)\n\t}\n\n\tctx1 = common.NewThreadNameContext(ctx1, bucket1name)\n\tctx1 = common.NewThreadIDContext(ctx1, dbID)\n\tvar buf bytes.Buffer\n\terr = buckets.PullPath(ctx1, buck.Root.Key, filepath, &buf)\n\tif err != nil {\n\t\tlog.Println(\"error pulling path\")\n\t\tlog.Fatal(err)\n\t}\n\n\ts := buf.String()\n\tlog.Println(\"fetch file content: \" + s)\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/set-envs",
    "content": "export TXL_HUB_TARGET=\nexport TXL_USER_KEY=\nexport TXL_USER_SECRET=\nexport MONGO_PW=\nexport MONGO_USR=\nexport MONGO_HOST=\nexport KEY_SEED=\nexport THREAD_ID=\nexport IPFS_ADDR=\nexport JOIN_THREAD_ADDR=\nexport JOIN_THREAD_KEY="
  },
  {
    "path": "examples/textileBucketsClient/sync-test/sync-test.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/ed25519\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\ttc \"github.com/textileio/go-threads/api/client\"\n\t\"github.com/textileio/go-threads/core/thread\"\n\tbc \"github.com/textileio/textile/v2/api/bucketsd/client\"\n\tbuckets_pb \"github.com/textileio/textile/v2/api/bucketsd/pb\"\n\t\"github.com/textileio/textile/v2/api/common\"\n\t\"github.com/textileio/textile/v2/cmd\"\n\t\"google.golang.org/grpc\"\n)\n\ntype TextileBucketRoot buckets_pb.Root\n\nfunc main() {\n\tseed := os.Getenv(\"KEY_SEED\")\n\tthreadID := os.Getenv(\"THREAD_ID\")\n\thost := os.Getenv(\"TXL_HUB_TARGET\")\n\tkey := os.Getenv(\"TXL_USER_KEY\")\n\tsecret := os.Getenv(\"TXL_USER_SECRET\")\n\n\tvar threads *tc.Client\n\tvar buckets *bc.Client\n\tvar err error\n\tauth := common.Credentials{}\n\tvar opts []grpc.DialOption\n\thubTarget := host\n\tthreadstarget := host\n\topts = append(opts, grpc.WithInsecure())\n\topts = append(opts, grpc.WithPerRPCCredentials(auth))\n\n\tbuckets, err = bc.NewClient(hubTarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\tthreads, err = tc.NewClient(threadstarget, opts...)\n\tif err != nil {\n\t\tcmd.Fatal(err)\n\t}\n\n\tctx := context.Background()\n\tctx = common.NewAPIKeyContext(ctx, key)\n\tctx, err = common.CreateAPISigContext(ctx, time.Now().Add(time.Minute*2), secret)\n\n\tif err != nil {\n\t\tlog.Println(\"error creating APISigContext\")\n\t\tlog.Fatal(err)\n\t}\n\n\tsb, err := hex.DecodeString(seed)\n\tpvk := ed25519.NewKeyFromSeed(sb)\n\tpbk := make([]byte, 32)\n\tcopy(pbk, pvk[32:])\n\n\tvar unmarshalledPriv crypto.PrivKey\n\tvar unmarshalledPub crypto.PubKey\n\n\tif unmarshalledPriv, err = crypto.UnmarshalEd25519PrivateKey(pvk); err != nil {\n\t\tlog.Fatal(\"Cant get libp2p version of priv key\")\n\t\treturn\n\t}\n\n\tif unmarshalledPub, err = crypto.UnmarshalEd25519PublicKey(pbk); err != nil {\n\t\tlog.Fatal(\"Cant get libp2p version of pub key\")\n\t\treturn\n\t}\n\tlog.Println(\"got libp2p keys\")\n\n\ttok, err := threads.GetToken(ctx, thread.NewLibp2pIdentity(unmarshalledPriv))\n\tctx = thread.NewTokenContext(ctx, tok)\n\n\tvar pubKeyInBytes []byte\n\tif pubKeyInBytes, err = unmarshalledPub.Bytes(); err != nil {\n\t\tlog.Fatal(\"Cant get bytes of pubkey\")\n\t\treturn\n\t}\n\n\tctx = common.NewThreadNameContext(ctx, hex.EncodeToString(pubKeyInBytes)+\"-personal\")\n\n\tdbBytes, err := hex.DecodeString(threadID)\n\tdbID, err := thread.Cast(dbBytes)\n\tctx = common.NewThreadIDContext(ctx, dbID)\n\n\tlog.Println(\"got thread id ctx\")\n\n\tbucketList, err := buckets.List(ctx)\n\tif err != nil {\n\t\tlog.Fatal(\"Cant get list of buckets\", err)\n\t\treturn\n\t}\n\n\tresult := make([]*TextileBucketRoot, 0)\n\tfor _, r := range bucketList.Roots {\n\t\tlog.Println(\"looping through bucket: \", (*TextileBucketRoot)(r).Name)\n\t\tif (*TextileBucketRoot)(r).Name == \"personal\" {\n\t\t\t_, _, err = buckets.PushPath(ctx, (*TextileBucketRoot)(r).Key, fmt.Sprint(int32(time.Now().Unix()))+\"synctestfile.md\", &bytes.Buffer{})\n\t\t\tresult = append(result, (*TextileBucketRoot)(r))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/FleekHQ/space-daemon\n\ngo 1.14\n\nreplace github.com/textileio/go-threads => github.com/FleekHQ/go-threads v1.0.1-0.20201028195307-d9371c20fe66\n\nreplace github.com/textileio/textile/v2 => github.com/FleekHQ/textile/v2 v2.0.0-20201127024116-cee5aaade92c\n\nreplace github.com/libp2p/go-libp2p-pubsub => github.com/libp2p/go-libp2p-pubsub v0.3.2\n\nreplace github.com/libp2p/go-libp2p-core => github.com/libp2p/go-libp2p-core v0.6.1\n\nreplace github.com/libp2p/go-libp2p => github.com/libp2p/go-libp2p v0.10.3\n\nreplace github.com/libp2p/go-libp2p-swarm => github.com/libp2p/go-libp2p-swarm v0.2.8\n\nrequire (\n\tbazil.org/fuse v0.0.0-20200117225306-7b5117fecadc\n\tgithub.com/99designs/keyring v1.1.5\n\tgithub.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2\n\tgithub.com/blevesearch/bleve v1.0.12\n\tgithub.com/creamdog/gonfig v0.0.0-20160810132730-80d86bfb5a37\n\tgithub.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect\n\tgithub.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect\n\tgithub.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect\n\tgithub.com/dgraph-io/badger v1.6.2\n\tgithub.com/dgrijalva/jwt-go v3.2.0+incompatible\n\tgithub.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3\n\tgithub.com/golang/protobuf v1.4.3\n\tgithub.com/grpc-ecosystem/go-grpc-middleware v1.2.2\n\tgithub.com/grpc-ecosystem/grpc-gateway v1.14.6\n\tgithub.com/hsanjuan/ipfs-lite v1.1.17 // indirect\n\tgithub.com/improbable-eng/grpc-web v0.13.0\n\tgithub.com/ipfs/go-cid v0.0.7\n\tgithub.com/ipfs/go-ipfs v0.7.0\n\tgithub.com/ipfs/go-ipfs-chunker v0.0.5\n\tgithub.com/ipfs/go-ipfs-config v0.10.0\n\tgithub.com/ipfs/go-ipfs-files v0.0.8\n\tgithub.com/ipfs/go-ipfs-http-client v0.1.0\n\tgithub.com/ipfs/go-ipld-format v0.2.0\n\tgithub.com/ipfs/go-merkledag v0.3.2\n\tgithub.com/ipfs/go-path v0.0.8 // indirect\n\tgithub.com/ipfs/go-unixfs v0.2.4\n\tgithub.com/ipfs/interface-go-ipfs-core v0.4.0\n\tgithub.com/jmhodges/levigo v1.0.0 // indirect\n\tgithub.com/joho/godotenv v1.3.0\n\tgithub.com/keybase/go-kext v0.0.0-20200218013902-e4a86908886a\n\tgithub.com/libp2p/go-libp2p-connmgr v0.2.4\n\tgithub.com/libp2p/go-libp2p-core v0.7.0\n\tgithub.com/libp2p/go-libp2p-crypto v0.1.0\n\tgithub.com/mitchellh/go-homedir v1.1.0\n\tgithub.com/multiformats/go-multiaddr v0.3.1\n\tgithub.com/multiformats/go-multibase v0.0.3\n\tgithub.com/multiformats/go-multihash v0.0.14\n\tgithub.com/odeke-em/go-utils v0.0.0-20170224015737-e8ebaed0777a\n\tgithub.com/onsi/ginkgo v1.14.2\n\tgithub.com/onsi/gomega v1.10.3\n\tgithub.com/opentracing/opentracing-go v1.2.0\n\tgithub.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/prometheus/client_golang v1.7.1 // indirect\n\tgithub.com/radovskyb/watcher v1.0.7\n\tgithub.com/rs/cors v1.7.0\n\tgithub.com/sirupsen/logrus v1.7.0\n\tgithub.com/stretchr/testify v1.6.1\n\tgithub.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect\n\tgithub.com/textileio/dcrypto v0.0.1\n\tgithub.com/textileio/go-threads v1.0.1\n\tgithub.com/textileio/textile/v2 v2.1.7\n\tgithub.com/tyler-smith/go-bip39 v1.0.2\n\tgithub.com/uber/jaeger-client-go v2.23.1+incompatible\n\tgolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a\n\tgolang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0\n\tgolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208\n\tgolang.org/x/sys v0.0.0-20201113135734-0a15ea8d9b02\n\tgoogle.golang.org/genproto v0.0.0-20200702021140-07506425bd67\n\tgoogle.golang.org/grpc v1.33.1\n\tgoogle.golang.org/protobuf v1.25.0\n\tgorm.io/driver/sqlite v1.1.3\n\tgorm.io/gorm v1.20.5\n\tgotest.tools v2.2.0+incompatible\n)\n"
  },
  {
    "path": "go.sum",
    "content": "bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=\nbazil.org/fuse v0.0.0-20200117225306-7b5117fecadc h1:utDghgcjE8u+EBjHOgYT+dJPcnDF05KqWMBcjuJy510=\nbazil.org/fuse v0.0.0-20200117225306-7b5117fecadc/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.37.0 h1:69FNAINiZfsEuwH3fKq8QrAAnHz+2m4XL4kVYi5BX0Q=\ncloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncontrib.go.opencensus.io/exporter/jaeger v0.1.0 h1:WNc9HbA38xEQmsI40Tjd/MNU/g8byN2Of7lwIjv0Jdc=\ncontrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA=\ncontrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A=\ncontrib.go.opencensus.io/exporter/prometheus v0.2.0/go.mod h1:TYmVAyE8Tn1lyPcltF5IYYfWp2KHu7lQGIZnj8iZMys=\ndmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ndmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=\ndmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=\ndmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=\ngit.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=\ngithub.com/99designs/keyring v1.1.5 h1:wLv7QyzYpFIyMSwOADq1CLTF9KbjbBfcnfmOGJ64aO4=\ngithub.com/99designs/keyring v1.1.5/go.mod h1:7hsVvt2qXgtadGevGJ4ujg+u8m6SpJ5TpHqTozIPqf0=\ngithub.com/AlecAivazis/survey/v2 v2.0.7/go.mod h1:mlizQTaPjnR4jcpwRSaSlkbsRfYFEyKgLQvYTzxxiHA=\ngithub.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190823232136-616930265c33 h1:2/E2IVdZoHh/aCBq4Gchy2MGWkTmbReP46/Wnt9qhKs=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190823232136-616930265c33/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=\ngithub.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=\ngithub.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=\ngithub.com/FleekHQ/go-threads v1.0.1-0.20201028195307-d9371c20fe66 h1:JppBUaU4v56XxHj8fOMK4jjYCKCdiEMOrhXibu/Jbs8=\ngithub.com/FleekHQ/go-threads v1.0.1-0.20201028195307-d9371c20fe66/go.mod h1:mQgVlEzC++pJ0+EyrhW19y5ZHa8xogdYQq/8pLUvOm4=\ngithub.com/FleekHQ/space-daemon v0.0.33/go.mod h1:dpCcfU+b6FP+whLdnPwaSAbcmVGQwYcNedsbEumE/Mc=\ngithub.com/FleekHQ/textile/v2 v2.0.0-20201116173414-db43a5d7591f h1:Phw2fWt6eJ2SAVXJNZaGXqQyT3I5HDOxibM5ocqVLvM=\ngithub.com/FleekHQ/textile/v2 v2.0.0-20201116173414-db43a5d7591f/go.mod h1:BXhNUwvl7dR0fvNi7xaKTSUEent09vJ7bhNYkMNzQ7c=\ngithub.com/FleekHQ/textile/v2 v2.0.0-20201127024116-cee5aaade92c h1:Qu2C3VP+G0maRQYrOxyU0HTqVBNXAjh/5Uyw3Y/DIQ8=\ngithub.com/FleekHQ/textile/v2 v2.0.0-20201127024116-cee5aaade92c/go.mod h1:telji7Pfrll6wugWd0cSk1u3FSsTESOPfL39r0QTloU=\ngithub.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=\ngithub.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=\ngithub.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=\ngithub.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee/go.mod h1:W0GbEAA4uFNYOGG2cJpmFJ04E6SD1NLELPYZB57/7AY=\ngithub.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=\ngithub.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=\ngithub.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=\ngithub.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=\ngithub.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=\ngithub.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=\ngithub.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=\ngithub.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo=\ngithub.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=\ngithub.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=\ngithub.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=\ngithub.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=\ngithub.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3oM7gXIttpYDAJXpVNnSCiUMYBLIZ6cb1t+Ip982MRo=\ngithub.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=\ngithub.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s=\ngithub.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=\ngithub.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=\ngithub.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=\ngithub.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=\ngithub.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=\ngithub.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=\ngithub.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2 h1:swGeCLPiUQ647AIRnFxnAHdzlg6IPpmU6QdkOPZINt8=\ngithub.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2/go.mod h1:Juc2PrI3wtNfUwptSvAIeNx+HrETwHQs6nf+TkOJlOA=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 h1:iW0a5ljuFxkLGPNem5Ui+KBjFJzKg4Fv2fnxe4dvzpM=\ngithub.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h1:Y2QMoi1vgtOIfc+6DhrMOGkLoGzqSV2rKp4Sm+opsyA=\ngithub.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=\ngithub.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI=\ngithub.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=\ngithub.com/apoorvam/goterminal v0.0.0-20180523175556-614d345c47e5/go.mod h1:E7x8aDc3AQzDKjEoIZCt+XYheHk2OkP+p2UgeNjecH8=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=\ngithub.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=\ngithub.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=\ngithub.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=\ngithub.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=\ngithub.com/aws/aws-sdk-go v1.29.15/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=\ngithub.com/aws/aws-sdk-go v1.32.11 h1:1nYF+Tfccn/hnAZsuwPPMSCVUVnx3j6LKOpx/WhgH0A=\ngithub.com/aws/aws-sdk-go v1.32.11/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=\ngithub.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=\ngithub.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=\ngithub.com/benbjohnson/clock v1.0.1/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=\ngithub.com/benbjohnson/clock v1.0.2 h1:Z0CN0Yb4ig9sGPXkvAQcGJfnrrMQ5QYLCMPRi9iD7YE=\ngithub.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=\ngithub.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=\ngithub.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=\ngithub.com/blevesearch/bleve v1.0.12 h1:2qJUSBpU/h1z8x3ERRB5WwpmEpJwoivPqmDpHzv4tuk=\ngithub.com/blevesearch/bleve v1.0.12/go.mod h1:G0ErXWdIrUSYZLPoMpS9Z3saTnTsk4ebhPsVv/+0nxk=\ngithub.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040 h1:SjYVcfJVZoCfBlg+fkaq2eoZHTf5HaJfaTeTkOtyfHQ=\ngithub.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040/go.mod h1:WH+MU2F4T0VmSdaPX+Wu5GYoZBrYWdOZWSjzvYcDmqQ=\ngithub.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=\ngithub.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=\ngithub.com/blevesearch/mmap-go v1.0.2 h1:JtMHb+FgQCTTYIhtMvimw15dJwu1Y5lrZDMOFXVWPk0=\ngithub.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=\ngithub.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac=\ngithub.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=\ngithub.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=\ngithub.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=\ngithub.com/blevesearch/zap/v11 v11.0.12 h1:ZA+80yajko2tXr1kmbSoVRMCo0mFZAVJmoijjYsZuwc=\ngithub.com/blevesearch/zap/v11 v11.0.12/go.mod h1:JLfFhc8DWP01zMG/6VwEY2eAnlJsTN1vDE4S0rC5Y78=\ngithub.com/blevesearch/zap/v12 v12.0.12 h1:9eWaL9/2hcjy1VR3lrl/b+kWh5G7w/BkNYI07mWActw=\ngithub.com/blevesearch/zap/v12 v12.0.12/go.mod h1:1HrB4hhPfI8u8x4SPYbluhb8xhflpPvvj8EcWImNnJY=\ngithub.com/blevesearch/zap/v13 v13.0.4 h1:eoRvJmLeIQUs1mAF+fAFALg1dPHOI1e1KFuXL0I7us4=\ngithub.com/blevesearch/zap/v13 v13.0.4/go.mod h1:YdB7UuG7TBWu/1dz9e2SaLp1RKfFfdJx+ulIK5HR1bA=\ngithub.com/blevesearch/zap/v14 v14.0.3 h1:ccEv296u6DEUHFF9U4W2E/6/WkbuDrS9/1VJM34SCzA=\ngithub.com/blevesearch/zap/v14 v14.0.3/go.mod h1:oObAhcDHw7p1ahiTCqhRkdxdl7UA8qpvX10pSgrTMHc=\ngithub.com/blevesearch/zap/v15 v15.0.1 h1:jEism63eY+qdcvwXH0K8MiKhv5tb10T1k7SNx6fauCM=\ngithub.com/blevesearch/zap/v15 v15.0.1/go.mod h1:ho0frqAex2ktT9cYFAxQpoQXsxb/KEfdjpx4s49rf/M=\ngithub.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=\ngithub.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=\ngithub.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d h1:QgeLLoPD3kRVmeu/1al9iIpIANMi9O1zXFm8BnYGCJg=\ngithub.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d/go.mod h1:Jbj8eKecMNwf0KFI75skSUZqMB4UCRcndUScVBTWyUI=\ngithub.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=\ngithub.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=\ngithub.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=\ngithub.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U=\ngithub.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=\ngithub.com/caarlos0/spin v1.1.0/go.mod h1:HOC4pUvfhjXR2yDt+sEY9dRc2m4CCaK5z5oQYAbzXSA=\ngithub.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=\ngithub.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=\ngithub.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=\ngithub.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=\ngithub.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=\ngithub.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=\ngithub.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=\ngithub.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=\ngithub.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cloudflare/cloudflare-go v0.11.6 h1:gErXaYucoS8aHdmoJnF4RMFiXJH449sk6rCtoP6EhrE=\ngithub.com/cloudflare/cloudflare-go v0.11.6/go.mod h1:lmCbgQdBeSQlMv0W0OSqoGgl8aFrgc5oXHhWMt47dh0=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=\ngithub.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=\ngithub.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=\ngithub.com/cockroachdb/pebble v0.0.0-20200916222308-4e219a90ba5b/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ=\ngithub.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ=\ngithub.com/cockroachdb/redact v0.0.0-20200622112456-cd282804bbd3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=\ngithub.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=\ngithub.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=\ngithub.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=\ngithub.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=\ngithub.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=\ngithub.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=\ngithub.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=\ngithub.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=\ngithub.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=\ngithub.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=\ngithub.com/couchbase/vellum v1.0.2 h1:BrbP0NKiyDdndMPec8Jjhy0U47CZ0Lgx3xUC2r9rZqw=\ngithub.com/couchbase/vellum v1.0.2/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLBJ1uAg1W4=\ngithub.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg=\ngithub.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE=\ngithub.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/creamdog/gonfig v0.0.0-20160810132730-80d86bfb5a37 h1:1oltS/xFsArksN6n2nXIYU5tkkDBqKgpcOvfPsTepR4=\ngithub.com/creamdog/gonfig v0.0.0-20160810132730-80d86bfb5a37/go.mod h1:Hhbh5su1JZ8cglUlxBwQjz0uwtmFhV/0D6DgvU3oT+4=\ngithub.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=\ngithub.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=\ngithub.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=\ngithub.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=\ngithub.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=\ngithub.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=\ngithub.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=\ngithub.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=\ngithub.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=\ngithub.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=\ngithub.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=\ngithub.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=\ngithub.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk=\ngithub.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=\ngithub.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=\ngithub.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=\ngithub.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=\ngithub.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=\ngithub.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=\ngithub.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=\ngithub.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=\ngithub.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=\ngithub.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=\ngithub.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=\ngithub.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ=\ngithub.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=\ngithub.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y=\ngithub.com/drand/drand v0.9.2-0.20200616080806-a94e9c1636a4/go.mod h1:Bu8QYdU0YdB2ZQZezHxabmOIciddiwLRnyV4nuZ2HQE=\ngithub.com/drand/drand v1.2.1/go.mod h1:j0P7RGmVaY7E/OuO2yQOcQj7OgeZCuhgu2gdv0JAm+g=\ngithub.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw=\ngithub.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw=\ngithub.com/drand/kyber v1.1.0/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw=\ngithub.com/drand/kyber v1.1.4/go.mod h1:9+IgTq7kadePhZg7eRwSD7+bA+bmvqRK+8DtmoV5a3U=\ngithub.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk=\ngithub.com/drand/kyber-bls12381 v0.2.0/go.mod h1:zQip/bHdeEB6HFZSU3v+d3cQE0GaBVQw9aR2E7AdoeI=\ngithub.com/drand/kyber-bls12381 v0.2.1/go.mod h1:JwWn4nHO9Mp4F5qCie5sVIPQZ0X6cw8XAeMRvc/GXBE=\ngithub.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU=\ngithub.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=\ngithub.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=\ngithub.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=\ngithub.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=\ngithub.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\ngithub.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=\ngithub.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=\ngithub.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=\ngithub.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 h1:QV0ZrfBLpFc2KDk+a4LJefDczXnonRwrYrQJY/9L4dA=\ngithub.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302/go.mod h1:qBlWZqWeVx9BjvqBsnC/8RUlAYpIFmPvgROcw0n1scE=\ngithub.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE=\ngithub.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=\ngithub.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=\ngithub.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A=\ngithub.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg=\ngithub.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=\ngithub.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=\ngithub.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/filecoin-project/chain-validation v0.0.6-0.20200615191232-6be1a8c6ed09/go.mod h1:HEJn6kOXMNhCNBYNTO/lrEI7wSgqCOR6hN5ecfYUnC8=\ngithub.com/filecoin-project/filecoin-ffi v0.0.0-20200326153646-e899cc1dd072/go.mod h1:PtH9YP0rURHUKHrKeEBeWg/BqIBMQOz8wtlXlVGREBE=\ngithub.com/filecoin-project/filecoin-ffi v0.26.1-0.20200508175440-05b30afeb00d/go.mod h1:vlQ7sDkbrtM70QMJFDvEyTDywY5SvIjadRCUB+76l90=\ngithub.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d/go.mod h1:XE4rWG1P7zWPaC11Pkn1CVR20stqN52MnMkIrF4q6ZU=\ngithub.com/filecoin-project/filecoin-ffi v0.30.4-0.20200910194244-f640612a1a1f/go.mod h1:+If3s2VxyjZn+KGGZIoRXBDSFQ9xL404JBJGf4WhEj0=\ngithub.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=\ngithub.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=\ngithub.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef/go.mod h1:SrA+pWVoUivqKOfC+ckVYbx41hWz++HxJcrlmHNnebU=\ngithub.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8=\ngithub.com/filecoin-project/go-address v0.0.5-0.20201103152444-f2023ef3f5bb/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8=\ngithub.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg=\ngithub.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg=\ngithub.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs=\ngithub.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20201006184820-924ee87a1349/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g=\ngithub.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw=\ngithub.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY=\ngithub.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY=\ngithub.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM=\ngithub.com/filecoin-project/go-bitfield v0.2.3-0.20201110211213-fe2c1862e816/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM=\ngithub.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg=\ngithub.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ=\ngithub.com/filecoin-project/go-data-transfer v0.3.0/go.mod h1:cONglGP4s/d+IUQw5mWZrQK+FQATQxr3AXzi4dRh0l4=\ngithub.com/filecoin-project/go-data-transfer v1.0.1/go.mod h1:UxvfUAY9v3ub0a21BSK9u3pB2aq30Y0KMsG+w9/ysyo=\ngithub.com/filecoin-project/go-data-transfer v1.1.0/go.mod h1:ZAH51JZFR8NZC4FPiDPG+swjgui0q6zTMJbztc6pHhY=\ngithub.com/filecoin-project/go-ds-versioning v0.1.0/go.mod h1:mp16rb4i2QPmxBnmanUx8i/XANp+PFCCJWiAb+VW4/s=\ngithub.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA=\ngithub.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=\ngithub.com/filecoin-project/go-fil-markets v0.3.0/go.mod h1:UXsXi43AyUQ5ieb4yIaLgk4PVt7TAbl1UCccuNw+7ds=\ngithub.com/filecoin-project/go-fil-markets v1.0.4/go.mod h1:AJySOJC00JRWEZzRG2KsfUnqEf5ITXxeX09BE9N4f9c=\ngithub.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=\ngithub.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI=\ngithub.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24/go.mod h1:j6zV//WXIIY5kky873Q3iIKt/ViOE8rcijovmpxrXzM=\ngithub.com/filecoin-project/go-jsonrpc v0.1.2-0.20201008195726-68c6a2704e49/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=\ngithub.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ=\ngithub.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE=\ngithub.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak=\ngithub.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc=\ngithub.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc=\ngithub.com/filecoin-project/go-paramfetch v0.0.2-0.20200605171344-fcac609550ca/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc=\ngithub.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc=\ngithub.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=\ngithub.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=\ngithub.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g=\ngithub.com/filecoin-project/go-state-types v0.0.0-20201013222834-41ea465f274f/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g=\ngithub.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=\ngithub.com/filecoin-project/go-statemachine v0.0.0-20200612181802-4eb3d0c68eba/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=\ngithub.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=\ngithub.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI=\ngithub.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8=\ngithub.com/filecoin-project/lotus v0.4.0/go.mod h1:RGmcSJ6+0D3vXcBgNk6T7fT9Y5UBZ+Aowse3cTi+yZA=\ngithub.com/filecoin-project/lotus v1.1.3/go.mod h1:cyY86E8Z30ka3OtlwUoRAFMBjejNHhZqudX6DfZ0ABg=\ngithub.com/filecoin-project/sector-storage v0.0.0-20200615154852-728a47ab99d6/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM=\ngithub.com/filecoin-project/sector-storage v0.0.0-20200618073200-d9de9b7cb4b4/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM=\ngithub.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA=\ngithub.com/filecoin-project/specs-actors v0.0.0-20200226200336-94c9b92b2775/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU=\ngithub.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y=\ngithub.com/filecoin-project/specs-actors v0.6.0/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY=\ngithub.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY=\ngithub.com/filecoin-project/specs-actors v0.6.2-0.20200617175406-de392ca14121/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY=\ngithub.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4=\ngithub.com/filecoin-project/specs-actors v0.9.12/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao=\ngithub.com/filecoin-project/specs-actors/v2 v2.0.1/go.mod h1:v2NZVYinNIKA9acEMBm5wWXxqv5+frFEbekBFemYghY=\ngithub.com/filecoin-project/specs-actors/v2 v2.2.0/go.mod h1:rlv5Mx9wUhV8Qsz+vUezZNm+zL4tK08O0HreKKPB2Wc=\ngithub.com/filecoin-project/specs-storage v0.1.0/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k=\ngithub.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g=\ngithub.com/filecoin-project/storage-fsm v0.0.0-20200617183754-4380106d3e94/go.mod h1:q1YCutTSMq/yGYvDPHReT37bPfDLHltnwJutzR9kOY0=\ngithub.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E=\ngithub.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=\ngithub.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=\ngithub.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=\ngithub.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=\ngithub.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=\ngithub.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=\ngithub.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/gabriel-vasile/mimetype v1.1.0/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=\ngithub.com/gabriel-vasile/mimetype v1.1.1 h1:qbN9MPuRf3bstHu9zkI9jDWNfH//9+9kHxr9oRBBBOA=\ngithub.com/gabriel-vasile/mimetype v1.1.1/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=\ngithub.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8=\ngithub.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=\ngithub.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=\ngithub.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=\ngithub.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=\ngithub.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=\ngithub.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2 h1:xLG16iua01X7Gzms9045s2Y2niNpvSY/Zb1oBwgNYZY=\ngithub.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=\ngithub.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=\ngithub.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=\ngithub.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=\ngithub.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=\ngithub.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=\ngithub.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=\ngithub.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=\ngithub.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=\ngithub.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=\ngithub.com/go-chi/chi v4.0.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=\ngithub.com/go-chi/chi v4.1.1+incompatible h1:MmTgB0R8Bt/jccxp+t6S/1VGIKdJw5J74CK/c9tTfA4=\ngithub.com/go-chi/chi v4.1.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=\ngithub.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=\ngithub.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=\ngithub.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=\ngithub.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=\ngithub.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=\ngithub.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=\ngithub.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=\ngithub.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=\ngithub.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=\ngithub.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=\ngithub.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=\ngithub.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=\ngithub.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=\ngithub.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=\ngithub.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=\ngithub.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=\ngithub.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=\ngithub.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=\ngithub.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=\ngithub.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=\ngithub.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=\ngithub.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=\ngithub.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=\ngithub.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=\ngithub.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=\ngithub.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=\ngithub.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=\ngithub.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=\ngithub.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=\ngithub.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=\ngithub.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=\ngithub.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=\ngithub.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=\ngithub.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=\ngithub.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=\ngithub.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=\ngithub.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=\ngithub.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=\ngithub.com/gogo/googleapis v1.3.1/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU=\ngithub.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI=\ngithub.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=\ngithub.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc=\ngithub.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA=\ngithub.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=\ngithub.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=\ngithub.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws=\ngithub.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=\ngithub.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=\ngithub.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=\ngithub.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY=\ngithub.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=\ngithub.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=\ngithub.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=\ngithub.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=\ngithub.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=\ngithub.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=\ngithub.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=\ngithub.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=\ngithub.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=\ngithub.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=\ngithub.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=\ngithub.com/gosuri/uilive v0.0.4/go.mod h1:V/epo5LjjlDE5RJUcqx8dbw+zc93y5Ya3yg8tfZ74VI=\ngithub.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=\ngithub.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=\ngithub.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=\ngithub.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=\ngithub.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=\ngithub.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=\ngithub.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=\ngithub.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3vH7VqgtMxQ=\ngithub.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=\ngithub.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=\ngithub.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE=\ngithub.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=\ngithub.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k=\ngithub.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8=\ngithub.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY=\ngithub.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY=\ngithub.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=\ngithub.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=\ngithub.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=\ngithub.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=\ngithub.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=\ngithub.com/hodgesds/perf-utils v0.0.8/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/hsanjuan/ipfs-lite v1.1.12/go.mod h1:YBI2I6SLkPCvVK/MjxNKy6Ihs9rQPPHnvCvdSNlXysE=\ngithub.com/hsanjuan/ipfs-lite v1.1.15/go.mod h1:LZffwuToye++XukPW/GUAw5XewT+t2lgZl8h/8RqFfs=\ngithub.com/hsanjuan/ipfs-lite v1.1.17 h1:Rk/QZD9TeSbRIm+7FbziZPMXRHr7XNVRx+YRJnLWQLc=\ngithub.com/hsanjuan/ipfs-lite v1.1.17/go.mod h1:ZetJanzQEAqWj+OwzIppE/S7x+Azu4WFF6PNMLnQGoY=\ngithub.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=\ngithub.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=\ngithub.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=\ngithub.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/improbable-eng/grpc-web v0.12.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=\ngithub.com/improbable-eng/grpc-web v0.13.0 h1:7XqtaBWaOCH0cVGKHyvhtcuo6fgW32Y10yRKrDHFHOc=\ngithub.com/improbable-eng/grpc-web v0.13.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=\ngithub.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=\ngithub.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI=\ngithub.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=\ngithub.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=\ngithub.com/ipfs/go-bitswap v0.0.3/go.mod h1:jadAZYsP/tcRMl47ZhFxhaNuDQoXawT8iHMg+iFoQbg=\ngithub.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis=\ngithub.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0=\ngithub.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs=\ngithub.com/ipfs/go-bitswap v0.1.3/go.mod h1:YEQlFy0kkxops5Vy+OxWdRSEZIoS7I7KDIwoa5Chkps=\ngithub.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM=\ngithub.com/ipfs/go-bitswap v0.2.8/go.mod h1:2Yjog0GMdH8+AsxkE0DI9D2mANaUTxbVVav0pPoZoug=\ngithub.com/ipfs/go-bitswap v0.2.13/go.mod h1:SDXpLeKZagyVVc8/z7sGtmM/lz8lyAmSzrUx3Ge3GXw=\ngithub.com/ipfs/go-bitswap v0.2.19/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo=\ngithub.com/ipfs/go-bitswap v0.2.20/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo=\ngithub.com/ipfs/go-bitswap v0.3.1 h1:YG2QTj7xEJsSvttivoKl4gBbDYtkxsFoliKtepNncyc=\ngithub.com/ipfs/go-bitswap v0.3.1/go.mod h1:AyWWfN3moBzQX0banEtfKOfbXb3ZeoOeXnZGNPV9S6w=\ngithub.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc=\ngithub.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE=\ngithub.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=\ngithub.com/ipfs/go-blockservice v0.0.3/go.mod h1:/NNihwTi6V2Yr6g8wBI+BSwPuURpBRMtYNGrlxZ8KuI=\ngithub.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So=\ngithub.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M=\ngithub.com/ipfs/go-blockservice v0.1.1/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I=\ngithub.com/ipfs/go-blockservice v0.1.2/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I=\ngithub.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU=\ngithub.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU=\ngithub.com/ipfs/go-blockservice v0.1.4 h1:Vq+MlsH8000KbbUciRyYMEw/NNP8UAGmcqKi4uWmFGA=\ngithub.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU=\ngithub.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=\ngithub.com/ipfs/go-cid v0.0.4-0.20191112011718-79e75dffeb10/go.mod h1:/BYOuUoxkE+0f6tGzlzMvycuN+5l35VOR4Bpg2sCmds=\ngithub.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=\ngithub.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=\ngithub.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=\ngithub.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=\ngithub.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=\ngithub.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=\ngithub.com/ipfs/go-cidutil v0.0.2 h1:CNOboQf1t7Qp0nuNh8QMmhJs0+Q//bRL1axtCnIB1Yo=\ngithub.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s=\ngithub.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=\ngithub.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=\ngithub.com/ipfs/go-datastore v0.3.0/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=\ngithub.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=\ngithub.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.2/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=\ngithub.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg=\ngithub.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs=\ngithub.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=\ngithub.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=\ngithub.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=\ngithub.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=\ngithub.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=\ngithub.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=\ngithub.com/ipfs/go-ds-badger v0.2.4/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=\ngithub.com/ipfs/go-ds-badger v0.2.6 h1:Hy8jw4rifxtRDrqpvC1yh36oIyE37KDzsUzlHUPOFiU=\ngithub.com/ipfs/go-ds-badger v0.2.6/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA=\ngithub.com/ipfs/go-ds-badger2 v0.1.0/go.mod h1:pbR1p817OZbdId9EvLOhKBgUVTM3BMCSTan78lDDVaw=\ngithub.com/ipfs/go-ds-badger2 v0.1.1-0.20200708190120-187fc06f714e/go.mod h1:lJnws7amT9Ehqzta0gwMrRsURU04caT0iRPr1W8AsOU=\ngithub.com/ipfs/go-ds-flatfs v0.4.4/go.mod h1:e4TesLyZoA8k1gV/yCuBTnt2PJtypn4XUlB5n8KQMZY=\ngithub.com/ipfs/go-ds-flatfs v0.4.5 h1:4QceuKEbH+HVZ2ZommstJMi3o3II+dWS3IhLaD7IGHs=\ngithub.com/ipfs/go-ds-flatfs v0.4.5/go.mod h1:e4TesLyZoA8k1gV/yCuBTnt2PJtypn4XUlB5n8KQMZY=\ngithub.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=\ngithub.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=\ngithub.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ds-leveldb v0.4.2 h1:QmQoAJ9WkPMUfBLnu1sBVy0xWWlJPg0m4kRAiJL9iaw=\ngithub.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=\ngithub.com/ipfs/go-ds-measure v0.1.0 h1:vE4TyY4aeLeVgnnPBC5QzKIjKrqzha0NCujTfgvVbVQ=\ngithub.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY=\ngithub.com/ipfs/go-ds-pebble v0.0.2-0.20200921225637-ce220f8ac459/go.mod h1:oh4liWHulKcDKVhCska5NLelE3MatWl+1FwSz3tY91g=\ngithub.com/ipfs/go-filestore v0.0.3/go.mod h1:dvXRykFzyyXN2CdNlRGzDAkXMDPyI+D7JE066SiKLSE=\ngithub.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEPb0=\ngithub.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM=\ngithub.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y=\ngithub.com/ipfs/go-fs-lock v0.0.5/go.mod h1:fq8gXFwbi1on9KScveHuVJ2wjuqo5jaDgCtZdKLuCO8=\ngithub.com/ipfs/go-fs-lock v0.0.6 h1:sn3TWwNVQqSeNjlWy6zQ1uUGAZrV3hPOyEA6y1/N2a0=\ngithub.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM=\ngithub.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE=\ngithub.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE=\ngithub.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE=\ngithub.com/ipfs/go-graphsync v0.4.2/go.mod h1:/VmbZTUdUMTbNkgzAiCEucIIAU3BkLE2cZrDCVUhyi0=\ngithub.com/ipfs/go-graphsync v0.4.3/go.mod h1:mPOwDYv128gf8gxPFgXnz4fNrSYPsWyqisJ7ych+XDY=\ngithub.com/ipfs/go-graphsync v0.5.0 h1:iaByvxq88Ys1KcaQzTS1wmRhNsNEo3SaUiSGqTSbGmM=\ngithub.com/ipfs/go-graphsync v0.5.0/go.mod h1:e2ZxnClqBBYAtd901g9vXMJzS47labjAtOzsWtOzKNk=\ngithub.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE=\ngithub.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg=\ngithub.com/ipfs/go-hamt-ipld v0.1.1-0.20200501020327-d53d20a7063e/go.mod h1:giiPqWYCnRBYpNTsJ/EX1ojldX5kTXrXYckSJQ7ko9M=\ngithub.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f/go.mod h1:phOFBB7W73N9dg1glcb1fQ9HtQFDUpeyJgatW8ns0bw=\ngithub.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk=\ngithub.com/ipfs/go-ipfs v0.6.1-0.20200817102359-90a573354af2/go.mod h1:mP0bh6FMyOF6SI6W/LsKvPyP1mxHCsVXQFIBAqnde4s=\ngithub.com/ipfs/go-ipfs v0.7.0 h1:8qJkP8PounMHhbWJ+sOij5FV3mlJhP+mhCg2JeDV1mg=\ngithub.com/ipfs/go-ipfs v0.7.0/go.mod h1:4UNBZMgbAZ6/+xUZDlMkGxMFPiu1RB67+TaNVvKV7ZQ=\ngithub.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08=\ngithub.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw=\ngithub.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ=\ngithub.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU=\ngithub.com/ipfs/go-ipfs-blockstore v1.0.1/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE=\ngithub.com/ipfs/go-ipfs-blockstore v1.0.2 h1:Z8nUlBHK7wVKPKliQCQR9tLgUtz4J2QRbqFcJrqzM+E=\ngithub.com/ipfs/go-ipfs-blockstore v1.0.2/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE=\ngithub.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk=\ngithub.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw=\ngithub.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8=\ngithub.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8=\ngithub.com/ipfs/go-ipfs-cmds v0.1.0/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8=\ngithub.com/ipfs/go-ipfs-cmds v0.2.2/go.mod h1:kqlUrp6m2ceoaJe40cXpADCi5aS6NKRn0NIeuLp5CeM=\ngithub.com/ipfs/go-ipfs-cmds v0.3.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=\ngithub.com/ipfs/go-ipfs-cmds v0.4.0 h1:xUavIxA9Ts8U6PAHmQBvDGMlGfUrQ13Rymd+5t8LIF4=\ngithub.com/ipfs/go-ipfs-cmds v0.4.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=\ngithub.com/ipfs/go-ipfs-config v0.0.11/go.mod h1:wveA8UT5ywN26oKStByzmz1CO6cXwLKKM6Jn/Hfw08I=\ngithub.com/ipfs/go-ipfs-config v0.5.3/go.mod h1:nSLCFtlaL+2rbl3F+9D4gQZQbT1LjRKx7TJg/IHz6oM=\ngithub.com/ipfs/go-ipfs-config v0.9.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=\ngithub.com/ipfs/go-ipfs-config v0.10.0 h1:QdTFdqCg3Zpvpz6wHc6B7UGwSnierqq0h8BwyUntjGA=\ngithub.com/ipfs/go-ipfs-config v0.10.0/go.mod h1:Ei/FLgHGTdPyqCPK0oPCwGTe8VSnsjJjx7HZqUb6Ry0=\ngithub.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=\ngithub.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=\ngithub.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo=\ngithub.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs=\ngithub.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g=\ngithub.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE=\ngithub.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM=\ngithub.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM=\ngithub.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew=\ngithub.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0=\ngithub.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=\ngithub.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=\ngithub.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=\ngithub.com/ipfs/go-ipfs-files v0.0.7/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs=\ngithub.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg=\ngithub.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs=\ngithub.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA=\ngithub.com/ipfs/go-ipfs-http-client v0.0.5/go.mod h1:8EKP9RGUrUex4Ff86WhnKU7seEBOtjdgXlY9XHYvYMw=\ngithub.com/ipfs/go-ipfs-http-client v0.0.6-0.20200512220018-7002cce28cb1/go.mod h1:h3VsuLMjVWwiTwH03gMfKvlFNur8m8a0HHk3f3KsEeg=\ngithub.com/ipfs/go-ipfs-http-client v0.1.0 h1:YrJ+/vqmZF1ignpxfHUaJEax7e4tgbaFCTLfIS5yFZY=\ngithub.com/ipfs/go-ipfs-http-client v0.1.0/go.mod h1:8e2dQbntMZKxLfny+tyXJ7bJHZFERp/2vyzZdvkeLMc=\ngithub.com/ipfs/go-ipfs-pinner v0.0.4 h1:EmxhS3vDsCK/rZrsgxX0Le9m2drBcGlUd7ah/VyFYVE=\ngithub.com/ipfs/go-ipfs-pinner v0.0.4/go.mod h1:s4kFZWLWGDudN8Jyd/GTpt222A12C2snA2+OTdy/7p8=\ngithub.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=\ngithub.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=\ngithub.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=\ngithub.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY=\ngithub.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=\ngithub.com/ipfs/go-ipfs-provider v0.4.3 h1:k54OHXZcFBkhL6l3GnPS9PfpaLeLqZjVASG1bgfBdfQ=\ngithub.com/ipfs/go-ipfs-provider v0.4.3/go.mod h1:rcQBVqfblDQRk5LaCtf2uxuKxMJxvKmF5pLS0pO4au4=\ngithub.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs=\ngithub.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ=\ngithub.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY=\ngithub.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=\ngithub.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=\ngithub.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=\ngithub.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8=\ngithub.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc=\ngithub.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc=\ngithub.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4=\ngithub.com/ipfs/go-ipld-cbor v0.0.5-0.20200204214505-252690b78669/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4=\ngithub.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4=\ngithub.com/ipfs/go-ipld-cbor v0.0.5 h1:ovz4CHKogtG2KB/h1zUp5U0c/IzZrL435rCh5+K/5G8=\ngithub.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4=\ngithub.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms=\ngithub.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k=\ngithub.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA=\ngithub.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs=\ngithub.com/ipfs/go-ipld-git v0.0.3 h1:/YjkjCyo5KYRpW+suby8Xh9Cm/iH9dAgGV6qyZ1dGus=\ngithub.com/ipfs/go-ipld-git v0.0.3/go.mod h1:RuvMXa9qtJpDbqngyICCU/d+cmLFXxLsbIclmD0Lcr0=\ngithub.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=\ngithub.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=\ngithub.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=\ngithub.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA=\ngithub.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I=\ngithub.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=\ngithub.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=\ngithub.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY=\ngithub.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=\ngithub.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=\ngithub.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=\ngithub.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=\ngithub.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=\ngithub.com/ipfs/go-log/v2 v2.1.2-0.20200609205458-f8d20c392cb7/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=\ngithub.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 h1:3bijxqzQ1O9yg7gd7Aqk80oaEvsJ+uXw0zSvi2qR3Jw=\ngithub.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=\ngithub.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA=\ngithub.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto=\ngithub.com/ipfs/go-merkledag v0.1.0/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk=\ngithub.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk=\ngithub.com/ipfs/go-merkledag v0.3.0/go.mod h1:4pymaZLhSLNVuiCITYrpViD6vmfZ/Ws4n/L9tfNv3S4=\ngithub.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M=\ngithub.com/ipfs/go-merkledag v0.3.2 h1:MRqj40QkrWkvPswXs4EfSslhZ4RVPRbxwX11js0t1xY=\ngithub.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M=\ngithub.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=\ngithub.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=\ngithub.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks=\ngithub.com/ipfs/go-mfs v0.1.2 h1:DlelNSmH+yz/Riy0RjPKlooPg0KML4lXGdLw7uZkfAg=\ngithub.com/ipfs/go-mfs v0.1.2/go.mod h1:T1QBiZPEpkPLzDqEJLNnbK55BVKVlNi2a+gVm4diFo0=\ngithub.com/ipfs/go-path v0.0.3/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo=\ngithub.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno=\ngithub.com/ipfs/go-path v0.0.8 h1:R0k6t9x/pa+g8qzl5apQIPurJFozXhopks3iw3MX+jU=\ngithub.com/ipfs/go-path v0.0.8/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8=\ngithub.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ=\ngithub.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U=\ngithub.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U=\ngithub.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc=\ngithub.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY=\ngithub.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4=\ngithub.com/ipfs/go-unixfs v0.0.4/go.mod h1:eIo/p9ADu/MFOuyxzwU+Th8D6xoxU//r590vUpWyfz8=\ngithub.com/ipfs/go-unixfs v0.1.0/go.mod h1:lysk5ELhOso8+Fed9U1QTGey2ocsfaZ18h0NCO2Fj9s=\ngithub.com/ipfs/go-unixfs v0.2.1/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k=\ngithub.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo=\ngithub.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=\ngithub.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E=\ngithub.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=\ngithub.com/ipfs/interface-go-ipfs-core v0.2.3/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=\ngithub.com/ipfs/interface-go-ipfs-core v0.2.6/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=\ngithub.com/ipfs/interface-go-ipfs-core v0.2.7/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=\ngithub.com/ipfs/interface-go-ipfs-core v0.3.0/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=\ngithub.com/ipfs/interface-go-ipfs-core v0.4.0 h1:+mUiamyHIwedqP8ZgbCIwpy40oX7QcXUbo4CZOeJVJg=\ngithub.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o=\ngithub.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg=\ngithub.com/ipfs/iptb-plugins v0.2.1/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs=\ngithub.com/ipfs/iptb-plugins v0.2.2/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs=\ngithub.com/ipfs/iptb-plugins v0.3.0/go.mod h1:5QtOvckeIw4bY86gSH4fgh3p3gCSMn3FmIKr4gaBncA=\ngithub.com/ipld/go-car v0.1.1-0.20200429200904-c222d793c339/go.mod h1:eajxljm6I8o3LitnFeVEmucwZmz7+yLSiKce9yYMefg=\ngithub.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae/go.mod h1:2mvxpu4dKRnuH3mj5u6KW/tmRSCcXvy/KYiJ4nC6h4c=\ngithub.com/ipld/go-car v0.1.1-0.20200923150018-8cdef32e2da4 h1:6phjU3kXvCEWOZpu+Ob0w6DzgPFZmDLgLPxJhD8RxEY=\ngithub.com/ipld/go-car v0.1.1-0.20200923150018-8cdef32e2da4/go.mod h1:xrMEcuSq+D1vEwl+YAXsg/JfA98XGpXDwnkIL4Aimqw=\ngithub.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8=\ngithub.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM=\ngithub.com/ipld/go-ipld-prime v0.5.1-0.20201021195245-109253e8a018 h1:RbRHv8epkmvBYA5cGfz68GUSbOgx5j/7ObLIl4Rsif0=\ngithub.com/ipld/go-ipld-prime v0.5.1-0.20201021195245-109253e8a018/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM=\ngithub.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs=\ngithub.com/ipld/go-ipld-prime-proto v0.0.0-20200922192210-9a2bfd4440a6/go.mod h1:3pHYooM9Ea65jewRwrb2u5uHZCNkNTe9ABsVB+SrkH0=\ngithub.com/ipld/go-ipld-prime-proto v0.1.0 h1:j7gjqrfwbT4+gXpHwEx5iMssma3mnctC7YaCimsFP70=\ngithub.com/ipld/go-ipld-prime-proto v0.1.0/go.mod h1:11zp8f3sHVgIqtb/c9Kr5ZGqpnCLF1IVTNOez9TopzE=\ngithub.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4=\ngithub.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=\ngithub.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=\ngithub.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=\ngithub.com/jbenet/go-is-domain v1.0.3/go.mod h1:xbRLRb0S7FgzDBTJlguhDVwLYM/5yNtvktxj2Ttfy7Q=\ngithub.com/jbenet/go-is-domain v1.0.5 h1:r92uiHbMEJo9Fkey5pMBtZAzjPQWic0ieo7Jw1jEuQQ=\ngithub.com/jbenet/go-is-domain v1.0.5/go.mod h1:xbRLRb0S7FgzDBTJlguhDVwLYM/5yNtvktxj2Ttfy7Q=\ngithub.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU=\ngithub.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=\ngithub.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=\ngithub.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=\ngithub.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=\ngithub.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=\ngithub.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=\ngithub.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=\ngithub.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15/go.mod h1:Fdm/oWRW+CH8PRbLntksCNtmcCBximKPkVQYvmMl80k=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jhump/protoreflect v1.7.0 h1:qJ7piXPrjP3mDrfHf5ATkxfLix8ANs226vpo0aACOn0=\ngithub.com/jhump/protoreflect v1.7.0/go.mod h1:RZkzh7Hi9J7qT/sPlWnJ/UwZqCJvciFxKDA0UCeltSM=\ngithub.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=\ngithub.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=\ngithub.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=\ngithub.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=\ngithub.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=\ngithub.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=\ngithub.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=\ngithub.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\ngithub.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=\ngithub.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=\ngithub.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU=\ngithub.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=\ngithub.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=\ngithub.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=\ngithub.com/keybase/go-kext v0.0.0-20200218013902-e4a86908886a h1:dHYanXneM8GTWrIW32GWFKFF3YFkNu17tTnkFmA7Jxw=\ngithub.com/keybase/go-kext v0.0.0-20200218013902-e4a86908886a/go.mod h1:Vtc6+1lR1vL60Xxv2mpL6qf5rZdagBZ/eOsXHa3cHFE=\ngithub.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM=\ngithub.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc=\ngithub.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s=\ngithub.com/kilic/bls12-381 v0.0.0-20200731194930-64c428e1bff5/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s=\ngithub.com/kilic/bls12-381 v0.0.0-20200820230200-6b2c19996391/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=\ngithub.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=\ngithub.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=\ngithub.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=\ngithub.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=\ngithub.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=\ngithub.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=\ngithub.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=\ngithub.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=\ngithub.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=\ngithub.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=\ngithub.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=\ngithub.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=\ngithub.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=\ngithub.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc=\ngithub.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8=\ngithub.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=\ngithub.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=\ngithub.com/libp2p/go-libp2p v0.10.3 h1:Bc8/VjmC+pICtK6xG8YgVutZvCdK0MsroWCHP+6AdFQ=\ngithub.com/libp2p/go-libp2p v0.10.3/go.mod h1:0ER6iPSaPeQjryNgOnm9bLNpMJCYmuw54xJXsVR17eE=\ngithub.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 h1:BM7aaOF7RpmNn9+9g6uTjGJ0cTzWr5j9i9IKeun2M8U=\ngithub.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=\ngithub.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8=\ngithub.com/libp2p/go-libp2p-autonat v0.3.2 h1:OhDSwVVaq7liTaRIsFFYvsaPp0pn2yi0WazejZ4DUmo=\ngithub.com/libp2p/go-libp2p-autonat v0.3.2/go.mod h1:0OzOi1/cVc7UcxfOddemYD5vzEqi4fwRbnZcJGLi68U=\ngithub.com/libp2p/go-libp2p-autonat-svc v0.1.0/go.mod h1:fqi8Obl/z3R4PFVLm8xFtZ6PBL9MlV/xumymRFkKq5A=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=\ngithub.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ=\ngithub.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk=\ngithub.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=\ngithub.com/libp2p/go-libp2p-circuit v0.1.3/go.mod h1:Xqh2TjSy8DD5iV2cCOMzdynd6h8OTBGoV1AWbWor3qM=\ngithub.com/libp2p/go-libp2p-circuit v0.2.3/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4=\ngithub.com/libp2p/go-libp2p-circuit v0.3.1 h1:69ENDoGnNN45BNDnBd+8SXSetDuw0eJFcGmOvvtOgBw=\ngithub.com/libp2p/go-libp2p-circuit v0.3.1/go.mod h1:8RMIlivu1+RxhebipJwFDA45DasLx+kkrp4IlJj53F4=\ngithub.com/libp2p/go-libp2p-connmgr v0.1.1/go.mod h1:wZxh8veAmU5qdrfJ0ZBLcU8oJe9L82ciVP/fl1VHjXk=\ngithub.com/libp2p/go-libp2p-connmgr v0.2.1/go.mod h1:JReKEFcgzSHKT9lL3rhYcUtXBs9uMIiMKJGM1tl3xJE=\ngithub.com/libp2p/go-libp2p-connmgr v0.2.3/go.mod h1:Gqjg29zI8CwXX21zRxy6gOg8VYu3zVerJRt2KyktzH4=\ngithub.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w=\ngithub.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0=\ngithub.com/libp2p/go-libp2p-core v0.6.1 h1:XS+Goh+QegCDojUZp00CaPMfiEADCrLjNZskWE7pvqs=\ngithub.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=\ngithub.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=\ngithub.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I=\ngithub.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ=\ngithub.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=\ngithub.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ=\ngithub.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=\ngithub.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=\ngithub.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=\ngithub.com/libp2p/go-libp2p-gostream v0.2.0/go.mod h1:nN/Aw00orrADXaXgNCeYjCtQrk6eT20PX/G8F12NW/s=\ngithub.com/libp2p/go-libp2p-gostream v0.2.1 h1:JjA9roGokaR2BgWmaI/3HQu1/+jSbVVDLatQGnVdGjI=\ngithub.com/libp2p/go-libp2p-gostream v0.2.1/go.mod h1:1Mjp3LDmkqICe5tH9yLVNCqFaRTy6OwBvuJV6j1b9Nk=\ngithub.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go=\ngithub.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8=\ngithub.com/libp2p/go-libp2p-http v0.1.5 h1:FfLnzjlEzV4/6UCXCpPXRYZNoGCfogqCFjd7eF0Jbm8=\ngithub.com/libp2p/go-libp2p-http v0.1.5/go.mod h1:2YfPjsQxUlBGFQl2u461unkQ7ukwiSs7NX2eSslOJiU=\ngithub.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=\ngithub.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=\ngithub.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=\ngithub.com/libp2p/go-libp2p-kad-dht v0.2.1/go.mod h1:k7ONOlup7HKzQ68dE6lSnp07cdxdkmnRa+6B4Fh9/w0=\ngithub.com/libp2p/go-libp2p-kad-dht v0.7.10/go.mod h1:COi43/398wedaaNzvnbnWQ8qeG629Nu7Aj0WixHmD3A=\ngithub.com/libp2p/go-libp2p-kad-dht v0.8.1/go.mod h1:u3rbYbp3CSraAHD5s81CJ3hHozKTud/UOXfAgh93Gek=\ngithub.com/libp2p/go-libp2p-kad-dht v0.8.2/go.mod h1:u3rbYbp3CSraAHD5s81CJ3hHozKTud/UOXfAgh93Gek=\ngithub.com/libp2p/go-libp2p-kad-dht v0.8.3/go.mod h1:HnYYy8taJWESkqiESd1ngb9XX/XGGsMA5G0Vj2HoSh4=\ngithub.com/libp2p/go-libp2p-kad-dht v0.9.0/go.mod h1:LEKcCFHxnvypOPaqZ0m6h0fLQ9Y8t1iZMOg7a0aQDD4=\ngithub.com/libp2p/go-libp2p-kad-dht v0.10.0/go.mod h1:LEKcCFHxnvypOPaqZ0m6h0fLQ9Y8t1iZMOg7a0aQDD4=\ngithub.com/libp2p/go-libp2p-kad-dht v0.11.0 h1:ZLhlmDKsFiOkPhTzfEqBrMy/1Tqx+Dk6UgbHM5//IQM=\ngithub.com/libp2p/go-libp2p-kad-dht v0.11.0/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI=\ngithub.com/libp2p/go-libp2p-kbucket v0.2.1/go.mod h1:/Rtu8tqbJ4WQ2KTCOMJhggMukOLNLNPY1EtEWWLxUvc=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.1/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70=\ngithub.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk=\ngithub.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=\ngithub.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=\ngithub.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=\ngithub.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=\ngithub.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=\ngithub.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE=\ngithub.com/libp2p/go-libp2p-mplex v0.3.0 h1:CZyqqKP0BSGQyPLvpRQougbfXaaaJZdGgzhCpJNuNSk=\ngithub.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=\ngithub.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=\ngithub.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=\ngithub.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c=\ngithub.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c=\ngithub.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q=\ngithub.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=\ngithub.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=\ngithub.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk=\ngithub.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE=\ngithub.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo=\ngithub.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es=\ngithub.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY=\ngithub.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=\ngithub.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=\ngithub.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U=\ngithub.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=\ngithub.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=\ngithub.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s=\ngithub.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk=\ngithub.com/libp2p/go-libp2p-pubsub v0.3.2 h1:k3cJm5JW5mjaWZkobS50sJLJWaB2mBi0HW4eRlE8mSo=\ngithub.com/libp2p/go-libp2p-pubsub v0.3.2/go.mod h1:Uss7/Cfz872KggNb+doCVPHeCDmXB7z500m/R8DaAUk=\ngithub.com/libp2p/go-libp2p-pubsub-router v0.3.0/go.mod h1:6kZb1gGV1yGzXTfyNsi4p+hyt1JnA1OMGHeExTOJR3A=\ngithub.com/libp2p/go-libp2p-pubsub-router v0.3.2 h1:BGC4irCUXlwmlCSxnA2DVDNY8JqhfAUUaiq3CZvcddw=\ngithub.com/libp2p/go-libp2p-pubsub-router v0.3.2/go.mod h1:G4MAvYzPxhoR0LEBluS9Ow+Nnr/8iDalUN+RNwVgNkY=\ngithub.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU=\ngithub.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M=\ngithub.com/libp2p/go-libp2p-quic-transport v0.7.1/go.mod h1:TD31to4E5exogR/GWHClXCfkktigjAl5rXSt7HoxNvY=\ngithub.com/libp2p/go-libp2p-quic-transport v0.8.0/go.mod h1:F2FG/6Bzz0U6essUVxDzE0s9CrY4XGLbl7QEmDNvU7A=\ngithub.com/libp2p/go-libp2p-quic-transport v0.9.0 h1:WPuq5nV/chmIZIzvrkC2ulSdAQ0P0BDvgvAhZFOZ59E=\ngithub.com/libp2p/go-libp2p-quic-transport v0.9.0/go.mod h1:xyY+IgxL0qsW7Kiutab0+NlxM0/p9yRtrGTYsuMWf70=\ngithub.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q=\ngithub.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q=\ngithub.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg=\ngithub.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=\ngithub.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0=\ngithub.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4=\ngithub.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys=\ngithub.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE=\ngithub.com/libp2p/go-libp2p-routing-helpers v0.2.1/go.mod h1:rTLUHlGDZbXHANJAWP2xW7ruPNJLj41/GnCBiR+qgjU=\ngithub.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY=\ngithub.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=\ngithub.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg=\ngithub.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=\ngithub.com/libp2p/go-libp2p-swarm v0.2.8 h1:cIUUvytBzNQmGSjnXFlI6UpoBGsaud82mJPIJVfkDlg=\ngithub.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=\ngithub.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=\ngithub.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=\ngithub.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=\ngithub.com/libp2p/go-libp2p-testing v0.2.0/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=\ngithub.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=\ngithub.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=\ngithub.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4=\ngithub.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=\ngithub.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4=\ngithub.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=\ngithub.com/libp2p/go-libp2p-yamux v0.4.1 h1:TJxRVPY9SjH7TNrNC80l1OJMBiWhs1qpKmeB+1Ug3xU=\ngithub.com/libp2p/go-libp2p-yamux v0.4.1/go.mod h1:FA/NjRYRVNjqOzpGuGqcruH7jAU2mYIjtKBicVOL3dc=\ngithub.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=\ngithub.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=\ngithub.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=\ngithub.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=\ngithub.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=\ngithub.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=\ngithub.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=\ngithub.com/libp2p/go-mplex v0.2.0 h1:Ov/D+8oBlbRkjBs1R1Iua8hJ8cUfbdiW8EOdZuxcgaI=\ngithub.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=\ngithub.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=\ngithub.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA=\ngithub.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=\ngithub.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q=\ngithub.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=\ngithub.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=\ngithub.com/libp2p/go-netroute v0.1.3 h1:1ngWRx61us/EpaKkdqkMjKk/ufr/JlIFYQAxV2XX8Ig=\ngithub.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=\ngithub.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=\ngithub.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=\ngithub.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=\ngithub.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=\ngithub.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=\ngithub.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM=\ngithub.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw=\ngithub.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=\ngithub.com/libp2p/go-socket-activation v0.0.2/go.mod h1:KP44C+yZ7gA8sTxavgaD0b8vXVFJwam2CEW0s7+f094=\ngithub.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=\ngithub.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=\ngithub.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=\ngithub.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=\ngithub.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns=\ngithub.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M=\ngithub.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I=\ngithub.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc=\ngithub.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw=\ngithub.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=\ngithub.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=\ngithub.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=\ngithub.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=\ngithub.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=\ngithub.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=\ngithub.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=\ngithub.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=\ngithub.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=\ngithub.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=\ngithub.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE=\ngithub.com/lucas-clemente/quic-go v0.17.3/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE=\ngithub.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=\ngithub.com/lucas-clemente/quic-go v0.18.1 h1:DMR7guC0NtVS8zNZR3IO7NARZvZygkSC56GGtC6cyys=\ngithub.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=\ngithub.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg=\ngithub.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=\ngithub.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=\ngithub.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=\ngithub.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=\ngithub.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=\ngithub.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/mailgun/mailgun-go/v3 v3.6.4 h1:+cvbZRgLSHivbz/w1iWLmxVl6Bqf4geD2D7QMj4+8PE=\ngithub.com/mailgun/mailgun-go/v3 v3.6.4/go.mod h1:ZjVnH8S0dR2BLjvkZc/rxwerdcirzlA12LQDuGAadR0=\ngithub.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8=\ngithub.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=\ngithub.com/manifoldco/promptui v0.7.0 h1:3l11YT8tm9MnwGFQ4kETwkzpAwY2Jt9lCrumCUW4+z4=\ngithub.com/manifoldco/promptui v0.7.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=\ngithub.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=\ngithub.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=\ngithub.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=\ngithub.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=\ngithub.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=\ngithub.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk=\ngithub.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=\ngithub.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=\ngithub.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=\ngithub.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA=\ngithub.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=\ngithub.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=\ngithub.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=\ngithub.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=\ngithub.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=\ngithub.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=\ngithub.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee/go.mod h1:Evt/EIne46u9PtQbeTx2NTcqURpr5K4SvKtGmBuDPN8=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo=\ngithub.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=\ngithub.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=\ngithub.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=\ngithub.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=\ngithub.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=\ngithub.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\ngithub.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw=\ngithub.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=\ngithub.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=\ngithub.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=\ngithub.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=\ngithub.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=\ngithub.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=\ngithub.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=\ngithub.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=\ngithub.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=\ngithub.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=\ngithub.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=\ngithub.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=\ngithub.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=\ngithub.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=\ngithub.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=\ngithub.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=\ngithub.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=\ngithub.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I=\ngithub.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=\ngithub.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=\ngithub.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=\ngithub.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=\ngithub.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=\ngithub.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=\ngithub.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=\ngithub.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=\ngithub.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk=\ngithub.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA=\ngithub.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=\ngithub.com/multiformats/go-multibase v0.0.2/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=\ngithub.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=\ngithub.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=\ngithub.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=\ngithub.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=\ngithub.com/multiformats/go-multihash v0.0.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA+H1IhmjoCDtJc7PXM=\ngithub.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=\ngithub.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I=\ngithub.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=\ngithub.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=\ngithub.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=\ngithub.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=\ngithub.com/multiformats/go-multistream v0.1.2/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=\ngithub.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU=\ngithub.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=\ngithub.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=\ngithub.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo=\ngithub.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=\ngithub.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=\ngithub.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=\ngithub.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=\ngithub.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=\ngithub.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=\ngithub.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=\ngithub.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=\ngithub.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=\ngithub.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28=\ngithub.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=\ngithub.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=\ngithub.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/odeke-em/go-utils v0.0.0-20170224015737-e8ebaed0777a h1:ID4uUGPTiRgDphmzLbX3+teq4mhp2d6Isw2Tb8cMuJU=\ngithub.com/odeke-em/go-utils v0.0.0-20170224015737-e8ebaed0777a/go.mod h1:I31zE0t3yGARXW3nOJIdaNT1BJ2uPHKP0xjmjfRQEVg=\ngithub.com/odeke-em/go-uuid v0.0.0-20151221120446-b211d769a9aa h1:XEhClAZN5U0GUTFRgRdPNgAKO4mP++S+zbqXH+Pr9nU=\ngithub.com/odeke-em/go-uuid v0.0.0-20151221120446-b211d769a9aa/go.mod h1:omlfAqAAOXYL53jxw8wG+G2xH7NqbkJPlDeGP9YpP6g=\ngithub.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=\ngithub.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=\ngithub.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=\ngithub.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=\ngithub.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=\ngithub.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=\ngithub.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=\ngithub.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=\ngithub.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=\ngithub.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=\ngithub.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=\ngithub.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=\ngithub.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=\ngithub.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=\ngithub.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc=\ngithub.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo=\ngithub.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=\ngithub.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=\ngithub.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=\ngithub.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=\ngithub.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=\ngithub.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=\ngithub.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=\ngithub.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=\ngithub.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=\ngithub.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=\ngithub.com/ory/dockertest/v3 v3.6.0/go.mod h1:4ZOpj8qBUmh8fcBSVzkH2bws2s91JdGvHUqan4GHEuQ=\ngithub.com/ory/dockertest/v3 v3.6.2/go.mod h1:EFLcVUOl8qCwp9NyDAcCDtq/QviLtYswW/VbWzUnTNE=\ngithub.com/oschwald/geoip2-golang v1.4.0/go.mod h1:8QwxJvRImBH+Zl6Aa6MaIcs5YdlZSTKtzmPGzQqi9ng=\ngithub.com/oschwald/maxminddb-golang v1.6.0/go.mod h1:DUJFucBg2cvqx42YmDa/+xHvb0elJtOm3o4aFQ/nb/w=\ngithub.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=\ngithub.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=\ngithub.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=\ngithub.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=\ngithub.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=\ngithub.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=\ngithub.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=\ngithub.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=\ngithub.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=\ngithub.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=\ngithub.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=\ngithub.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=\ngithub.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M=\ngithub.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=\ngithub.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=\ngithub.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=\ngithub.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=\ngithub.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=\ngithub.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=\ngithub.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=\ngithub.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc=\ngithub.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=\ngithub.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=\ngithub.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7WL1zHKK7WMqFQqu72rw=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE=\ngithub.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=\ngithub.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=\ngithub.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=\ngithub.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc=\ngithub.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0=\ngithub.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=\ngithub.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=\ngithub.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rhysd/go-github-selfupdate v1.2.2/go.mod h1:khesvSyKcXDUxeySCedFh621iawCks0dS/QnHPcpCws=\ngithub.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=\ngithub.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=\ngithub.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc=\ngithub.com/sercand/kuberesolver v2.1.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ=\ngithub.com/sercand/kuberesolver v2.4.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=\ngithub.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=\ngithub.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=\ngithub.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=\ngithub.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=\ngithub.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=\ngithub.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=\ngithub.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=\ngithub.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=\ngithub.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=\ngithub.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=\ngithub.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=\ngithub.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=\ngithub.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=\ngithub.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=\ngithub.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=\ngithub.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=\ngithub.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=\ngithub.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=\ngithub.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=\ngithub.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=\ngithub.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=\ngithub.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=\ngithub.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=\ngithub.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=\ngithub.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=\ngithub.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=\ngithub.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=\ngithub.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0=\ngithub.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=\ngithub.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=\ngithub.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=\ngithub.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=\ngithub.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=\ngithub.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=\ngithub.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=\ngithub.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=\ngithub.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=\ngithub.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=\ngithub.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=\ngithub.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=\ngithub.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=\ngithub.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=\ngithub.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM=\ngithub.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y=\ngithub.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=\ngithub.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=\ngithub.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=\ngithub.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=\ngithub.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stripe/stripe-go/v72 v72.10.0 h1:4Rsv7Ts4D2qii2r0gW3qZpvPXRV0W8BpagLgvh7kRjY=\ngithub.com/stripe/stripe-go/v72 v72.10.0/go.mod h1:QwqJQtduHubZht9mek5sds9CtQcKFdsykV9ZepRWwo0=\ngithub.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/supranational/blst v0.1.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=\ngithub.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=\ngithub.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=\ngithub.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=\ngithub.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=\ngithub.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=\ngithub.com/textileio/dcrypto v0.0.1 h1:ftXQKd+CAM7a0XFrw+hJqizo+ux8+g5RttKjImZRc7U=\ngithub.com/textileio/dcrypto v0.0.1/go.mod h1:rDlYXuL+HQwkyrxOR230zEUouRnlTwH6O5XWoPbmfcE=\ngithub.com/textileio/go-assets v0.0.0-20200430191519-b341e634e2b7 h1:J7+UXJT/Ku8ylMqqHH4T+CiHtOSd8woUZjynG3fEwDI=\ngithub.com/textileio/go-assets v0.0.0-20200430191519-b341e634e2b7/go.mod h1:j7aKMh8sbbtvttp7V7yCOkHW/pfRtIM/6h+8qEDsLyI=\ngithub.com/textileio/go-datastore v0.4.5-0.20200819232101-baa577bf9422 h1:DNpznzcn7pd1Cn2fdKHfPPw62r8Ii4DGVnQRu9Jbvok=\ngithub.com/textileio/go-datastore v0.4.5-0.20200819232101-baa577bf9422/go.mod h1:/38mp5DMgxCZrb5wpgPlWGXuZ99/ur8wgHDSXU5zCjU=\ngithub.com/textileio/go-datastore-extensions v1.0.0/go.mod h1:Pzj9FDRkb55910dr/FX8M7WywvnS26gBgEDez1ZBuLE=\ngithub.com/textileio/go-ds-badger v0.2.5-0.20200819232634-de89720b5d6a h1:AdjNdwIWrZAUrXfC9IHG8eKhRlJarXZoN9CmGlfTeLA=\ngithub.com/textileio/go-ds-badger v0.2.5-0.20200819232634-de89720b5d6a/go.mod h1:0kLVpG7eeM95s4rS78lQe4eG5DCk+cnU8xas2nPSdZY=\ngithub.com/textileio/go-ds-mongo v0.1.2/go.mod h1:9wmGTUr+MWidGxYQe27RuCogEUZ7vnQxZb4GWj7uWL8=\ngithub.com/textileio/powergate v0.0.1-beta.13.0.20200703203605-db27e80fa8b5/go.mod h1:D3ImIiFCJSFdNdSO1m1SL+P8kQvW2Jrkc6hAZI8h7Bg=\ngithub.com/textileio/powergate v1.2.1 h1:qMqSo/nqN870NRCSrH5AqIQhPm/v9V1HHAiZrFWy5AM=\ngithub.com/textileio/powergate v1.2.1/go.mod h1:MFWG3Tm4wv/Sb5fIL+JyM7mDbvZtfdh8ky09VJFnGNg=\ngithub.com/textileio/textile v1.0.14 h1:ohEoUHATajh6FdVElYtOlgZI3Y0DFPTAJfMrGzpCquc=\ngithub.com/textileio/textile v1.0.14/go.mod h1:W+VB49SnKeZrbXhLIJMe+rFixVYireocJmfrds3EWKo=\ngithub.com/textileio/uiprogress v0.0.4/go.mod h1:ijtyLXHP6vw9MbbT4tmCKZonLPE3LN4mD9C/XRJkrgg=\ngithub.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=\ngithub.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ=\ngithub.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=\ngithub.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=\ngithub.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=\ngithub.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=\ngithub.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=\ngithub.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=\ngithub.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg=\ngithub.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=\ngithub.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=\ngithub.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=\ngithub.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=\ngithub.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=\ngithub.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8=\ngithub.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=\ngithub.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=\ngithub.com/uber/jaeger-client-go v2.23.1+incompatible h1:uArBYHQR0HqLFFAypI7RsWTzPSj/bDpmZZuQjMLSg1A=\ngithub.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=\ngithub.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=\ngithub.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=\ngithub.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=\ngithub.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=\ngithub.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=\ngithub.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=\ngithub.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=\ngithub.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=\ngithub.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=\ngithub.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=\ngithub.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=\ngithub.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=\ngithub.com/urfave/cli v1.22.3/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=\ngithub.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngithub.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngithub.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngithub.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=\ngithub.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=\ngithub.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=\ngithub.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=\ngithub.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=\ngithub.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=\ngithub.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=\ngithub.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=\ngithub.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5/go.mod h1:c98fKi5B9u8OsKGiWHLRKus6ToQ1Tubeow44ECO1uxY=\ngithub.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA=\ngithub.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=\ngithub.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=\ngithub.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CHQnYnQUEPydYCwuy8lmTHfGmdw9TKrhWV0xLx8l0oM=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200206220010-03c9665e2a66/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200723185710-6a3894a6352b/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163 h1:TtcUeY2XZSriVWR1pXyfCBWIf/NGC2iUdNw1lofUjUU=\ngithub.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=\ngithub.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=\ngithub.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=\ngithub.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=\ngithub.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=\ngithub.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=\ngithub.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 h1:ctS9Anw/KozviCCtK6VWMz5kPL9nbQzbQY4yfqlIV4M=\ngithub.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1/go.mod h1:tKH72zYNt/exx6/5IQO6L9LoQ0rEjd5SbbWaDTs9Zso=\ngithub.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4/go.mod h1:K+EVq8d5QcQ2At5VECsA+SNZvWefyBXh8TnIsxo1OvQ=\ngithub.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=\ngithub.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 h1:Y1/FEOpaCpD21WxrmfeIYCFPuVPRCY2XZTWzTNHGw30=\ngithub.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=\ngithub.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=\ngithub.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7ckxrjiFh8mi1AY7ox23PZD0g6QU/TxW3U3unX7I3A=\ngithub.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c h1:GGsyl0dZ2jJgVT+VvWBf/cNijrHRhkrTjkmp5wg7li0=\ngithub.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:xxcJeBb7SIUl/Wzkz1eVKJE/CB34YNrqX2TQI6jY9zs=\ngithub.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=\ngithub.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=\ngithub.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=\ngithub.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=\ngithub.com/xakep666/mongo-migrate v0.2.1 h1:pRK966a44ujuGMEl73MOzv4MajcH8Q6MWo+TBlxjhvs=\ngithub.com/xakep666/mongo-migrate v0.2.1/go.mod h1:pVQysP+es2wX4TaeVd7zLkRZhKMcBqcC/KRyLms6Eyk=\ngithub.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=\ngithub.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=\ngithub.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=\ngithub.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=\ngithub.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=\ngithub.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=\ngithub.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=\ngithub.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=\ngithub.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=\ngithub.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=\ngithub.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=\ngithub.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=\ngithub.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=\ngithub.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I=\ngithub.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245/go.mod h1:C+diUUz7pxhNY6KAoLgrTYARGWnt82zWTylZlxT92vk=\ngithub.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ=\ngithub.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ=\ngithub.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=\ngithub.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=\ngithub.com/zondax/ledger-go v0.12.1/go.mod h1:KatxXrVDzgWwbssUWsF5+cOJHXPvzQ09YSlzGNuhOEo=\ngo.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=\ngo.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ=\ngo.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg=\ngo.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=\ngo.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=\ngo.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4=\ngo.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=\ngo.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=\ngo.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=\ngo.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=\ngo.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=\ngo.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=\ngo.etcd.io/etcd v3.3.22+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=\ngo.mongodb.org/mongo-driver v1.0.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=\ngo.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=\ngo.mongodb.org/mongo-driver v1.4.0/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs=\ngo.mongodb.org/mongo-driver v1.4.1 h1:38NSAyDPagwnFpUA/D5SFgbugUYR3NzYRNa4Qk9UxKs=\ngo.mongodb.org/mongo-driver v1.4.1/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs=\ngo.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=\ngo.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=\ngo.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=\ngo.uber.org/dig v1.9.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=\ngo.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY=\ngo.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=\ngo.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw=\ngo.uber.org/fx v1.12.0/go.mod h1:egT3Kyg1JFYQkvKLZ3EsykxkNrZxgXS+gKoKo7abERY=\ngo.uber.org/fx v1.13.1 h1:CFNTr1oin5OJ0VCZ8EycL3wzF29Jz2g0xe55RFsf2a4=\ngo.uber.org/fx v1.13.1/go.mod h1:bREWhavnedxpJeTq9pQT53BbvwhUv7TcpsOqcH4a+3w=\ngo.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=\ngo.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=\ngo.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngo.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngo.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=\ngo.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=\ngo4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=\ngo4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=\ngo4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=\ngo4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=\ngo4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=\ngolang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=\ngolang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=\ngolang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=\ngolang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201113135734-0a15ea8d9b02 h1:5Ftd3YbC/kANXWCBjvppvUmv1BMakgFcBKA7MpYYp4M=\ngolang.org/x/sys v0.0.0-20201113135734-0a15ea8d9b02/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=\ngolang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=\ngoogle.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=\ngoogle.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=\ngoogle.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=\ngoogle.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=\ngoogle.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200428115010-c45acf45369a/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200624020401-64a14ca9d1ad/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200702021140-07506425bd67 h1:4BC1C1i30F3MZeiIO6y6IIo4DxrtOwITK87bQl3lhFA=\ngoogle.golang.org/genproto v0.0.0-20200702021140-07506425bd67/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=\ngoogle.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=\ngoogle.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=\ngoogle.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=\ngoogle.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc/examples v0.0.0-20200819190100-f640ae6a4f43/go.mod h1:wQWkdCkP0Pl3MzFPvfqTNUnXA2eIVY4eakDiKJvniKc=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=\ngopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=\ngopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=\ngopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=\ngopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=\ngopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=\ngopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=\ngopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=\ngopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc=\ngorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=\ngorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=\ngorm.io/gorm v1.20.5 h1:g3tpSF9kggASzReK+Z3dYei1IJODLqNUbOjSuCczY8g=\ngorm.io/gorm v1.20.5/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=\ngotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=\ngotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=\ngotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=\ngrpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=\nhonnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhowett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=\nlaunchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=\nmodernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=\nmodernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=\nmodernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=\nmodernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\nsigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=\nsourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=\nsourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=\nsourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=\n"
  },
  {
    "path": "grpc/auth/app_token_auth/app_token_auth.go",
    "content": "package app_token_auth\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n)\n\ntype AppTokenAuth struct {\n\tkc keychain.Keychain\n}\n\nfunc New(kc keychain.Keychain) *AppTokenAuth {\n\treturn &AppTokenAuth{\n\t\tkc: kc,\n\t}\n}\n\nfunc (a *AppTokenAuth) Authorize(ctx context.Context, fullMethodName string) (context.Context, error) {\n\tif canSkipAuth(fullMethodName) {\n\t\treturn ctx, nil\n\t}\n\n\ttoken, err := AuthFromMD(ctx, \"AppToken\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttokenInfo, err := a.validateToken(token, fullMethodName)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.Unauthenticated, \"invalid auth token: %v\", err)\n\t}\n\n\tnewCtx := context.WithValue(ctx, \"appToken\", tokenInfo)\n\n\treturn newCtx, nil\n}\n\nfunc (a *AppTokenAuth) validateToken(tok, fullMethodName string) (*permissions.AppToken, error) {\n\tkey, sec, err := permissions.GetKeyAndSecretFromAccessToken(tok)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tappTok, err := a.kc.GetAppToken(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif appTok.Secret != sec {\n\t\treturn nil, errors.New(\"app token secret does not match\")\n\t}\n\n\tauthorized := false\n\n\tif appTok.IsMaster {\n\t\tauthorized = true\n\t}\n\n\t// Check if method is authorized\n\tfor _, p := range appTok.Permissions {\n\t\tif \"/space.SpaceApi/\"+p == fullMethodName {\n\t\t\tauthorized = true\n\t\t}\n\t}\n\n\tif authorized == false {\n\t\treturn nil, errors.New(\"app token does not grant access to \" + fullMethodName)\n\t}\n\n\treturn appTok, nil\n}\n\nvar publicMethods = []string{\n\t\"InitializeMasterAppToken\",\n}\n\nfunc canSkipAuth(fullMethodName string) bool {\n\tfor _, pm := range publicMethods {\n\t\tif \"/space.SpaceApi/\"+pm == fullMethodName {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "grpc/auth/app_token_auth/auth_from_md.go",
    "content": "package app_token_auth\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n)\n\nvar (\n\theaderAuthorize = \"authorization\"\n)\n\n// AuthFromMD is a helper function for extracting the :authorization header from the gRPC metadata of the request.\n//\n// It expects the `:authorization` header to be of a certain scheme (e.g. `basic`, `bearer`), in a\n// case-insensitive format (see rfc2617, sec 1.2). If no such authorization is found, or the token\n// is of wrong scheme, an error with gRPC status `Unauthenticated` is returned.\nfunc AuthFromMD(ctx context.Context, expectedScheme string) (string, error) {\n\tval := metautils.ExtractIncoming(ctx).Get(headerAuthorize)\n\tif val == \"\" {\n\t\treturn \"\", status.Errorf(codes.Unauthenticated, \"Request unauthenticated with \"+expectedScheme)\n\t}\n\tsplits := strings.SplitN(val, \" \", 2)\n\tif len(splits) < 2 {\n\t\treturn \"\", status.Errorf(codes.Unauthenticated, \"Bad authorization string\")\n\t}\n\tif !strings.EqualFold(splits[0], expectedScheme) {\n\t\treturn \"\", status.Errorf(codes.Unauthenticated, \"Request unauthenticated with \"+expectedScheme)\n\t}\n\treturn splits[1], nil\n}\n"
  },
  {
    "path": "grpc/auth/middleware/grpc_auth.go",
    "content": "package grpc_auth\n\nimport (\n\t\"context\"\n\n\tgrpc_middleware \"github.com/grpc-ecosystem/go-grpc-middleware\"\n\t\"google.golang.org/grpc\"\n)\n\n// AuthFunc is the pluggable function that performs authentication.\n//\n// The passed in `Context` will contain the gRPC metadata.MD object (for header-based authentication) and\n// the peer.Peer information that can contain transport-based credentials (e.g. `credentials.AuthInfo`).\n//\n// The returned context will be propagated to handlers, allowing user changes to `Context`. However,\n// please make sure that the `Context` returned is a child `Context` of the one passed in.\n//\n// If error is returned, its `grpc.Code()` will be returned to the user as well as the verbatim message.\n// Please make sure you use `codes.Unauthenticated` (lacking auth) and `codes.PermissionDenied`\n// (authed, but lacking perms) appropriately.\ntype AuthFunc func(ctx context.Context, fullMethodName string) (context.Context, error)\n\n// UnaryServerInterceptor returns a new unary server interceptors that performs per-request auth.\nfunc UnaryServerInterceptor(authFunc AuthFunc) grpc.UnaryServerInterceptor {\n\treturn func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {\n\t\tvar newCtx context.Context\n\t\tvar err error\n\t\tnewCtx, err = authFunc(ctx, info.FullMethod)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn handler(newCtx, req)\n\t}\n}\n\n// StreamServerInterceptor returns a new unary server interceptors that performs per-request auth.\nfunc StreamServerInterceptor(authFunc AuthFunc) grpc.StreamServerInterceptor {\n\treturn func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {\n\t\tvar newCtx context.Context\n\t\tvar err error\n\t\tnewCtx, err = authFunc(stream.Context(), info.FullMethod)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\twrapped := grpc_middleware.WrapServerStream(stream)\n\t\twrapped.WrappedContext = newCtx\n\t\treturn handler(srv, wrapped)\n\t}\n}\n"
  },
  {
    "path": "grpc/grpc.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/rs/cors\"\n\n\t\"github.com/improbable-eng/grpc-web/go/grpcweb\"\n\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\t\"github.com/FleekHQ/space-daemon/core/space/fuse\"\n\t\"github.com/grpc-ecosystem/grpc-gateway/runtime\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/auth/app_token_auth\"\n\tgrpc_auth \"github.com/FleekHQ/space-daemon/grpc/auth/middleware\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"google.golang.org/grpc\"\n)\n\nconst (\n\tDefaultGrpcPort = 9999\n)\n\nvar defaultServerOptions = serverOptions{\n\tport: DefaultGrpcPort,\n}\n\ntype serverOptions struct {\n\tport          int\n\tproxyPort     int // port for grpcweb proxy\n\trestProxyPort int // port for rest api proxy\n}\n\ntype grpcServer struct {\n\topts       *serverOptions\n\ts          *grpc.Server\n\trpcProxy   *http.Server\n\trestServer *http.Server\n\tsv         space.Service\n\tfc         *fuse.Controller\n\tkc         keychain.Keychain\n\t// TODO: see if we need to clean this up by gc or handle an array\n\tfileEventStream         pb.SpaceApi_SubscribeServer\n\ttxlEventStream          pb.SpaceApi_TxlSubscribeServer\n\tnotificationEventStream pb.SpaceApi_NotificationSubscribeServer\n\tisStarted               bool\n\treadyCh                 chan bool\n}\n\n// Idea taken from here https://medium.com/soon-london/variadic-configuration-functions-in-go-8cef1c97ce99\n\ntype ServerOption func(o *serverOptions)\n\n// gRPC server uses Service from core to handle requests\nfunc New(sv space.Service, fc *fuse.Controller, kc keychain.Keychain, opts ...ServerOption) *grpcServer {\n\to := defaultServerOptions\n\tfor _, opt := range opts {\n\t\topt(&o)\n\t}\n\tsrv := &grpcServer{\n\t\topts:    &o,\n\t\tsv:      sv,\n\t\tfc:      fc,\n\t\tkc:      kc,\n\t\treadyCh: make(chan bool, 1),\n\t}\n\n\treturn srv\n}\n\n// Start grpc and api server with provided options\nfunc (srv *grpcServer) Start(ctx context.Context) error {\n\tlis, err := net.Listen(\"tcp\", fmt.Sprintf(\":%d\", srv.opts.port))\n\tif err != nil {\n\t\tlog.Error(fmt.Sprintf(\"failed to listen on port : %v\", srv.opts.port), err)\n\t\treturn err\n\t}\n\n\tlog.Info(fmt.Sprintf(\"listening on address %s\", lis.Addr().String()))\n\n\tappTokenAuth := app_token_auth.New(srv.kc)\n\n\tsrv.s = grpc.NewServer(\n\t\tgrpc.StreamInterceptor(grpc_auth.StreamServerInterceptor(appTokenAuth.Authorize)),\n\t\tgrpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(appTokenAuth.Authorize)),\n\t)\n\tpb.RegisterSpaceApiServer(srv.s, srv)\n\n\tif err = srv.startRestProxy(ctx, lis); err != nil {\n\t\treturn err\n\t}\n\tsrv.startGrpcWebProxy()\n\n\tlog.Info(fmt.Sprintf(\"gRPC server started on Port %v\", srv.opts.port))\n\tsrv.isStarted = true\n\tsrv.readyCh <- true\n\t// this is a blocking function\n\treturn srv.s.Serve(lis)\n}\n\nfunc (srv *grpcServer) startRestProxy(ctx context.Context, lis net.Listener) error {\n\tmux := runtime.NewServeMux()\n\topts := []grpc.DialOption{grpc.WithInsecure()}\n\tif err := pb.RegisterSpaceApiHandlerFromEndpoint(ctx, mux, lis.Addr().String(), opts); err != nil {\n\t\tlog.Error(\"Failed to start REST server\", err)\n\t\treturn err\n\t}\n\n\tsrv.restServer = &http.Server{\n\t\tAddr:    fmt.Sprintf(\":%d\", srv.opts.restProxyPort),\n\t\tHandler: mux,\n\t}\n\n\tsrv.restServer.Handler = cors.AllowAll().Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tlog.Debug(\"Incoming REST Proxy Request\", \"path:\"+r.URL.Path, \"method:\"+r.Method)\n\t\tmux.ServeHTTP(w, r)\n\t}))\n\n\tlog.Info(\"REST server is starting\", fmt.Sprintf(\"port:%v\", srv.opts.restProxyPort))\n\tgo func() {\n\t\tif err := srv.restServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n\t\t\tlog.Error(fmt.Sprintf(\"REST server failed to start on port %d\", srv.opts.restProxyPort), err)\n\t\t}\n\t}()\n\n\treturn nil\n}\n\nfunc (srv *grpcServer) startGrpcWebProxy() {\n\twebrpcProxy := grpcweb.WrapServer(\n\t\tsrv.s,\n\t\tgrpcweb.WithOriginFunc(func(origin string) bool {\n\t\t\treturn true\n\t\t}),\n\t\tgrpcweb.WithWebsockets(true),\n\t\tgrpcweb.WithWebsocketOriginFunc(func(req *http.Request) bool {\n\t\t\treturn true\n\t\t}),\n\t)\n\n\tsrv.rpcProxy = &http.Server{\n\t\tAddr: fmt.Sprintf(\":%d\", srv.opts.proxyPort),\n\t}\n\tsrv.rpcProxy.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif webrpcProxy.IsGrpcWebRequest(r) ||\n\t\t\twebrpcProxy.IsAcceptableGrpcCorsRequest(r) ||\n\t\t\twebrpcProxy.IsGrpcWebSocketRequest(r) {\n\t\t\twebrpcProxy.ServeHTTP(w, r)\n\t\t}\n\t})\n\n\tgo func() {\n\t\tif err := srv.rpcProxy.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n\t\t\tlog.Error(\"Space grpcweb proxy error\", err)\n\t\t}\n\t}()\n\tlog.Info(fmt.Sprintf(\"gRPC-web proxy server started on Port %d\", srv.opts.proxyPort))\n}\n\n// Helper function for setting port\nfunc WithPort(port int) ServerOption {\n\treturn func(o *serverOptions) {\n\t\tif port != 0 {\n\t\t\to.port = port\n\t\t}\n\t}\n}\n\nfunc WithProxyPort(port int) ServerOption {\n\treturn func(o *serverOptions) {\n\t\tif port != 0 {\n\t\t\to.proxyPort = port\n\t\t}\n\t}\n}\n\n// WithRestProxyPort configures the REST Proxy port\nfunc WithRestProxyPort(port int) ServerOption {\n\treturn func(o *serverOptions) {\n\t\tif port != 0 {\n\t\t\to.restProxyPort = port\n\t\t}\n\t}\n}\n\nfunc (srv *grpcServer) Shutdown() error {\n\tif !srv.isStarted {\n\t\treturn nil\n\n\t}\n\tclose(srv.readyCh)\n\n\tdefer func() {\n\t\tsrv.rpcProxy = nil\n\t\tsrv.restServer = nil\n\t\tsrv.s = nil\n\t\tsrv.isStarted = false\n\t}()\n\n\tsrv.s.GracefulStop()\n\n\tshutdownCtx, _ := context.WithTimeout(context.Background(), 10*time.Second)\n\tif err := srv.rpcProxy.Shutdown(shutdownCtx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := srv.restServer.Shutdown(shutdownCtx); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (srv *grpcServer) WaitForReady() chan bool {\n\treturn srv.readyCh\n}\n"
  },
  {
    "path": "grpc/handlers.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/golang/protobuf/ptypes/empty\"\n)\n\nvar errNotImplemented = errors.New(\"Not implemented\")\n\nfunc (srv *grpcServer) sendFileEvent(event *pb.FileEventResponse) {\n\tif srv.fileEventStream != nil {\n\t\tlog.Info(\"sending events to client\", event.String())\n\t\tsrv.fileEventStream.Send(event)\n\t}\n}\n\nfunc (srv *grpcServer) SendFileEvent(event events.FileEvent) {\n\tdirEntries := mapFileInfoToDirectoryEntry([]domain.FileInfo{event.Info})\n\tentry := dirEntries[0]\n\n\tpe := &pb.FileEventResponse{\n\t\tType:   mapFileEventToPb(event.Type),\n\t\tEntry:  entry,\n\t\tBucket: event.Bucket,\n\t\tDbId:   event.DbID,\n\t}\n\n\tsrv.sendFileEvent(pe)\n}\n\nfunc mapFileEventToPb(eventType events.FileEventType) pb.EventType {\n\tswitch eventType {\n\tcase events.FileAdded:\n\t\treturn pb.EventType_ENTRY_ADDED\n\tcase events.FileDeleted:\n\t\treturn pb.EventType_ENTRY_DELETED\n\tcase events.FileUpdated:\n\t\treturn pb.EventType_ENTRY_UPDATED\n\tcase events.FileBackupInProgress:\n\t\treturn pb.EventType_ENTRY_BACKUP_IN_PROGRESS\n\tcase events.FileBackupReady:\n\t\treturn pb.EventType_ENTRY_BACKUP_READY\n\tcase events.FileRestoring:\n\t\treturn pb.EventType_ENTRY_RESTORE_IN_PROGRESS\n\tcase events.FileRestored:\n\t\treturn pb.EventType_ENTRY_RESTORE_READY\n\tcase events.FolderAdded:\n\t\treturn pb.EventType_FOLDER_ADDED\n\tcase events.FolderDeleted:\n\t\treturn pb.EventType_FOLDER_DELETED\n\tcase events.FolderUpdated:\n\t\treturn pb.EventType_FOLDER_UPDATED\n\tdefault:\n\t\treturn pb.EventType_ENTRY_ADDED\n\t}\n}\n\nfunc (srv *grpcServer) sendTextileEvent(event *pb.TextileEventResponse) {\n\tif srv.txlEventStream != nil {\n\t\tlog.Info(\"sending events to client\")\n\t\tsrv.txlEventStream.Send(event)\n\t}\n}\n\nfunc (srv *grpcServer) SendTextileEvent(event events.TextileEvent) {\n\tpe := &pb.TextileEventResponse{}\n\n\tsrv.sendTextileEvent(pe)\n}\n\nfunc (srv *grpcServer) ListDirectories(ctx context.Context, request *pb.ListDirectoriesRequest) (*pb.ListDirectoriesResponse, error) {\n\tbucketName := request.Bucket\n\tlistMembers := !request.OmitMembers\n\n\tentries, err := srv.sv.ListDirs(ctx, \"\", bucketName, listMembers)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdirEntries := mapFileInfoToDirectoryEntry(entries)\n\n\tres := &pb.ListDirectoriesResponse{\n\t\tEntries: dirEntries,\n\t}\n\n\treturn res, nil\n}\n\nfunc (srv *grpcServer) ListDirectory(\n\tctx context.Context,\n\trequest *pb.ListDirectoryRequest,\n) (*pb.ListDirectoryResponse, error) {\n\tlistMembers := !request.OmitMembers\n\n\tentries, err := srv.sv.ListDir(ctx, request.GetPath(), request.GetBucket(), listMembers)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdirEntries := mapFileInfoToDirectoryEntry(entries)\n\n\tres := &pb.ListDirectoryResponse{\n\t\tEntries: dirEntries,\n\t}\n\n\treturn res, nil\n}\n\nfunc mapFileInfoToDirectoryEntry(entries []domain.FileInfo) []*pb.ListDirectoryEntry {\n\tdirEntries := make([]*pb.ListDirectoryEntry, 0)\n\n\tfor _, e := range entries {\n\t\tmembers := make([]*pb.FileMember, 0)\n\n\t\tfor _, m := range e.Members {\n\t\t\tmembers = append(members, &pb.FileMember{\n\t\t\t\tAddress:   m.Address,\n\t\t\t\tPublicKey: m.PublicKey,\n\t\t\t})\n\t\t}\n\n\t\tvar backupCount = 0\n\t\tif e.BackedUp {\n\t\t\tbackupCount = 1\n\t\t}\n\n\t\tdirEntry := &pb.ListDirectoryEntry{\n\t\t\tPath:                e.Path,\n\t\t\tIsDir:               e.IsDir,\n\t\t\tName:                e.Name,\n\t\t\tSizeInBytes:         e.SizeInBytes,\n\t\t\tCreated:             e.Created,\n\t\t\tUpdated:             e.Updated,\n\t\t\tFileExtension:       e.FileExtension,\n\t\t\tIpfsHash:            e.IpfsHash,\n\t\t\tMembers:             members,\n\t\t\tBackupCount:         int64(backupCount),\n\t\t\tIsLocallyAvailable:  e.LocallyAvailable,\n\t\t\tIsBackupInProgress:  e.BackupInProgress,\n\t\t\tIsRestoreInProgress: e.RestoreInProgress,\n\t\t}\n\t\tdirEntries = append(dirEntries, dirEntry)\n\t}\n\treturn dirEntries\n}\n\nfunc (srv *grpcServer) Subscribe(empty *empty.Empty, stream pb.SpaceApi_SubscribeServer) error {\n\tsrv.registerStream(stream)\n\t// waits until request is done\n\tselect {\n\tcase <-stream.Context().Done():\n\t\tbreak\n\t}\n\t// clean up stream\n\tsrv.registerStream(nil)\n\tlog.Info(\"closing stream\")\n\treturn nil\n}\n\nfunc (srv *grpcServer) registerStream(stream pb.SpaceApi_SubscribeServer) {\n\tsrv.fileEventStream = stream\n}\n\nfunc (srv *grpcServer) TxlSubscribe(empty *empty.Empty, stream pb.SpaceApi_TxlSubscribeServer) error {\n\tsrv.registerTxlStream(stream)\n\t// waits until request is done\n\tselect {\n\tcase <-stream.Context().Done():\n\t\tbreak\n\t}\n\t// clean up stream\n\tsrv.registerTxlStream(nil)\n\tlog.Info(\"closing stream\")\n\treturn nil\n}\n\nfunc (srv *grpcServer) registerTxlStream(stream pb.SpaceApi_TxlSubscribeServer) {\n\tsrv.txlEventStream = stream\n}\n\nfunc (srv *grpcServer) OpenFile(ctx context.Context, request *pb.OpenFileRequest) (*pb.OpenFileResponse, error) {\n\tfi, err := srv.sv.OpenFile(ctx, request.Path, request.Bucket, request.DbId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.OpenFileResponse{Location: fi.Location}, nil\n}\n\nfunc (srv *grpcServer) AddItems(request *pb.AddItemsRequest, stream pb.SpaceApi_AddItemsServer) error {\n\tctx := stream.Context()\n\n\tresults, totals, err := srv.sv.AddItems(ctx, request.SourcePaths, request.TargetPath, request.Bucket)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnotifications := make(chan domain.AddItemResult)\n\n\tdone := make(chan struct{})\n\n\t// push notification stream from out\n\tgo func() {\n\t\tvar completedBytes int64\n\t\tvar completedFiles int64\n\t\tfor res := range notifications {\n\t\t\tcompletedFiles++\n\t\t\tvar r *pb.AddItemsResponse\n\t\t\tif res.Error != nil {\n\t\t\t\tr = &pb.AddItemsResponse{\n\t\t\t\t\tResult: &pb.AddItemResult{\n\t\t\t\t\t\tSourcePath: res.SourcePath,\n\t\t\t\t\t\tError:      res.Error.Error(),\n\t\t\t\t\t},\n\t\t\t\t\tTotalFiles:     totals.TotalFiles,\n\t\t\t\t\tTotalBytes:     totals.TotalBytes,\n\t\t\t\t\tCompletedFiles: completedFiles,\n\t\t\t\t\tCompletedBytes: completedBytes,\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcompletedBytes += res.Bytes\n\t\t\t\tr = &pb.AddItemsResponse{\n\t\t\t\t\tResult: &pb.AddItemResult{\n\t\t\t\t\t\tSourcePath: res.SourcePath,\n\t\t\t\t\t\tBucketPath: res.BucketPath,\n\t\t\t\t\t},\n\t\t\t\t\tTotalFiles:     totals.TotalFiles,\n\t\t\t\t\tTotalBytes:     totals.TotalBytes,\n\t\t\t\t\tCompletedFiles: completedFiles,\n\t\t\t\t\tCompletedBytes: completedBytes,\n\t\t\t\t}\n\t\t\t}\n\t\t\tstream.Send(r)\n\t\t}\n\t\tdone <- struct{}{}\n\t}()\n\n\t// receive results from service\n\tfor in := range results {\n\t\tselect {\n\t\tcase notifications <- in:\n\t\tcase <-stream.Context().Done():\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// close out channel and stream\n\tclose(notifications)\n\t// wait for all notifications to finish\n\t<-done\n\tlog.Printf(\"closing stream for addFiles\")\n\n\treturn nil\n}\n\nfunc (srv *grpcServer) CreateFolder(ctx context.Context, request *pb.CreateFolderRequest) (*pb.CreateFolderResponse, error) {\n\terr := srv.sv.CreateFolder(ctx, request.Path, request.Bucket)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.CreateFolderResponse{}, nil\n}\n\nfunc (srv *grpcServer) RemoveDirOrFile(ctx context.Context, request *pb.RemoveDirOrFileRequest) (*pb.RemoveDirOrFileResponse, error) {\n\terr := srv.sv.RemoveDirOrFile(ctx, request.Path, request.Bucket)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.RemoveDirOrFileResponse{}, nil\n}\n"
  },
  {
    "path": "grpc/handlers_account.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/pkg/errors\"\n)\n\nfunc (srv *grpcServer) DeleteAccount(ctx context.Context, request *pb.DeleteAccountRequest) (*pb.DeleteAccountResponse, error) {\n\n\tif err := srv.fc.Unmount(); err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to unmount fuse drive\")\n\t}\n\n\tif err := srv.sv.TruncateData(ctx); err != nil {\n\t\treturn nil, errors.Wrap(err, \"error during clean up\")\n\t}\n\n\tif err := srv.sv.DeleteKeypair(ctx); err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to remove keypair\")\n\t}\n\n\treturn &pb.DeleteAccountResponse{}, nil\n}\n"
  },
  {
    "path": "grpc/handlers_app_token.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) InitializeMasterAppToken(ctx context.Context, request *pb.InitializeMasterAppTokenRequest) (*pb.InitializeMasterAppTokenResponse, error) {\n\tappToken, err := srv.sv.InitializeMasterAppToken(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.InitializeMasterAppTokenResponse{\n\t\tAppToken: appToken.GetAccessToken(),\n\t}, nil\n}\n\nfunc (srv *grpcServer) GenerateAppToken(ctx context.Context, request *pb.GenerateAppTokenRequest) (*pb.GenerateAppTokenResponse, error) {\n\t// TODO: Implement this when we prioritize adding a third-party app marketplace\n\treturn nil, errNotImplemented\n}\n"
  },
  {
    "path": "grpc/handlers_backup.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) ToggleBucketBackup(ctx context.Context, request *pb.ToggleBucketBackupRequest) (*pb.ToggleBucketBackupResponse, error) {\n\tbucketSlug := request.Bucket\n\tbucketBackup := request.Backup\n\n\terr := srv.sv.ToggleBucketBackup(ctx, bucketSlug, bucketBackup)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.ToggleBucketBackupResponse{}, nil\n}\n\nfunc (srv *grpcServer) BucketBackupRestore(ctx context.Context, request *pb.BucketBackupRestoreRequest) (*pb.BucketBackupRestoreResponse, error) {\n\tbucketSlug := request.Bucket\n\n\terr := srv.sv.BucketBackupRestore(ctx, bucketSlug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.BucketBackupRestoreResponse{}, nil\n}\n\nfunc (srv *grpcServer) GetUsageInfo(ctx context.Context, request *pb.GetUsageInfoRequest) (*pb.GetUsageInfoResponse, error) {\n\treturn nil, errNotImplemented\n}\n"
  },
  {
    "path": "grpc/handlers_central_services.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) GetAPISessionTokens(ctx context.Context, request *pb.GetAPISessionTokensRequest) (*pb.GetAPISessionTokensResponse, error) {\n\ttokens, err := srv.sv.GetAPISessionTokens(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.GetAPISessionTokensResponse{\n\t\tHubToken:      tokens.HubToken,\n\t\tServicesToken: tokens.ServicesToken,\n\t}, nil\n}\n"
  },
  {
    "path": "grpc/handlers_fuse.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/opentracing/opentracing-go\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/fuse\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\t\"github.com/pkg/errors\"\n)\n\n// ToggleFuseDrive switching on or off a mounted fuse drive\nfunc (srv *grpcServer) ToggleFuseDrive(ctx context.Context, request *pb.ToggleFuseRequest) (*pb.FuseDriveResponse, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"ToggleFuseDrive\")\n\tdefer span.Finish()\n\n\tif request.MountDrive {\n\t\tif err := srv.fc.Mount(); err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"failed to mount fuse drive\")\n\t\t}\n\t} else {\n\t\tif err := srv.fc.Unmount(); err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"failed to unmount fuse drive\")\n\t\t}\n\t}\n\n\treturn srv.GetFuseDriveStatus(ctx, nil)\n}\n\n// GetFuseDriveStatus returns the current mounted state\nfunc (srv *grpcServer) GetFuseDriveStatus(ctx context.Context, empty *empty.Empty) (*pb.FuseDriveResponse, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"GetFuseDriveStatus\")\n\tdefer span.Finish()\n\n\tstate, err := srv.fc.GetFuseState(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.FuseDriveResponse{\n\t\tState:     fuseStateToRpcState(state),\n\t\tMountPath: srv.fc.GetMountPath(),\n\t}, nil\n}\n\nvar fuseStateToRpcStateMap = map[fuse.State]pb.FuseState{\n\tfuse.UNSUPPORTED:   pb.FuseState_UNSUPPORTED,\n\tfuse.NOT_INSTALLED: pb.FuseState_NOT_INSTALLED,\n\tfuse.UNMOUNTED:     pb.FuseState_UNMOUNTED,\n\tfuse.MOUNTED:       pb.FuseState_MOUNTED,\n}\n\nfunc fuseStateToRpcState(state fuse.State) pb.FuseState {\n\treturn fuseStateToRpcStateMap[state]\n}\n"
  },
  {
    "path": "grpc/handlers_key_pair.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) GenerateKeyPair(ctx context.Context, request *pb.GenerateKeyPairRequest) (*pb.GenerateKeyPairResponse, error) {\n\tmnemonic, err := srv.sv.GenerateKeyPair(ctx, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.GenerateKeyPairResponse{\n\t\tMnemonic: mnemonic,\n\t}, nil\n\n}\n\nfunc (srv *grpcServer) GenerateKeyPairWithForce(ctx context.Context, request *pb.GenerateKeyPairRequest) (*pb.GenerateKeyPairResponse, error) {\n\tmnemonic, err := srv.sv.GenerateKeyPair(ctx, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.GenerateKeyPairResponse{\n\t\tMnemonic: mnemonic,\n\t}, nil\n}\n\nfunc (srv *grpcServer) GetPublicKey(ctx context.Context, request *pb.GetPublicKeyRequest) (*pb.GetPublicKeyResponse, error) {\n\tpub, err := srv.sv.GetPublicKey(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.GetPublicKeyResponse{\n\t\tPublicKey: pub,\n\t}, nil\n}\n\nfunc (srv *grpcServer) DeleteKeyPair(ctx context.Context, request *pb.DeleteKeyPairRequest) (*pb.DeleteKeyPairResponse, error) {\n\terr := srv.sv.DeleteKeypair(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.DeleteKeyPairResponse{}, nil\n}\n\nfunc (srv *grpcServer) RestoreKeyPairViaMnemonic(ctx context.Context, request *pb.RestoreKeyPairViaMnemonicRequest) (*pb.RestoreKeyPairViaMnemonicResponse, error) {\n\tif err := srv.sv.RestoreKeyPairFromMnemonic(ctx, request.Mnemonic); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.RestoreKeyPairViaMnemonicResponse{}, nil\n}\n\nfunc (srv *grpcServer) GetStoredMnemonic(ctx context.Context, request *pb.GetStoredMnemonicRequest) (*pb.GetStoredMnemonicResponse, error) {\n\tmnemonic, err := srv.sv.GetMnemonic(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.GetStoredMnemonicResponse{\n\t\tMnemonic: mnemonic,\n\t}, nil\n}\n"
  },
  {
    "path": "grpc/handlers_notif.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/FleekHQ/space-daemon/log\"\n\t\"github.com/golang/protobuf/ptypes/empty\"\n)\n\nfunc mapToPbNotification(n domain.Notification) *pb.Notification {\n\t// maybe there is a cooler way to do this (e.g., with reflection)\n\tswitch n.NotificationType {\n\tcase domain.INVITATION:\n\t\tinv := n.InvitationValue\n\t\tpbpths := make([]*pb.FullPath, 0)\n\n\t\tfor _, pth := range n.InvitationValue.ItemPaths {\n\t\t\tpbpth := &pb.FullPath{\n\t\t\t\tBucket: pth.Bucket,\n\t\t\t\tDbId:   pth.DbId,\n\t\t\t\tPath:   pth.Path,\n\t\t\t}\n\t\t\tpbpths = append(pbpths, pbpth)\n\t\t}\n\n\t\tpbinv := &pb.Invitation{\n\t\t\tInvitationID:     n.ID,\n\t\t\tInviterPublicKey: inv.InviterPublicKey,\n\t\t\tStatus:           pb.InvitationStatus(inv.Status),\n\t\t\tItemPaths:        pbpths,\n\t\t}\n\t\tro := &pb.Notification_InvitationValue{pbinv}\n\t\tparsedNotif := &pb.Notification{\n\t\t\tID:            n.ID,\n\t\t\tBody:          n.Body,\n\t\t\tReadAt:        n.ReadAt,\n\t\t\tCreatedAt:     n.CreatedAt,\n\t\t\tRelatedObject: ro,\n\t\t\tType:          pb.NotificationType(n.NotificationType),\n\t\t}\n\t\treturn parsedNotif\n\tcase domain.USAGEALERT:\n\t\tua := n.UsageAlertValue\n\t\tpbua := &pb.UsageAlert{\n\t\t\tUsed:    ua.Used,\n\t\t\tLimit:   ua.Limit,\n\t\t\tMessage: ua.Message,\n\t\t}\n\t\tro := &pb.Notification_UsageAlert{pbua}\n\t\tparsedNotif := &pb.Notification{\n\t\t\tID:            n.ID,\n\t\t\tBody:          n.Body,\n\t\t\tReadAt:        n.ReadAt,\n\t\t\tCreatedAt:     n.CreatedAt,\n\t\t\tRelatedObject: ro,\n\t\t\tType:          pb.NotificationType(n.NotificationType),\n\t\t}\n\t\treturn parsedNotif\n\tcase domain.INVITATION_REPLY:\n\t\tir := n.InvitationAcceptValue\n\t\tpbir := &pb.InvitationAccept{\n\t\t\tInvitationID: ir.InvitationID,\n\t\t}\n\t\tro := &pb.Notification_InvitationAccept{pbir}\n\t\tparsedNotif := &pb.Notification{\n\t\t\tID:            n.ID,\n\t\t\tBody:          n.Body,\n\t\t\tReadAt:        n.ReadAt,\n\t\t\tCreatedAt:     n.CreatedAt,\n\t\t\tRelatedObject: ro,\n\t\t\tType:          pb.NotificationType(n.NotificationType),\n\t\t}\n\t\treturn parsedNotif\n\tcase domain.REVOKED_INVITATION:\n\t\tpbpths := make([]*pb.FullPath, 0)\n\n\t\tfor _, pth := range n.RevokedInvitationValue.ItemPaths {\n\t\t\tpbpth := &pb.FullPath{\n\t\t\t\tBucket: pth.Bucket,\n\t\t\t\tDbId:   pth.DbId,\n\t\t\t\tPath:   pth.Path,\n\t\t\t}\n\t\t\tpbpths = append(pbpths, pbpth)\n\t\t}\n\n\t\trevokedInvite := &pb.RevokedInvitation{\n\t\t\tInviterPublicKey: n.RevokedInvitationValue.InviterPublicKey,\n\t\t\tItemPaths:        pbpths,\n\t\t}\n\t\tro := &pb.Notification_RevokedInvitation{RevokedInvitation: revokedInvite}\n\t\tparsedNotif := &pb.Notification{\n\t\t\tID:            n.ID,\n\t\t\tBody:          n.Body,\n\t\t\tReadAt:        n.ReadAt,\n\t\t\tCreatedAt:     n.CreatedAt,\n\t\t\tRelatedObject: ro,\n\t\t\tType:          pb.NotificationType(n.NotificationType),\n\t\t}\n\t\treturn parsedNotif\n\tdefault:\n\t\tparsedNotif := &pb.Notification{\n\t\t\tID:        n.ID,\n\t\t\tBody:      n.Body,\n\t\t\tReadAt:    n.ReadAt,\n\t\t\tCreatedAt: n.CreatedAt,\n\t\t\tType:      pb.NotificationType(n.NotificationType),\n\t\t}\n\t\treturn parsedNotif\n\t}\n}\n\nfunc (srv *grpcServer) SetNotificationsLastSeenAt(ctx context.Context, request *pb.SetNotificationsLastSeenAtRequest) (*pb.SetNotificationsLastSeenAtResponse, error) {\n\terr := srv.sv.SetNotificationsLastSeenAt(request.Timestamp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &pb.SetNotificationsLastSeenAtResponse{}, nil\n}\n\nfunc (srv *grpcServer) GetNotifications(ctx context.Context, request *pb.GetNotificationsRequest) (*pb.GetNotificationsResponse, error) {\n\t// textile expects int instead of int64 for limit field\n\tn, err := srv.sv.GetNotifications(ctx, request.Seek, int(request.Limit))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparsedNotifs := []*pb.Notification{}\n\n\tfor _, notif := range n {\n\t\tparsedNotif := mapToPbNotification(*notif)\n\t\tparsedNotifs = append(parsedNotifs, parsedNotif)\n\t}\n\n\tvar no string\n\tif len(parsedNotifs) > 0 {\n\t\tno = parsedNotifs[len(parsedNotifs)-1].ID\n\t}\n\n\tls, err := srv.sv.GetNotificationsLastSeenAt()\n\tif err != nil {\n\t\t// error getting last seen at but we dont want to fail the\n\t\t// whole request for that\n\t\tls = 0\n\t}\n\n\treturn &pb.GetNotificationsResponse{\n\t\tNotifications: parsedNotifs,\n\t\tNextOffset:    no,\n\t\tLastSeenAt:    ls,\n\t}, nil\n}\n\nfunc (srv *grpcServer) ReadNotification(ctx context.Context, request *pb.ReadNotificationRequest) (*pb.ReadNotificationResponse, error) {\n\treturn nil, errNotImplemented\n}\n\nfunc (srv *grpcServer) HandleFilesInvitation(\n\tctx context.Context,\n\trequest *pb.HandleFilesInvitationRequest,\n) (*pb.HandleFilesInvitationResponse, error) {\n\terr := srv.sv.HandleSharedFilesInvitation(ctx, request.InvitationID, request.Accept)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.HandleFilesInvitationResponse{}, nil\n}\n\nfunc (srv *grpcServer) NotificationSubscribe(empty *empty.Empty, stream pb.SpaceApi_NotificationSubscribeServer) error {\n\tsrv.registerNotificationStream(stream)\n\t// waits until request is done\n\tselect {\n\tcase <-stream.Context().Done():\n\t\tbreak\n\t}\n\t// clean up stream\n\tsrv.registerNotificationStream(nil)\n\tlog.Info(\"closing stream\")\n\treturn nil\n}\n\nfunc (srv *grpcServer) registerNotificationStream(stream pb.SpaceApi_NotificationSubscribeServer) {\n\tsrv.notificationEventStream = stream\n}\n\nfunc (srv *grpcServer) sendNotificationEvent(event *pb.NotificationEventResponse) {\n\tif srv.notificationEventStream != nil {\n\t\tlog.Info(\"sending events to client\")\n\t\tsrv.notificationEventStream.Send(event)\n\t}\n}\n\nfunc (srv *grpcServer) SendNotificationEvent(notif *domain.Notification) {\n\tparsedNotif := mapToPbNotification(*notif)\n\n\tpe := &pb.NotificationEventResponse{\n\t\tNotification: parsedNotif,\n\t}\n\n\tsrv.sendNotificationEvent(pe)\n}\n"
  },
  {
    "path": "grpc/handlers_search.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\n// Search files based on query fields\nfunc (srv *grpcServer) SearchFiles(ctx context.Context, request *pb.SearchFilesRequest) (*pb.SearchFilesResponse, error) {\n\tif request.Query == \"\" {\n\t\treturn &pb.SearchFilesResponse{\n\t\t\tEntries: []*pb.SearchFilesDirectoryEntry{},\n\t\t\tQuery:   request.Query,\n\t\t}, nil\n\t}\n\n\tentries, err := srv.sv.SearchFiles(ctx, request.Query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsearchResponseEntries := make([]*pb.SearchFilesDirectoryEntry, len(entries))\n\tfor i, e := range entries {\n\t\tsearchResponseEntries[i] = &pb.SearchFilesDirectoryEntry{\n\t\t\tEntry: &pb.ListDirectoryEntry{\n\t\t\t\tPath:                e.Path,\n\t\t\t\tIsDir:               e.IsDir,\n\t\t\t\tName:                e.Name,\n\t\t\t\tSizeInBytes:         e.SizeInBytes,\n\t\t\t\tCreated:             e.Created,\n\t\t\t\tUpdated:             e.Updated,\n\t\t\t\tFileExtension:       e.FileExtension,\n\t\t\t\tIpfsHash:            e.IpfsHash,\n\t\t\t\tIsLocallyAvailable:  e.LocallyAvailable,\n\t\t\t\tIsBackupInProgress:  e.BackupInProgress,\n\t\t\t\tIsRestoreInProgress: e.RestoreInProgress,\n\t\t\t},\n\t\t\tDbId:   e.DbID,\n\t\t\tBucket: e.Bucket,\n\t\t}\n\t}\n\n\treturn &pb.SearchFilesResponse{\n\t\tEntries: searchResponseEntries,\n\t\tQuery:   request.Query,\n\t}, nil\n}\n"
  },
  {
    "path": "grpc/handlers_sharing.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/util/address\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/libp2p/go-libp2p-core/crypto\"\n\t\"github.com/opentracing/opentracing-go\"\n)\n\nfunc (srv *grpcServer) ShareFilesViaPublicKey(ctx context.Context, request *pb.ShareFilesViaPublicKeyRequest) (*pb.ShareFilesViaPublicKeyResponse, error) {\n\n\tvar pks []crypto.PubKey\n\n\tfor _, pk := range request.PublicKeys {\n\t\tb, err := hex.DecodeString(pk)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp, err := crypto.UnmarshalEd25519PublicKey([]byte(b))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpks = append(pks, p)\n\t}\n\n\tvar cleanedPaths []domain.FullPath\n\tfor _, path := range request.Paths {\n\t\tcleanedPath := &domain.FullPath{\n\t\t\tBucket: path.Bucket,\n\t\t\tPath:   path.Path,\n\t\t\tDbId:   path.DbId,\n\t\t}\n\n\t\tcleanedPaths = append(cleanedPaths, *cleanedPath)\n\t}\n\n\t// fail before since actual sharing is irreversible\n\terr := srv.sv.AddRecentlySharedPublicKeys(ctx, pks)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = srv.sv.ShareFilesViaPublicKey(ctx, cleanedPaths, pks)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.ShareFilesViaPublicKeyResponse{}, nil\n}\n\nfunc (srv *grpcServer) UnshareFilesViaPublicKey(\n\tctx context.Context,\n\trequest *pb.UnshareFilesViaPublicKeyRequest,\n) (*pb.UnshareFilesViaPublicKeyResponse, error) {\n\tvar pks []crypto.PubKey\n\n\tfor _, pk := range request.PublicKeys {\n\t\tb, err := hex.DecodeString(pk)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp, err := crypto.UnmarshalEd25519PublicKey(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpks = append(pks, p)\n\t}\n\n\tvar domainPaths []domain.FullPath\n\tfor _, path := range request.Paths {\n\t\tcleanedPath := domain.FullPath{\n\t\t\tBucket: path.Bucket,\n\t\t\tPath:   path.Path,\n\t\t\tDbId:   path.DbId,\n\t\t}\n\n\t\tdomainPaths = append(domainPaths, cleanedPath)\n\t}\n\n\terr := srv.sv.UnshareFilesViaPublicKey(ctx, domainPaths, pks)\n\n\treturn &pb.UnshareFilesViaPublicKeyResponse{}, err\n}\n\nfunc (srv *grpcServer) GetSharedWithMeFiles(ctx context.Context, request *pb.GetSharedWithMeFilesRequest) (*pb.GetSharedWithMeFilesResponse, error) {\n\tentries, offset, err := srv.sv.GetSharedWithMeFiles(ctx, request.Seek, int(request.Limit))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdirEntries := make([]*pb.SharedListDirectoryEntry, 0)\n\n\tfor _, e := range entries {\n\t\tmembers := make([]*pb.FileMember, 0)\n\n\t\tfor _, m := range e.Members {\n\t\t\tmembers = append(members, &pb.FileMember{\n\t\t\t\tPublicKey: m.PublicKey,\n\t\t\t\tAddress:   m.Address,\n\t\t\t})\n\t\t}\n\n\t\tvar backupCount = 0\n\t\tif e.BackedUp {\n\t\t\tbackupCount = 1\n\t\t}\n\n\t\tdirEntry := &pb.SharedListDirectoryEntry{\n\t\t\tDbId:     e.DbID,\n\t\t\tBucket:   e.Bucket,\n\t\t\tSharedBy: e.SharedBy,\n\t\t\tEntry: &pb.ListDirectoryEntry{\n\t\t\t\tPath:               e.Path,\n\t\t\t\tIsDir:              e.IsDir,\n\t\t\t\tName:               e.Name,\n\t\t\t\tSizeInBytes:        e.SizeInBytes,\n\t\t\t\tCreated:            e.Created,\n\t\t\t\tUpdated:            e.Updated,\n\t\t\t\tFileExtension:      e.FileExtension,\n\t\t\t\tIpfsHash:           e.IpfsHash,\n\t\t\t\tMembers:            members,\n\t\t\t\tIsLocallyAvailable: e.LocallyAvailable,\n\t\t\t\tBackupCount:        int64(backupCount),\n\t\t\t},\n\t\t\tIsPublicLink: e.IsPublicLink,\n\t\t}\n\t\tdirEntries = append(dirEntries, dirEntry)\n\t}\n\n\tres := &pb.GetSharedWithMeFilesResponse{\n\t\tItems:      dirEntries,\n\t\tNextOffset: offset,\n\t}\n\n\treturn res, nil\n}\n\nfunc (srv *grpcServer) GetSharedByMeFiles(ctx context.Context, request *pb.GetSharedByMeFilesRequest) (*pb.GetSharedByMeFilesResponse, error) {\n\tentries, offset, err := srv.sv.GetSharedByMeFiles(ctx, request.Seek, int(request.Limit))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdirEntries := make([]*pb.SharedListDirectoryEntry, 0)\n\n\tfor _, e := range entries {\n\t\tmembers := make([]*pb.FileMember, 0)\n\n\t\tfor _, m := range e.Members {\n\t\t\tmembers = append(members, &pb.FileMember{\n\t\t\t\tPublicKey: m.PublicKey,\n\t\t\t\tAddress:   m.Address,\n\t\t\t})\n\t\t}\n\n\t\tvar backupCount = 0\n\t\tif e.BackedUp {\n\t\t\tbackupCount = 1\n\t\t}\n\n\t\tdirEntry := &pb.SharedListDirectoryEntry{\n\t\t\tDbId:   e.DbID,\n\t\t\tBucket: e.Bucket,\n\t\t\tEntry: &pb.ListDirectoryEntry{\n\t\t\t\tPath:               e.Path,\n\t\t\t\tIsDir:              e.IsDir,\n\t\t\t\tName:               e.Name,\n\t\t\t\tSizeInBytes:        e.SizeInBytes,\n\t\t\t\tCreated:            e.Created,\n\t\t\t\tUpdated:            e.Updated,\n\t\t\t\tFileExtension:      e.FileExtension,\n\t\t\t\tIpfsHash:           e.IpfsHash,\n\t\t\t\tMembers:            members,\n\t\t\t\tIsLocallyAvailable: e.LocallyAvailable,\n\t\t\t\tBackupCount:        int64(backupCount),\n\t\t\t},\n\t\t\tIsPublicLink: e.IsPublicLink,\n\t\t}\n\t\tdirEntries = append(dirEntries, dirEntry)\n\t}\n\n\tres := &pb.GetSharedByMeFilesResponse{\n\t\tItems:      dirEntries,\n\t\tNextOffset: offset,\n\t}\n\n\treturn res, nil\n}\n\nfunc (srv *grpcServer) GeneratePublicFileLink(ctx context.Context, request *pb.GeneratePublicFileLinkRequest) (*pb.GeneratePublicFileLinkResponse, error) {\n\tspan, ctx := opentracing.StartSpanFromContext(ctx, \"GeneratePublicFileLink\")\n\tdefer span.Finish()\n\n\tres, err := srv.sv.GenerateFilesSharingLink(ctx, request.Password, request.ItemPaths, request.Bucket, request.DbId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.GeneratePublicFileLinkResponse{\n\t\tLink:    res.SpaceDownloadLink,\n\t\tFileCid: res.SharedFileCid,\n\t}, nil\n}\n\nfunc (srv *grpcServer) OpenPublicFile(ctx context.Context, request *pb.OpenPublicFileRequest) (*pb.OpenPublicFileResponse, error) {\n\tres, err := srv.sv.OpenSharedFile(ctx, request.FileCid, request.Password, request.Filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.OpenPublicFileResponse{\n\t\tLocation: res.Location,\n\t}, nil\n}\n\nfunc (srv *grpcServer) GetRecentlySharedWith(ctx context.Context, request *pb.GetRecentlySharedWithRequest) (*pb.GetRecentlySharedWithResponse, error) {\n\tfileMembers := make([]*pb.FileMember, 0)\n\n\tpks, err := srv.sv.RecentlySharedPublicKeys(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, pk := range pks {\n\t\tpubBytes, err := pk.Raw()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfileMember := &pb.FileMember{\n\t\t\tPublicKey: hex.EncodeToString(pubBytes),\n\t\t\tAddress:   address.DeriveAddress(pk),\n\t\t}\n\n\t\tfileMembers = append(fileMembers, fileMember)\n\t}\n\n\tres := &pb.GetRecentlySharedWithResponse{\n\t\tMembers: fileMembers,\n\t}\n\n\treturn res, nil\n}\n"
  },
  {
    "path": "grpc/handlers_textile.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/core/textile\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc parseBucket(ctx context.Context, b textile.Bucket) *pb.Bucket {\n\tbd := b.GetData()\n\n\titemsCount, _ := b.ItemsCount(ctx, bd.Path, false)\n\n\tbr := &pb.Bucket{\n\t\tKey:        bd.Key,\n\t\tName:       bd.Name,\n\t\tPath:       bd.Path,\n\t\tCreatedAt:  bd.CreatedAt,\n\t\tUpdatedAt:  bd.UpdatedAt,\n\t\tItemsCount: itemsCount,\n\n\t\t// TODO: Fill these out from metathread + identity service call\n\t\tMembers:          []*pb.BucketMember{},\n\t\tIsPersonalBucket: false,\n\t}\n\n\treturn br\n}\n\nfunc (srv *grpcServer) CreateBucket(ctx context.Context, request *pb.CreateBucketRequest) (*pb.CreateBucketResponse, error) {\n\tb, err := srv.sv.CreateBucket(ctx, request.Slug)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparsedBucket := parseBucket(ctx, b)\n\treturn &pb.CreateBucketResponse{\n\t\tBucket: parsedBucket,\n\t}, nil\n}\n\nfunc (srv *grpcServer) ListBuckets(ctx context.Context, request *pb.ListBucketsRequest) (*pb.ListBucketsResponse, error) {\n\tbuckets, err := srv.sv.ListBuckets(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparsedBuckets := []*pb.Bucket{}\n\n\tfor _, b := range buckets {\n\t\tparsedBucket := parseBucket(ctx, b)\n\t\tparsedBuckets = append(parsedBuckets, parsedBucket)\n\t}\n\n\treturn &pb.ListBucketsResponse{\n\t\tBuckets: parsedBuckets,\n\t}, nil\n}\n\nfunc (srv *grpcServer) ShareBucket(ctx context.Context, request *pb.ShareBucketRequest) (*pb.ShareBucketResponse, error) {\n\ti, err := srv.sv.ShareBucket(ctx, request.Bucket)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tti := &pb.ThreadInfo{\n\t\tAddresses: i.Addresses,\n\t\tKey:       i.Key,\n\t}\n\n\treturn &pb.ShareBucketResponse{\n\t\tThreadinfo: ti,\n\t}, nil\n}\n\nfunc (srv *grpcServer) JoinBucket(ctx context.Context, request *pb.JoinBucketRequest) (*pb.JoinBucketResponse, error) {\n\tti := &domain.ThreadInfo{\n\t\tAddresses: request.Threadinfo.Addresses,\n\t\tKey:       request.Threadinfo.Key,\n\t}\n\tr, err := srv.sv.JoinBucket(ctx, request.Bucket, ti)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &pb.JoinBucketResponse{\n\t\tResult: r,\n\t}, nil\n}\n"
  },
  {
    "path": "grpc/handlers_vault.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) BackupKeysByPassphrase(ctx context.Context, request *pb.BackupKeysByPassphraseRequest) (*pb.BackupKeysByPassphraseResponse, error) {\n\tresp := &pb.BackupKeysByPassphraseResponse{}\n\terr := srv.sv.BackupKeysByPassphrase(ctx, request.Uuid, request.Passphrase, domain.KeyBackupType(request.Type))\n\n\treturn resp, err\n}\n\nfunc (srv *grpcServer) RecoverKeysByPassphrase(ctx context.Context, request *pb.RecoverKeysByPassphraseRequest) (*pb.RecoverKeysByPassphraseResponse, error) {\n\tresp := &pb.RecoverKeysByPassphraseResponse{}\n\terr := srv.sv.RecoverKeysByPassphrase(ctx, request.Uuid, request.Passphrase, domain.KeyBackupType(request.Type))\n\n\treturn resp, err\n}\n\nfunc (srv *grpcServer) CreateLocalKeysBackup(ctx context.Context, request *pb.CreateLocalKeysBackupRequest) (*pb.CreateLocalKeysBackupResponse, error) {\n\tresp := &pb.CreateLocalKeysBackupResponse{}\n\terr := srv.sv.CreateLocalKeysBackup(ctx, request.PathToKeyBackup)\n\n\treturn resp, err\n}\n\nfunc (srv *grpcServer) RecoverKeysByLocalBackup(ctx context.Context, request *pb.RecoverKeysByLocalBackupRequest) (*pb.RecoverKeysByLocalBackupResponse, error) {\n\tresp := &pb.RecoverKeysByLocalBackupResponse{}\n\terr := srv.sv.RecoverKeysByLocalBackup(ctx, request.PathToKeyBackup)\n\n\treturn resp, err\n}\n\nfunc (srv *grpcServer) TestKeysPassphrase(ctx context.Context, request *pb.TestKeysPassphraseRequest) (*pb.TestKeysPassphraseResponse, error) {\n\tresp := &pb.TestKeysPassphraseResponse{}\n\terr := srv.sv.TestPassphrase(ctx, request.Uuid, request.Passphrase)\n\n\treturn resp, err\n}\n"
  },
  {
    "path": "grpc/pb/space.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.6.1\n// source: space.proto\n\npackage pb\n\nimport (\n\tcontext \"context\"\n\tproto \"github.com/golang/protobuf/proto\"\n\tempty \"github.com/golang/protobuf/ptypes/empty\"\n\t_ \"google.golang.org/genproto/googleapis/api/annotations\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// This is a compile-time assertion that a sufficiently up-to-date version\n// of the legacy proto package is being used.\nconst _ = proto.ProtoPackageIsVersion4\n\ntype EventType int32\n\nconst (\n\tEventType_ENTRY_ADDED               EventType = 0\n\tEventType_ENTRY_DELETED             EventType = 1\n\tEventType_ENTRY_UPDATED             EventType = 2\n\tEventType_ENTRY_BACKUP_IN_PROGRESS  EventType = 3\n\tEventType_ENTRY_BACKUP_READY        EventType = 4\n\tEventType_ENTRY_RESTORE_IN_PROGRESS EventType = 5\n\tEventType_ENTRY_RESTORE_READY       EventType = 6\n\tEventType_FOLDER_ADDED              EventType = 7\n\tEventType_FOLDER_DELETED            EventType = 8\n\tEventType_FOLDER_UPDATED            EventType = 9\n)\n\n// Enum value maps for EventType.\nvar (\n\tEventType_name = map[int32]string{\n\t\t0: \"ENTRY_ADDED\",\n\t\t1: \"ENTRY_DELETED\",\n\t\t2: \"ENTRY_UPDATED\",\n\t\t3: \"ENTRY_BACKUP_IN_PROGRESS\",\n\t\t4: \"ENTRY_BACKUP_READY\",\n\t\t5: \"ENTRY_RESTORE_IN_PROGRESS\",\n\t\t6: \"ENTRY_RESTORE_READY\",\n\t\t7: \"FOLDER_ADDED\",\n\t\t8: \"FOLDER_DELETED\",\n\t\t9: \"FOLDER_UPDATED\",\n\t}\n\tEventType_value = map[string]int32{\n\t\t\"ENTRY_ADDED\":               0,\n\t\t\"ENTRY_DELETED\":             1,\n\t\t\"ENTRY_UPDATED\":             2,\n\t\t\"ENTRY_BACKUP_IN_PROGRESS\":  3,\n\t\t\"ENTRY_BACKUP_READY\":        4,\n\t\t\"ENTRY_RESTORE_IN_PROGRESS\": 5,\n\t\t\"ENTRY_RESTORE_READY\":       6,\n\t\t\"FOLDER_ADDED\":              7,\n\t\t\"FOLDER_DELETED\":            8,\n\t\t\"FOLDER_UPDATED\":            9,\n\t}\n)\n\nfunc (x EventType) Enum() *EventType {\n\tp := new(EventType)\n\t*p = x\n\treturn p\n}\n\nfunc (x EventType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (EventType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_space_proto_enumTypes[0].Descriptor()\n}\n\nfunc (EventType) Type() protoreflect.EnumType {\n\treturn &file_space_proto_enumTypes[0]\n}\n\nfunc (x EventType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use EventType.Descriptor instead.\nfunc (EventType) EnumDescriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{0}\n}\n\ntype KeyBackupType int32\n\nconst (\n\tKeyBackupType_PASSWORD KeyBackupType = 0\n\tKeyBackupType_GOOGLE   KeyBackupType = 1\n\tKeyBackupType_TWITTER  KeyBackupType = 2\n\tKeyBackupType_EMAIL    KeyBackupType = 3\n)\n\n// Enum value maps for KeyBackupType.\nvar (\n\tKeyBackupType_name = map[int32]string{\n\t\t0: \"PASSWORD\",\n\t\t1: \"GOOGLE\",\n\t\t2: \"TWITTER\",\n\t\t3: \"EMAIL\",\n\t}\n\tKeyBackupType_value = map[string]int32{\n\t\t\"PASSWORD\": 0,\n\t\t\"GOOGLE\":   1,\n\t\t\"TWITTER\":  2,\n\t\t\"EMAIL\":    3,\n\t}\n)\n\nfunc (x KeyBackupType) Enum() *KeyBackupType {\n\tp := new(KeyBackupType)\n\t*p = x\n\treturn p\n}\n\nfunc (x KeyBackupType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (KeyBackupType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_space_proto_enumTypes[1].Descriptor()\n}\n\nfunc (KeyBackupType) Type() protoreflect.EnumType {\n\treturn &file_space_proto_enumTypes[1]\n}\n\nfunc (x KeyBackupType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use KeyBackupType.Descriptor instead.\nfunc (KeyBackupType) EnumDescriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{1}\n}\n\ntype FuseState int32\n\nconst (\n\tFuseState_UNSUPPORTED   FuseState = 0\n\tFuseState_NOT_INSTALLED FuseState = 1\n\tFuseState_UNMOUNTED     FuseState = 2\n\tFuseState_MOUNTED       FuseState = 3\n)\n\n// Enum value maps for FuseState.\nvar (\n\tFuseState_name = map[int32]string{\n\t\t0: \"UNSUPPORTED\",\n\t\t1: \"NOT_INSTALLED\",\n\t\t2: \"UNMOUNTED\",\n\t\t3: \"MOUNTED\",\n\t}\n\tFuseState_value = map[string]int32{\n\t\t\"UNSUPPORTED\":   0,\n\t\t\"NOT_INSTALLED\": 1,\n\t\t\"UNMOUNTED\":     2,\n\t\t\"MOUNTED\":       3,\n\t}\n)\n\nfunc (x FuseState) Enum() *FuseState {\n\tp := new(FuseState)\n\t*p = x\n\treturn p\n}\n\nfunc (x FuseState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (FuseState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_space_proto_enumTypes[2].Descriptor()\n}\n\nfunc (FuseState) Type() protoreflect.EnumType {\n\treturn &file_space_proto_enumTypes[2]\n}\n\nfunc (x FuseState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use FuseState.Descriptor instead.\nfunc (FuseState) EnumDescriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{2}\n}\n\ntype NotificationType int32\n\nconst (\n\tNotificationType_UNKNOWN            NotificationType = 0\n\tNotificationType_INVITATION         NotificationType = 1\n\tNotificationType_USAGEALERT         NotificationType = 2\n\tNotificationType_INVITATION_REPLY   NotificationType = 3\n\tNotificationType_REVOKED_INVITATION NotificationType = 4\n)\n\n// Enum value maps for NotificationType.\nvar (\n\tNotificationType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"INVITATION\",\n\t\t2: \"USAGEALERT\",\n\t\t3: \"INVITATION_REPLY\",\n\t\t4: \"REVOKED_INVITATION\",\n\t}\n\tNotificationType_value = map[string]int32{\n\t\t\"UNKNOWN\":            0,\n\t\t\"INVITATION\":         1,\n\t\t\"USAGEALERT\":         2,\n\t\t\"INVITATION_REPLY\":   3,\n\t\t\"REVOKED_INVITATION\": 4,\n\t}\n)\n\nfunc (x NotificationType) Enum() *NotificationType {\n\tp := new(NotificationType)\n\t*p = x\n\treturn p\n}\n\nfunc (x NotificationType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NotificationType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_space_proto_enumTypes[3].Descriptor()\n}\n\nfunc (NotificationType) Type() protoreflect.EnumType {\n\treturn &file_space_proto_enumTypes[3]\n}\n\nfunc (x NotificationType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NotificationType.Descriptor instead.\nfunc (NotificationType) EnumDescriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{3}\n}\n\ntype InvitationStatus int32\n\nconst (\n\tInvitationStatus_PENDING  InvitationStatus = 0\n\tInvitationStatus_ACCEPTED InvitationStatus = 1\n\tInvitationStatus_REJECTED InvitationStatus = 2\n)\n\n// Enum value maps for InvitationStatus.\nvar (\n\tInvitationStatus_name = map[int32]string{\n\t\t0: \"PENDING\",\n\t\t1: \"ACCEPTED\",\n\t\t2: \"REJECTED\",\n\t}\n\tInvitationStatus_value = map[string]int32{\n\t\t\"PENDING\":  0,\n\t\t\"ACCEPTED\": 1,\n\t\t\"REJECTED\": 2,\n\t}\n)\n\nfunc (x InvitationStatus) Enum() *InvitationStatus {\n\tp := new(InvitationStatus)\n\t*p = x\n\treturn p\n}\n\nfunc (x InvitationStatus) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (InvitationStatus) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_space_proto_enumTypes[4].Descriptor()\n}\n\nfunc (InvitationStatus) Type() protoreflect.EnumType {\n\treturn &file_space_proto_enumTypes[4]\n}\n\nfunc (x InvitationStatus) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use InvitationStatus.Descriptor instead.\nfunc (InvitationStatus) EnumDescriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{4}\n}\n\ntype SearchFilesRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tQuery string `protobuf:\"bytes,1,opt,name=query,proto3\" json:\"query,omitempty\"`\n}\n\nfunc (x *SearchFilesRequest) Reset() {\n\t*x = SearchFilesRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SearchFilesRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SearchFilesRequest) ProtoMessage() {}\n\nfunc (x *SearchFilesRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SearchFilesRequest.ProtoReflect.Descriptor instead.\nfunc (*SearchFilesRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *SearchFilesRequest) GetQuery() string {\n\tif x != nil {\n\t\treturn x.Query\n\t}\n\treturn \"\"\n}\n\ntype SearchFilesResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntries []*SearchFilesDirectoryEntry `protobuf:\"bytes,1,rep,name=entries,proto3\" json:\"entries,omitempty\"`\n\tQuery   string                       `protobuf:\"bytes,2,opt,name=query,proto3\" json:\"query,omitempty\"`\n}\n\nfunc (x *SearchFilesResponse) Reset() {\n\t*x = SearchFilesResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SearchFilesResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SearchFilesResponse) ProtoMessage() {}\n\nfunc (x *SearchFilesResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SearchFilesResponse.ProtoReflect.Descriptor instead.\nfunc (*SearchFilesResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *SearchFilesResponse) GetEntries() []*SearchFilesDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Entries\n\t}\n\treturn nil\n}\n\nfunc (x *SearchFilesResponse) GetQuery() string {\n\tif x != nil {\n\t\treturn x.Query\n\t}\n\treturn \"\"\n}\n\ntype SearchFilesDirectoryEntry struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntry  *ListDirectoryEntry `protobuf:\"bytes,1,opt,name=entry,proto3\" json:\"entry,omitempty\"`\n\tDbId   string              `protobuf:\"bytes,2,opt,name=dbId,proto3\" json:\"dbId,omitempty\"`\n\tBucket string              `protobuf:\"bytes,3,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *SearchFilesDirectoryEntry) Reset() {\n\t*x = SearchFilesDirectoryEntry{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SearchFilesDirectoryEntry) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SearchFilesDirectoryEntry) ProtoMessage() {}\n\nfunc (x *SearchFilesDirectoryEntry) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SearchFilesDirectoryEntry.ProtoReflect.Descriptor instead.\nfunc (*SearchFilesDirectoryEntry) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SearchFilesDirectoryEntry) GetEntry() *ListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Entry\n\t}\n\treturn nil\n}\n\nfunc (x *SearchFilesDirectoryEntry) GetDbId() string {\n\tif x != nil {\n\t\treturn x.DbId\n\t}\n\treturn \"\"\n}\n\nfunc (x *SearchFilesDirectoryEntry) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype SetNotificationsLastSeenAtRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTimestamp int64 `protobuf:\"varint,1,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n}\n\nfunc (x *SetNotificationsLastSeenAtRequest) Reset() {\n\t*x = SetNotificationsLastSeenAtRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SetNotificationsLastSeenAtRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SetNotificationsLastSeenAtRequest) ProtoMessage() {}\n\nfunc (x *SetNotificationsLastSeenAtRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SetNotificationsLastSeenAtRequest.ProtoReflect.Descriptor instead.\nfunc (*SetNotificationsLastSeenAtRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *SetNotificationsLastSeenAtRequest) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.Timestamp\n\t}\n\treturn 0\n}\n\ntype SetNotificationsLastSeenAtResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *SetNotificationsLastSeenAtResponse) Reset() {\n\t*x = SetNotificationsLastSeenAtResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SetNotificationsLastSeenAtResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SetNotificationsLastSeenAtResponse) ProtoMessage() {}\n\nfunc (x *SetNotificationsLastSeenAtResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SetNotificationsLastSeenAtResponse.ProtoReflect.Descriptor instead.\nfunc (*SetNotificationsLastSeenAtResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{4}\n}\n\ntype GetSharedWithMeFilesRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSeek  string `protobuf:\"bytes,1,opt,name=seek,proto3\" json:\"seek,omitempty\"`\n\tLimit int64  `protobuf:\"varint,2,opt,name=limit,proto3\" json:\"limit,omitempty\"`\n}\n\nfunc (x *GetSharedWithMeFilesRequest) Reset() {\n\t*x = GetSharedWithMeFilesRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetSharedWithMeFilesRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetSharedWithMeFilesRequest) ProtoMessage() {}\n\nfunc (x *GetSharedWithMeFilesRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetSharedWithMeFilesRequest.ProtoReflect.Descriptor instead.\nfunc (*GetSharedWithMeFilesRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *GetSharedWithMeFilesRequest) GetSeek() string {\n\tif x != nil {\n\t\treturn x.Seek\n\t}\n\treturn \"\"\n}\n\nfunc (x *GetSharedWithMeFilesRequest) GetLimit() int64 {\n\tif x != nil {\n\t\treturn x.Limit\n\t}\n\treturn 0\n}\n\ntype GetSharedWithMeFilesResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tItems      []*SharedListDirectoryEntry `protobuf:\"bytes,1,rep,name=items,proto3\" json:\"items,omitempty\"`\n\tNextOffset string                      `protobuf:\"bytes,2,opt,name=nextOffset,proto3\" json:\"nextOffset,omitempty\"`\n}\n\nfunc (x *GetSharedWithMeFilesResponse) Reset() {\n\t*x = GetSharedWithMeFilesResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetSharedWithMeFilesResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetSharedWithMeFilesResponse) ProtoMessage() {}\n\nfunc (x *GetSharedWithMeFilesResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetSharedWithMeFilesResponse.ProtoReflect.Descriptor instead.\nfunc (*GetSharedWithMeFilesResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *GetSharedWithMeFilesResponse) GetItems() []*SharedListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Items\n\t}\n\treturn nil\n}\n\nfunc (x *GetSharedWithMeFilesResponse) GetNextOffset() string {\n\tif x != nil {\n\t\treturn x.NextOffset\n\t}\n\treturn \"\"\n}\n\ntype GetSharedByMeFilesRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSeek  string `protobuf:\"bytes,1,opt,name=seek,proto3\" json:\"seek,omitempty\"`\n\tLimit int64  `protobuf:\"varint,2,opt,name=limit,proto3\" json:\"limit,omitempty\"`\n}\n\nfunc (x *GetSharedByMeFilesRequest) Reset() {\n\t*x = GetSharedByMeFilesRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetSharedByMeFilesRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetSharedByMeFilesRequest) ProtoMessage() {}\n\nfunc (x *GetSharedByMeFilesRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetSharedByMeFilesRequest.ProtoReflect.Descriptor instead.\nfunc (*GetSharedByMeFilesRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *GetSharedByMeFilesRequest) GetSeek() string {\n\tif x != nil {\n\t\treturn x.Seek\n\t}\n\treturn \"\"\n}\n\nfunc (x *GetSharedByMeFilesRequest) GetLimit() int64 {\n\tif x != nil {\n\t\treturn x.Limit\n\t}\n\treturn 0\n}\n\ntype GetSharedByMeFilesResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tItems      []*SharedListDirectoryEntry `protobuf:\"bytes,1,rep,name=items,proto3\" json:\"items,omitempty\"`\n\tNextOffset string                      `protobuf:\"bytes,2,opt,name=nextOffset,proto3\" json:\"nextOffset,omitempty\"`\n}\n\nfunc (x *GetSharedByMeFilesResponse) Reset() {\n\t*x = GetSharedByMeFilesResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetSharedByMeFilesResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetSharedByMeFilesResponse) ProtoMessage() {}\n\nfunc (x *GetSharedByMeFilesResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetSharedByMeFilesResponse.ProtoReflect.Descriptor instead.\nfunc (*GetSharedByMeFilesResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *GetSharedByMeFilesResponse) GetItems() []*SharedListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Items\n\t}\n\treturn nil\n}\n\nfunc (x *GetSharedByMeFilesResponse) GetNextOffset() string {\n\tif x != nil {\n\t\treturn x.NextOffset\n\t}\n\treturn \"\"\n}\n\ntype GetUsageInfoRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *GetUsageInfoRequest) Reset() {\n\t*x = GetUsageInfoRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetUsageInfoRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetUsageInfoRequest) ProtoMessage() {}\n\nfunc (x *GetUsageInfoRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetUsageInfoRequest.ProtoReflect.Descriptor instead.\nfunc (*GetUsageInfoRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{9}\n}\n\ntype GetUsageInfoResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLocalStarogeUsed   uint64 `protobuf:\"varint,1,opt,name=localStarogeUsed,proto3\" json:\"localStarogeUsed,omitempty\"`\n\tLocalBandwidthUsed uint64 `protobuf:\"varint,2,opt,name=localBandwidthUsed,proto3\" json:\"localBandwidthUsed,omitempty\"`\n\tSpaceStorageUsed   uint64 `protobuf:\"varint,3,opt,name=spaceStorageUsed,proto3\" json:\"spaceStorageUsed,omitempty\"`\n\tSpaceBandwidthUsed uint64 `protobuf:\"varint,4,opt,name=spaceBandwidthUsed,proto3\" json:\"spaceBandwidthUsed,omitempty\"`\n\tUsageQuota         uint64 `protobuf:\"varint,5,opt,name=usageQuota,proto3\" json:\"usageQuota,omitempty\"`\n}\n\nfunc (x *GetUsageInfoResponse) Reset() {\n\t*x = GetUsageInfoResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[10]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetUsageInfoResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetUsageInfoResponse) ProtoMessage() {}\n\nfunc (x *GetUsageInfoResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[10]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetUsageInfoResponse.ProtoReflect.Descriptor instead.\nfunc (*GetUsageInfoResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *GetUsageInfoResponse) GetLocalStarogeUsed() uint64 {\n\tif x != nil {\n\t\treturn x.LocalStarogeUsed\n\t}\n\treturn 0\n}\n\nfunc (x *GetUsageInfoResponse) GetLocalBandwidthUsed() uint64 {\n\tif x != nil {\n\t\treturn x.LocalBandwidthUsed\n\t}\n\treturn 0\n}\n\nfunc (x *GetUsageInfoResponse) GetSpaceStorageUsed() uint64 {\n\tif x != nil {\n\t\treturn x.SpaceStorageUsed\n\t}\n\treturn 0\n}\n\nfunc (x *GetUsageInfoResponse) GetSpaceBandwidthUsed() uint64 {\n\tif x != nil {\n\t\treturn x.SpaceBandwidthUsed\n\t}\n\treturn 0\n}\n\nfunc (x *GetUsageInfoResponse) GetUsageQuota() uint64 {\n\tif x != nil {\n\t\treturn x.UsageQuota\n\t}\n\treturn 0\n}\n\ntype ToggleBucketBackupRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket string `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tBackup bool   `protobuf:\"varint,2,opt,name=backup,proto3\" json:\"backup,omitempty\"`\n}\n\nfunc (x *ToggleBucketBackupRequest) Reset() {\n\t*x = ToggleBucketBackupRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[11]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ToggleBucketBackupRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ToggleBucketBackupRequest) ProtoMessage() {}\n\nfunc (x *ToggleBucketBackupRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[11]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ToggleBucketBackupRequest.ProtoReflect.Descriptor instead.\nfunc (*ToggleBucketBackupRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *ToggleBucketBackupRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *ToggleBucketBackupRequest) GetBackup() bool {\n\tif x != nil {\n\t\treturn x.Backup\n\t}\n\treturn false\n}\n\ntype ToggleBucketBackupResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *ToggleBucketBackupResponse) Reset() {\n\t*x = ToggleBucketBackupResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[12]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ToggleBucketBackupResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ToggleBucketBackupResponse) ProtoMessage() {}\n\nfunc (x *ToggleBucketBackupResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[12]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ToggleBucketBackupResponse.ProtoReflect.Descriptor instead.\nfunc (*ToggleBucketBackupResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{12}\n}\n\ntype BucketBackupRestoreRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket string `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *BucketBackupRestoreRequest) Reset() {\n\t*x = BucketBackupRestoreRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[13]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BucketBackupRestoreRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BucketBackupRestoreRequest) ProtoMessage() {}\n\nfunc (x *BucketBackupRestoreRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[13]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BucketBackupRestoreRequest.ProtoReflect.Descriptor instead.\nfunc (*BucketBackupRestoreRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *BucketBackupRestoreRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype BucketBackupRestoreResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *BucketBackupRestoreResponse) Reset() {\n\t*x = BucketBackupRestoreResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[14]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BucketBackupRestoreResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BucketBackupRestoreResponse) ProtoMessage() {}\n\nfunc (x *BucketBackupRestoreResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[14]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BucketBackupRestoreResponse.ProtoReflect.Descriptor instead.\nfunc (*BucketBackupRestoreResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{14}\n}\n\ntype ListDirectoriesRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket      string `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tOmitMembers bool   `protobuf:\"varint,2,opt,name=omitMembers,proto3\" json:\"omitMembers,omitempty\"`\n}\n\nfunc (x *ListDirectoriesRequest) Reset() {\n\t*x = ListDirectoriesRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[15]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListDirectoriesRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListDirectoriesRequest) ProtoMessage() {}\n\nfunc (x *ListDirectoriesRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[15]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListDirectoriesRequest.ProtoReflect.Descriptor instead.\nfunc (*ListDirectoriesRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *ListDirectoriesRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoriesRequest) GetOmitMembers() bool {\n\tif x != nil {\n\t\treturn x.OmitMembers\n\t}\n\treturn false\n}\n\ntype FileMember struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPublicKey string `protobuf:\"bytes,1,opt,name=publicKey,proto3\" json:\"publicKey,omitempty\"`\n\tAddress   string `protobuf:\"bytes,2,opt,name=address,proto3\" json:\"address,omitempty\"`\n}\n\nfunc (x *FileMember) Reset() {\n\t*x = FileMember{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[16]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FileMember) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FileMember) ProtoMessage() {}\n\nfunc (x *FileMember) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[16]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FileMember.ProtoReflect.Descriptor instead.\nfunc (*FileMember) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *FileMember) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *FileMember) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\ntype ListDirectoryEntry struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPath                string        `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tIsDir               bool          `protobuf:\"varint,2,opt,name=isDir,proto3\" json:\"isDir,omitempty\"`\n\tName                string        `protobuf:\"bytes,3,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tSizeInBytes         string        `protobuf:\"bytes,4,opt,name=sizeInBytes,proto3\" json:\"sizeInBytes,omitempty\"`\n\tCreated             string        `protobuf:\"bytes,5,opt,name=created,proto3\" json:\"created,omitempty\"`\n\tUpdated             string        `protobuf:\"bytes,6,opt,name=updated,proto3\" json:\"updated,omitempty\"`\n\tFileExtension       string        `protobuf:\"bytes,7,opt,name=fileExtension,proto3\" json:\"fileExtension,omitempty\"`\n\tIpfsHash            string        `protobuf:\"bytes,8,opt,name=ipfsHash,proto3\" json:\"ipfsHash,omitempty\"`\n\tIsLocallyAvailable  bool          `protobuf:\"varint,9,opt,name=isLocallyAvailable,proto3\" json:\"isLocallyAvailable,omitempty\"`\n\tBackupCount         int64         `protobuf:\"varint,10,opt,name=backupCount,proto3\" json:\"backupCount,omitempty\"`\n\tMembers             []*FileMember `protobuf:\"bytes,11,rep,name=members,proto3\" json:\"members,omitempty\"`\n\tIsBackupInProgress  bool          `protobuf:\"varint,12,opt,name=isBackupInProgress,proto3\" json:\"isBackupInProgress,omitempty\"`\n\tIsRestoreInProgress bool          `protobuf:\"varint,13,opt,name=isRestoreInProgress,proto3\" json:\"isRestoreInProgress,omitempty\"`\n}\n\nfunc (x *ListDirectoryEntry) Reset() {\n\t*x = ListDirectoryEntry{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[17]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListDirectoryEntry) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListDirectoryEntry) ProtoMessage() {}\n\nfunc (x *ListDirectoryEntry) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[17]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListDirectoryEntry.ProtoReflect.Descriptor instead.\nfunc (*ListDirectoryEntry) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{17}\n}\n\nfunc (x *ListDirectoryEntry) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetIsDir() bool {\n\tif x != nil {\n\t\treturn x.IsDir\n\t}\n\treturn false\n}\n\nfunc (x *ListDirectoryEntry) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetSizeInBytes() string {\n\tif x != nil {\n\t\treturn x.SizeInBytes\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetCreated() string {\n\tif x != nil {\n\t\treturn x.Created\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetUpdated() string {\n\tif x != nil {\n\t\treturn x.Updated\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetFileExtension() string {\n\tif x != nil {\n\t\treturn x.FileExtension\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetIpfsHash() string {\n\tif x != nil {\n\t\treturn x.IpfsHash\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryEntry) GetIsLocallyAvailable() bool {\n\tif x != nil {\n\t\treturn x.IsLocallyAvailable\n\t}\n\treturn false\n}\n\nfunc (x *ListDirectoryEntry) GetBackupCount() int64 {\n\tif x != nil {\n\t\treturn x.BackupCount\n\t}\n\treturn 0\n}\n\nfunc (x *ListDirectoryEntry) GetMembers() []*FileMember {\n\tif x != nil {\n\t\treturn x.Members\n\t}\n\treturn nil\n}\n\nfunc (x *ListDirectoryEntry) GetIsBackupInProgress() bool {\n\tif x != nil {\n\t\treturn x.IsBackupInProgress\n\t}\n\treturn false\n}\n\nfunc (x *ListDirectoryEntry) GetIsRestoreInProgress() bool {\n\tif x != nil {\n\t\treturn x.IsRestoreInProgress\n\t}\n\treturn false\n}\n\ntype SharedListDirectoryEntry struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntry        *ListDirectoryEntry `protobuf:\"bytes,1,opt,name=entry,proto3\" json:\"entry,omitempty\"`\n\tDbId         string              `protobuf:\"bytes,2,opt,name=dbId,proto3\" json:\"dbId,omitempty\"`\n\tBucket       string              `protobuf:\"bytes,3,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tIsPublicLink bool                `protobuf:\"varint,4,opt,name=isPublicLink,proto3\" json:\"isPublicLink,omitempty\"`\n\tSharedBy     string              `protobuf:\"bytes,5,opt,name=sharedBy,proto3\" json:\"sharedBy,omitempty\"`\n}\n\nfunc (x *SharedListDirectoryEntry) Reset() {\n\t*x = SharedListDirectoryEntry{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[18]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SharedListDirectoryEntry) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SharedListDirectoryEntry) ProtoMessage() {}\n\nfunc (x *SharedListDirectoryEntry) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[18]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SharedListDirectoryEntry.ProtoReflect.Descriptor instead.\nfunc (*SharedListDirectoryEntry) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *SharedListDirectoryEntry) GetEntry() *ListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Entry\n\t}\n\treturn nil\n}\n\nfunc (x *SharedListDirectoryEntry) GetDbId() string {\n\tif x != nil {\n\t\treturn x.DbId\n\t}\n\treturn \"\"\n}\n\nfunc (x *SharedListDirectoryEntry) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *SharedListDirectoryEntry) GetIsPublicLink() bool {\n\tif x != nil {\n\t\treturn x.IsPublicLink\n\t}\n\treturn false\n}\n\nfunc (x *SharedListDirectoryEntry) GetSharedBy() string {\n\tif x != nil {\n\t\treturn x.SharedBy\n\t}\n\treturn \"\"\n}\n\ntype ListDirectoriesResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntries []*ListDirectoryEntry `protobuf:\"bytes,1,rep,name=entries,proto3\" json:\"entries,omitempty\"`\n}\n\nfunc (x *ListDirectoriesResponse) Reset() {\n\t*x = ListDirectoriesResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[19]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListDirectoriesResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListDirectoriesResponse) ProtoMessage() {}\n\nfunc (x *ListDirectoriesResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[19]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListDirectoriesResponse.ProtoReflect.Descriptor instead.\nfunc (*ListDirectoriesResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{19}\n}\n\nfunc (x *ListDirectoriesResponse) GetEntries() []*ListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Entries\n\t}\n\treturn nil\n}\n\ntype ListDirectoryRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPath        string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tBucket      string `protobuf:\"bytes,2,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tOmitMembers bool   `protobuf:\"varint,3,opt,name=omitMembers,proto3\" json:\"omitMembers,omitempty\"`\n}\n\nfunc (x *ListDirectoryRequest) Reset() {\n\t*x = ListDirectoryRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[20]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListDirectoryRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListDirectoryRequest) ProtoMessage() {}\n\nfunc (x *ListDirectoryRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[20]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListDirectoryRequest.ProtoReflect.Descriptor instead.\nfunc (*ListDirectoryRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{20}\n}\n\nfunc (x *ListDirectoryRequest) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListDirectoryRequest) GetOmitMembers() bool {\n\tif x != nil {\n\t\treturn x.OmitMembers\n\t}\n\treturn false\n}\n\ntype ListDirectoryResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tEntries []*ListDirectoryEntry `protobuf:\"bytes,1,rep,name=entries,proto3\" json:\"entries,omitempty\"`\n}\n\nfunc (x *ListDirectoryResponse) Reset() {\n\t*x = ListDirectoryResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[21]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListDirectoryResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListDirectoryResponse) ProtoMessage() {}\n\nfunc (x *ListDirectoryResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[21]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListDirectoryResponse.ProtoReflect.Descriptor instead.\nfunc (*ListDirectoryResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{21}\n}\n\nfunc (x *ListDirectoryResponse) GetEntries() []*ListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Entries\n\t}\n\treturn nil\n}\n\ntype CreateBucketRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSlug string `protobuf:\"bytes,1,opt,name=slug,proto3\" json:\"slug,omitempty\"`\n}\n\nfunc (x *CreateBucketRequest) Reset() {\n\t*x = CreateBucketRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[22]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateBucketRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateBucketRequest) ProtoMessage() {}\n\nfunc (x *CreateBucketRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[22]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateBucketRequest.ProtoReflect.Descriptor instead.\nfunc (*CreateBucketRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{22}\n}\n\nfunc (x *CreateBucketRequest) GetSlug() string {\n\tif x != nil {\n\t\treturn x.Slug\n\t}\n\treturn \"\"\n}\n\ntype BucketMember struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAddress   string `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tPublicKey string `protobuf:\"bytes,2,opt,name=publicKey,proto3\" json:\"publicKey,omitempty\"`\n\tIsOwner   bool   `protobuf:\"varint,3,opt,name=isOwner,proto3\" json:\"isOwner,omitempty\"`\n\tHasJoined bool   `protobuf:\"varint,4,opt,name=hasJoined,proto3\" json:\"hasJoined,omitempty\"`\n}\n\nfunc (x *BucketMember) Reset() {\n\t*x = BucketMember{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[23]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BucketMember) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BucketMember) ProtoMessage() {}\n\nfunc (x *BucketMember) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[23]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BucketMember.ProtoReflect.Descriptor instead.\nfunc (*BucketMember) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{23}\n}\n\nfunc (x *BucketMember) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\nfunc (x *BucketMember) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *BucketMember) GetIsOwner() bool {\n\tif x != nil {\n\t\treturn x.IsOwner\n\t}\n\treturn false\n}\n\nfunc (x *BucketMember) GetHasJoined() bool {\n\tif x != nil {\n\t\treturn x.HasJoined\n\t}\n\treturn false\n}\n\ntype Bucket struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tKey              string          `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tName             string          `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tPath             string          `protobuf:\"bytes,3,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tCreatedAt        int64           `protobuf:\"varint,4,opt,name=createdAt,proto3\" json:\"createdAt,omitempty\"`\n\tUpdatedAt        int64           `protobuf:\"varint,5,opt,name=updatedAt,proto3\" json:\"updatedAt,omitempty\"`\n\tMembers          []*BucketMember `protobuf:\"bytes,6,rep,name=members,proto3\" json:\"members,omitempty\"`\n\tIsPersonalBucket bool            `protobuf:\"varint,7,opt,name=isPersonalBucket,proto3\" json:\"isPersonalBucket,omitempty\"`\n\tIsBackupEnabled  bool            `protobuf:\"varint,8,opt,name=isBackupEnabled,proto3\" json:\"isBackupEnabled,omitempty\"`\n\tItemsCount       int32           `protobuf:\"varint,9,opt,name=itemsCount,proto3\" json:\"itemsCount,omitempty\"`\n}\n\nfunc (x *Bucket) Reset() {\n\t*x = Bucket{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[24]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Bucket) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Bucket) ProtoMessage() {}\n\nfunc (x *Bucket) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[24]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Bucket.ProtoReflect.Descriptor instead.\nfunc (*Bucket) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{24}\n}\n\nfunc (x *Bucket) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *Bucket) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Bucket) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *Bucket) GetCreatedAt() int64 {\n\tif x != nil {\n\t\treturn x.CreatedAt\n\t}\n\treturn 0\n}\n\nfunc (x *Bucket) GetUpdatedAt() int64 {\n\tif x != nil {\n\t\treturn x.UpdatedAt\n\t}\n\treturn 0\n}\n\nfunc (x *Bucket) GetMembers() []*BucketMember {\n\tif x != nil {\n\t\treturn x.Members\n\t}\n\treturn nil\n}\n\nfunc (x *Bucket) GetIsPersonalBucket() bool {\n\tif x != nil {\n\t\treturn x.IsPersonalBucket\n\t}\n\treturn false\n}\n\nfunc (x *Bucket) GetIsBackupEnabled() bool {\n\tif x != nil {\n\t\treturn x.IsBackupEnabled\n\t}\n\treturn false\n}\n\nfunc (x *Bucket) GetItemsCount() int32 {\n\tif x != nil {\n\t\treturn x.ItemsCount\n\t}\n\treturn 0\n}\n\ntype CreateBucketResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket *Bucket `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *CreateBucketResponse) Reset() {\n\t*x = CreateBucketResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[25]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateBucketResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateBucketResponse) ProtoMessage() {}\n\nfunc (x *CreateBucketResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[25]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateBucketResponse.ProtoReflect.Descriptor instead.\nfunc (*CreateBucketResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{25}\n}\n\nfunc (x *CreateBucketResponse) GetBucket() *Bucket {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn nil\n}\n\ntype GenerateKeyPairRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *GenerateKeyPairRequest) Reset() {\n\t*x = GenerateKeyPairRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[26]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GenerateKeyPairRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateKeyPairRequest) ProtoMessage() {}\n\nfunc (x *GenerateKeyPairRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[26]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateKeyPairRequest.ProtoReflect.Descriptor instead.\nfunc (*GenerateKeyPairRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{26}\n}\n\ntype GenerateKeyPairResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMnemonic string `protobuf:\"bytes,1,opt,name=mnemonic,proto3\" json:\"mnemonic,omitempty\"`\n}\n\nfunc (x *GenerateKeyPairResponse) Reset() {\n\t*x = GenerateKeyPairResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[27]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GenerateKeyPairResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateKeyPairResponse) ProtoMessage() {}\n\nfunc (x *GenerateKeyPairResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[27]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateKeyPairResponse.ProtoReflect.Descriptor instead.\nfunc (*GenerateKeyPairResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{27}\n}\n\nfunc (x *GenerateKeyPairResponse) GetMnemonic() string {\n\tif x != nil {\n\t\treturn x.Mnemonic\n\t}\n\treturn \"\"\n}\n\ntype GetStoredMnemonicRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *GetStoredMnemonicRequest) Reset() {\n\t*x = GetStoredMnemonicRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[28]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetStoredMnemonicRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetStoredMnemonicRequest) ProtoMessage() {}\n\nfunc (x *GetStoredMnemonicRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[28]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetStoredMnemonicRequest.ProtoReflect.Descriptor instead.\nfunc (*GetStoredMnemonicRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{28}\n}\n\ntype GetStoredMnemonicResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMnemonic string `protobuf:\"bytes,1,opt,name=mnemonic,proto3\" json:\"mnemonic,omitempty\"`\n}\n\nfunc (x *GetStoredMnemonicResponse) Reset() {\n\t*x = GetStoredMnemonicResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[29]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetStoredMnemonicResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetStoredMnemonicResponse) ProtoMessage() {}\n\nfunc (x *GetStoredMnemonicResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[29]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetStoredMnemonicResponse.ProtoReflect.Descriptor instead.\nfunc (*GetStoredMnemonicResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{29}\n}\n\nfunc (x *GetStoredMnemonicResponse) GetMnemonic() string {\n\tif x != nil {\n\t\treturn x.Mnemonic\n\t}\n\treturn \"\"\n}\n\ntype RestoreKeyPairViaMnemonicRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMnemonic string `protobuf:\"bytes,1,opt,name=mnemonic,proto3\" json:\"mnemonic,omitempty\"`\n}\n\nfunc (x *RestoreKeyPairViaMnemonicRequest) Reset() {\n\t*x = RestoreKeyPairViaMnemonicRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[30]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RestoreKeyPairViaMnemonicRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestoreKeyPairViaMnemonicRequest) ProtoMessage() {}\n\nfunc (x *RestoreKeyPairViaMnemonicRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[30]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestoreKeyPairViaMnemonicRequest.ProtoReflect.Descriptor instead.\nfunc (*RestoreKeyPairViaMnemonicRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{30}\n}\n\nfunc (x *RestoreKeyPairViaMnemonicRequest) GetMnemonic() string {\n\tif x != nil {\n\t\treturn x.Mnemonic\n\t}\n\treturn \"\"\n}\n\ntype RestoreKeyPairViaMnemonicResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RestoreKeyPairViaMnemonicResponse) Reset() {\n\t*x = RestoreKeyPairViaMnemonicResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[31]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RestoreKeyPairViaMnemonicResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestoreKeyPairViaMnemonicResponse) ProtoMessage() {}\n\nfunc (x *RestoreKeyPairViaMnemonicResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[31]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestoreKeyPairViaMnemonicResponse.ProtoReflect.Descriptor instead.\nfunc (*RestoreKeyPairViaMnemonicResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{31}\n}\n\ntype FileEventResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tType   EventType           `protobuf:\"varint,1,opt,name=type,proto3,enum=space.EventType\" json:\"type,omitempty\"`\n\tEntry  *ListDirectoryEntry `protobuf:\"bytes,2,opt,name=entry,proto3\" json:\"entry,omitempty\"`\n\tBucket string              `protobuf:\"bytes,3,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tDbId   string              `protobuf:\"bytes,4,opt,name=dbId,proto3\" json:\"dbId,omitempty\"`\n}\n\nfunc (x *FileEventResponse) Reset() {\n\t*x = FileEventResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[32]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FileEventResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FileEventResponse) ProtoMessage() {}\n\nfunc (x *FileEventResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[32]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FileEventResponse.ProtoReflect.Descriptor instead.\nfunc (*FileEventResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{32}\n}\n\nfunc (x *FileEventResponse) GetType() EventType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn EventType_ENTRY_ADDED\n}\n\nfunc (x *FileEventResponse) GetEntry() *ListDirectoryEntry {\n\tif x != nil {\n\t\treturn x.Entry\n\t}\n\treturn nil\n}\n\nfunc (x *FileEventResponse) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *FileEventResponse) GetDbId() string {\n\tif x != nil {\n\t\treturn x.DbId\n\t}\n\treturn \"\"\n}\n\ntype TextileEventResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket string `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *TextileEventResponse) Reset() {\n\t*x = TextileEventResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[33]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TextileEventResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TextileEventResponse) ProtoMessage() {}\n\nfunc (x *TextileEventResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[33]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TextileEventResponse.ProtoReflect.Descriptor instead.\nfunc (*TextileEventResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{33}\n}\n\nfunc (x *TextileEventResponse) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype OpenFileRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPath   string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tBucket string `protobuf:\"bytes,2,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tDbId   string `protobuf:\"bytes,3,opt,name=dbId,proto3\" json:\"dbId,omitempty\"` // optional field to specify shared with me file\n}\n\nfunc (x *OpenFileRequest) Reset() {\n\t*x = OpenFileRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[34]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OpenFileRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OpenFileRequest) ProtoMessage() {}\n\nfunc (x *OpenFileRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[34]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OpenFileRequest.ProtoReflect.Descriptor instead.\nfunc (*OpenFileRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{34}\n}\n\nfunc (x *OpenFileRequest) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *OpenFileRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *OpenFileRequest) GetDbId() string {\n\tif x != nil {\n\t\treturn x.DbId\n\t}\n\treturn \"\"\n}\n\ntype OpenFileResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLocation string `protobuf:\"bytes,1,opt,name=location,proto3\" json:\"location,omitempty\"`\n}\n\nfunc (x *OpenFileResponse) Reset() {\n\t*x = OpenFileResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[35]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OpenFileResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OpenFileResponse) ProtoMessage() {}\n\nfunc (x *OpenFileResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[35]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OpenFileResponse.ProtoReflect.Descriptor instead.\nfunc (*OpenFileResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{35}\n}\n\nfunc (x *OpenFileResponse) GetLocation() string {\n\tif x != nil {\n\t\treturn x.Location\n\t}\n\treturn \"\"\n}\n\ntype OpenPublicFileRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tFileCid  string `protobuf:\"bytes,1,opt,name=fileCid,proto3\" json:\"fileCid,omitempty\"`\n\tPassword string `protobuf:\"bytes,2,opt,name=password,proto3\" json:\"password,omitempty\"`\n\tFilename string `protobuf:\"bytes,3,opt,name=filename,proto3\" json:\"filename,omitempty\"`\n}\n\nfunc (x *OpenPublicFileRequest) Reset() {\n\t*x = OpenPublicFileRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[36]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OpenPublicFileRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OpenPublicFileRequest) ProtoMessage() {}\n\nfunc (x *OpenPublicFileRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[36]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OpenPublicFileRequest.ProtoReflect.Descriptor instead.\nfunc (*OpenPublicFileRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{36}\n}\n\nfunc (x *OpenPublicFileRequest) GetFileCid() string {\n\tif x != nil {\n\t\treturn x.FileCid\n\t}\n\treturn \"\"\n}\n\nfunc (x *OpenPublicFileRequest) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\nfunc (x *OpenPublicFileRequest) GetFilename() string {\n\tif x != nil {\n\t\treturn x.Filename\n\t}\n\treturn \"\"\n}\n\ntype OpenPublicFileResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLocation string `protobuf:\"bytes,1,opt,name=location,proto3\" json:\"location,omitempty\"`\n}\n\nfunc (x *OpenPublicFileResponse) Reset() {\n\t*x = OpenPublicFileResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[37]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *OpenPublicFileResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OpenPublicFileResponse) ProtoMessage() {}\n\nfunc (x *OpenPublicFileResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[37]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OpenPublicFileResponse.ProtoReflect.Descriptor instead.\nfunc (*OpenPublicFileResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{37}\n}\n\nfunc (x *OpenPublicFileResponse) GetLocation() string {\n\tif x != nil {\n\t\treturn x.Location\n\t}\n\treturn \"\"\n}\n\ntype AddItemsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// full paths to file or Folder on FS. Needs to be a location available to the daemon\n\tSourcePaths []string `protobuf:\"bytes,1,rep,name=sourcePaths,proto3\" json:\"sourcePaths,omitempty\"`\n\t// target path in bucket.\n\tTargetPath string `protobuf:\"bytes,2,opt,name=targetPath,proto3\" json:\"targetPath,omitempty\"`\n\t// The bucket in which to save the item\n\tBucket string `protobuf:\"bytes,3,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *AddItemsRequest) Reset() {\n\t*x = AddItemsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[38]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddItemsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddItemsRequest) ProtoMessage() {}\n\nfunc (x *AddItemsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[38]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddItemsRequest.ProtoReflect.Descriptor instead.\nfunc (*AddItemsRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{38}\n}\n\nfunc (x *AddItemsRequest) GetSourcePaths() []string {\n\tif x != nil {\n\t\treturn x.SourcePaths\n\t}\n\treturn nil\n}\n\nfunc (x *AddItemsRequest) GetTargetPath() string {\n\tif x != nil {\n\t\treturn x.TargetPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *AddItemsRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype AddItemResult struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSourcePath string `protobuf:\"bytes,1,opt,name=sourcePath,proto3\" json:\"sourcePath,omitempty\"`\n\tBucketPath string `protobuf:\"bytes,2,opt,name=bucketPath,proto3\" json:\"bucketPath,omitempty\"`\n\tError      string `protobuf:\"bytes,3,opt,name=error,proto3\" json:\"error,omitempty\"`\n}\n\nfunc (x *AddItemResult) Reset() {\n\t*x = AddItemResult{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[39]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddItemResult) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddItemResult) ProtoMessage() {}\n\nfunc (x *AddItemResult) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[39]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddItemResult.ProtoReflect.Descriptor instead.\nfunc (*AddItemResult) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{39}\n}\n\nfunc (x *AddItemResult) GetSourcePath() string {\n\tif x != nil {\n\t\treturn x.SourcePath\n\t}\n\treturn \"\"\n}\n\nfunc (x *AddItemResult) GetBucketPath() string {\n\tif x != nil {\n\t\treturn x.BucketPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *AddItemResult) GetError() string {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn \"\"\n}\n\ntype AddItemsResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tResult         *AddItemResult `protobuf:\"bytes,1,opt,name=result,proto3\" json:\"result,omitempty\"`\n\tTotalFiles     int64          `protobuf:\"varint,2,opt,name=totalFiles,proto3\" json:\"totalFiles,omitempty\"`\n\tTotalBytes     int64          `protobuf:\"varint,3,opt,name=totalBytes,proto3\" json:\"totalBytes,omitempty\"`\n\tCompletedFiles int64          `protobuf:\"varint,4,opt,name=completedFiles,proto3\" json:\"completedFiles,omitempty\"`\n\tCompletedBytes int64          `protobuf:\"varint,5,opt,name=completedBytes,proto3\" json:\"completedBytes,omitempty\"`\n}\n\nfunc (x *AddItemsResponse) Reset() {\n\t*x = AddItemsResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[40]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AddItemsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddItemsResponse) ProtoMessage() {}\n\nfunc (x *AddItemsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[40]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddItemsResponse.ProtoReflect.Descriptor instead.\nfunc (*AddItemsResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{40}\n}\n\nfunc (x *AddItemsResponse) GetResult() *AddItemResult {\n\tif x != nil {\n\t\treturn x.Result\n\t}\n\treturn nil\n}\n\nfunc (x *AddItemsResponse) GetTotalFiles() int64 {\n\tif x != nil {\n\t\treturn x.TotalFiles\n\t}\n\treturn 0\n}\n\nfunc (x *AddItemsResponse) GetTotalBytes() int64 {\n\tif x != nil {\n\t\treturn x.TotalBytes\n\t}\n\treturn 0\n}\n\nfunc (x *AddItemsResponse) GetCompletedFiles() int64 {\n\tif x != nil {\n\t\treturn x.CompletedFiles\n\t}\n\treturn 0\n}\n\nfunc (x *AddItemsResponse) GetCompletedBytes() int64 {\n\tif x != nil {\n\t\treturn x.CompletedBytes\n\t}\n\treturn 0\n}\n\ntype CreateFolderRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// target path in bucket to add new empty folder\n\tPath string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\t// The bucket in which to add the folder\n\tBucket string `protobuf:\"bytes,2,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *CreateFolderRequest) Reset() {\n\t*x = CreateFolderRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[41]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateFolderRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateFolderRequest) ProtoMessage() {}\n\nfunc (x *CreateFolderRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[41]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateFolderRequest.ProtoReflect.Descriptor instead.\nfunc (*CreateFolderRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{41}\n}\n\nfunc (x *CreateFolderRequest) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *CreateFolderRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\n// not sure we need to return anything other than an error if we failed\ntype CreateFolderResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *CreateFolderResponse) Reset() {\n\t*x = CreateFolderResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[42]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateFolderResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateFolderResponse) ProtoMessage() {}\n\nfunc (x *CreateFolderResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[42]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateFolderResponse.ProtoReflect.Descriptor instead.\nfunc (*CreateFolderResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{42}\n}\n\ntype BackupKeysByPassphraseRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUuid       string        `protobuf:\"bytes,1,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tPassphrase string        `protobuf:\"bytes,2,opt,name=passphrase,proto3\" json:\"passphrase,omitempty\"`\n\tType       KeyBackupType `protobuf:\"varint,3,opt,name=type,proto3,enum=space.KeyBackupType\" json:\"type,omitempty\"`\n}\n\nfunc (x *BackupKeysByPassphraseRequest) Reset() {\n\t*x = BackupKeysByPassphraseRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[43]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BackupKeysByPassphraseRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BackupKeysByPassphraseRequest) ProtoMessage() {}\n\nfunc (x *BackupKeysByPassphraseRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[43]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BackupKeysByPassphraseRequest.ProtoReflect.Descriptor instead.\nfunc (*BackupKeysByPassphraseRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{43}\n}\n\nfunc (x *BackupKeysByPassphraseRequest) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *BackupKeysByPassphraseRequest) GetPassphrase() string {\n\tif x != nil {\n\t\treturn x.Passphrase\n\t}\n\treturn \"\"\n}\n\nfunc (x *BackupKeysByPassphraseRequest) GetType() KeyBackupType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn KeyBackupType_PASSWORD\n}\n\ntype BackupKeysByPassphraseResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *BackupKeysByPassphraseResponse) Reset() {\n\t*x = BackupKeysByPassphraseResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[44]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BackupKeysByPassphraseResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BackupKeysByPassphraseResponse) ProtoMessage() {}\n\nfunc (x *BackupKeysByPassphraseResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[44]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BackupKeysByPassphraseResponse.ProtoReflect.Descriptor instead.\nfunc (*BackupKeysByPassphraseResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{44}\n}\n\ntype RecoverKeysByPassphraseRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUuid       string        `protobuf:\"bytes,1,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tPassphrase string        `protobuf:\"bytes,2,opt,name=passphrase,proto3\" json:\"passphrase,omitempty\"`\n\tType       KeyBackupType `protobuf:\"varint,3,opt,name=type,proto3,enum=space.KeyBackupType\" json:\"type,omitempty\"`\n}\n\nfunc (x *RecoverKeysByPassphraseRequest) Reset() {\n\t*x = RecoverKeysByPassphraseRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[45]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RecoverKeysByPassphraseRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RecoverKeysByPassphraseRequest) ProtoMessage() {}\n\nfunc (x *RecoverKeysByPassphraseRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[45]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RecoverKeysByPassphraseRequest.ProtoReflect.Descriptor instead.\nfunc (*RecoverKeysByPassphraseRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{45}\n}\n\nfunc (x *RecoverKeysByPassphraseRequest) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *RecoverKeysByPassphraseRequest) GetPassphrase() string {\n\tif x != nil {\n\t\treturn x.Passphrase\n\t}\n\treturn \"\"\n}\n\nfunc (x *RecoverKeysByPassphraseRequest) GetType() KeyBackupType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn KeyBackupType_PASSWORD\n}\n\ntype RecoverKeysByPassphraseResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RecoverKeysByPassphraseResponse) Reset() {\n\t*x = RecoverKeysByPassphraseResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[46]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RecoverKeysByPassphraseResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RecoverKeysByPassphraseResponse) ProtoMessage() {}\n\nfunc (x *RecoverKeysByPassphraseResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[46]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RecoverKeysByPassphraseResponse.ProtoReflect.Descriptor instead.\nfunc (*RecoverKeysByPassphraseResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{46}\n}\n\ntype TestKeysPassphraseRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUuid       string `protobuf:\"bytes,1,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tPassphrase string `protobuf:\"bytes,2,opt,name=passphrase,proto3\" json:\"passphrase,omitempty\"`\n}\n\nfunc (x *TestKeysPassphraseRequest) Reset() {\n\t*x = TestKeysPassphraseRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[47]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TestKeysPassphraseRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TestKeysPassphraseRequest) ProtoMessage() {}\n\nfunc (x *TestKeysPassphraseRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[47]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TestKeysPassphraseRequest.ProtoReflect.Descriptor instead.\nfunc (*TestKeysPassphraseRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{47}\n}\n\nfunc (x *TestKeysPassphraseRequest) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *TestKeysPassphraseRequest) GetPassphrase() string {\n\tif x != nil {\n\t\treturn x.Passphrase\n\t}\n\treturn \"\"\n}\n\ntype TestKeysPassphraseResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *TestKeysPassphraseResponse) Reset() {\n\t*x = TestKeysPassphraseResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[48]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TestKeysPassphraseResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TestKeysPassphraseResponse) ProtoMessage() {}\n\nfunc (x *TestKeysPassphraseResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[48]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TestKeysPassphraseResponse.ProtoReflect.Descriptor instead.\nfunc (*TestKeysPassphraseResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{48}\n}\n\ntype ThreadInfo struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAddresses []string `protobuf:\"bytes,1,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tKey       string   `protobuf:\"bytes,2,opt,name=key,proto3\" json:\"key,omitempty\"`\n}\n\nfunc (x *ThreadInfo) Reset() {\n\t*x = ThreadInfo{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[49]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ThreadInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ThreadInfo) ProtoMessage() {}\n\nfunc (x *ThreadInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[49]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ThreadInfo.ProtoReflect.Descriptor instead.\nfunc (*ThreadInfo) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{49}\n}\n\nfunc (x *ThreadInfo) GetAddresses() []string {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\nfunc (x *ThreadInfo) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\ntype ShareBucketRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket string `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *ShareBucketRequest) Reset() {\n\t*x = ShareBucketRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[50]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ShareBucketRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShareBucketRequest) ProtoMessage() {}\n\nfunc (x *ShareBucketRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[50]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShareBucketRequest.ProtoReflect.Descriptor instead.\nfunc (*ShareBucketRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{50}\n}\n\nfunc (x *ShareBucketRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype ShareBucketResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tThreadinfo *ThreadInfo `protobuf:\"bytes,1,opt,name=threadinfo,proto3\" json:\"threadinfo,omitempty\"`\n}\n\nfunc (x *ShareBucketResponse) Reset() {\n\t*x = ShareBucketResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[51]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ShareBucketResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShareBucketResponse) ProtoMessage() {}\n\nfunc (x *ShareBucketResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[51]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShareBucketResponse.ProtoReflect.Descriptor instead.\nfunc (*ShareBucketResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{51}\n}\n\nfunc (x *ShareBucketResponse) GetThreadinfo() *ThreadInfo {\n\tif x != nil {\n\t\treturn x.Threadinfo\n\t}\n\treturn nil\n}\n\ntype JoinBucketRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tThreadinfo *ThreadInfo `protobuf:\"bytes,1,opt,name=threadinfo,proto3\" json:\"threadinfo,omitempty\"`\n\tBucket     string      `protobuf:\"bytes,2,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *JoinBucketRequest) Reset() {\n\t*x = JoinBucketRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[52]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *JoinBucketRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*JoinBucketRequest) ProtoMessage() {}\n\nfunc (x *JoinBucketRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[52]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use JoinBucketRequest.ProtoReflect.Descriptor instead.\nfunc (*JoinBucketRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{52}\n}\n\nfunc (x *JoinBucketRequest) GetThreadinfo() *ThreadInfo {\n\tif x != nil {\n\t\treturn x.Threadinfo\n\t}\n\treturn nil\n}\n\nfunc (x *JoinBucketRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype JoinBucketResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tResult bool `protobuf:\"varint,1,opt,name=result,proto3\" json:\"result,omitempty\"`\n}\n\nfunc (x *JoinBucketResponse) Reset() {\n\t*x = JoinBucketResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[53]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *JoinBucketResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*JoinBucketResponse) ProtoMessage() {}\n\nfunc (x *JoinBucketResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[53]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use JoinBucketResponse.ProtoReflect.Descriptor instead.\nfunc (*JoinBucketResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{53}\n}\n\nfunc (x *JoinBucketResponse) GetResult() bool {\n\tif x != nil {\n\t\treturn x.Result\n\t}\n\treturn false\n}\n\ntype ShareFilesViaPublicKeyRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPublicKeys []string    `protobuf:\"bytes,1,rep,name=publicKeys,proto3\" json:\"publicKeys,omitempty\"`\n\tPaths      []*FullPath `protobuf:\"bytes,2,rep,name=paths,proto3\" json:\"paths,omitempty\"`\n}\n\nfunc (x *ShareFilesViaPublicKeyRequest) Reset() {\n\t*x = ShareFilesViaPublicKeyRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[54]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ShareFilesViaPublicKeyRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShareFilesViaPublicKeyRequest) ProtoMessage() {}\n\nfunc (x *ShareFilesViaPublicKeyRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[54]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShareFilesViaPublicKeyRequest.ProtoReflect.Descriptor instead.\nfunc (*ShareFilesViaPublicKeyRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{54}\n}\n\nfunc (x *ShareFilesViaPublicKeyRequest) GetPublicKeys() []string {\n\tif x != nil {\n\t\treturn x.PublicKeys\n\t}\n\treturn nil\n}\n\nfunc (x *ShareFilesViaPublicKeyRequest) GetPaths() []*FullPath {\n\tif x != nil {\n\t\treturn x.Paths\n\t}\n\treturn nil\n}\n\ntype FullPath struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tDbId   string `protobuf:\"bytes,1,opt,name=dbId,proto3\" json:\"dbId,omitempty\"` // optional field to specify shared with me file\n\tBucket string `protobuf:\"bytes,2,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tPath   string `protobuf:\"bytes,3,opt,name=path,proto3\" json:\"path,omitempty\"`\n}\n\nfunc (x *FullPath) Reset() {\n\t*x = FullPath{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[55]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FullPath) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FullPath) ProtoMessage() {}\n\nfunc (x *FullPath) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[55]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FullPath.ProtoReflect.Descriptor instead.\nfunc (*FullPath) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{55}\n}\n\nfunc (x *FullPath) GetDbId() string {\n\tif x != nil {\n\t\treturn x.DbId\n\t}\n\treturn \"\"\n}\n\nfunc (x *FullPath) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *FullPath) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\ntype ShareFilesViaPublicKeyResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *ShareFilesViaPublicKeyResponse) Reset() {\n\t*x = ShareFilesViaPublicKeyResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[56]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ShareFilesViaPublicKeyResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShareFilesViaPublicKeyResponse) ProtoMessage() {}\n\nfunc (x *ShareFilesViaPublicKeyResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[56]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShareFilesViaPublicKeyResponse.ProtoReflect.Descriptor instead.\nfunc (*ShareFilesViaPublicKeyResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{56}\n}\n\ntype UnshareFilesViaPublicKeyRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPublicKeys []string    `protobuf:\"bytes,1,rep,name=publicKeys,proto3\" json:\"publicKeys,omitempty\"`\n\tPaths      []*FullPath `protobuf:\"bytes,2,rep,name=paths,proto3\" json:\"paths,omitempty\"`\n}\n\nfunc (x *UnshareFilesViaPublicKeyRequest) Reset() {\n\t*x = UnshareFilesViaPublicKeyRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[57]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *UnshareFilesViaPublicKeyRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UnshareFilesViaPublicKeyRequest) ProtoMessage() {}\n\nfunc (x *UnshareFilesViaPublicKeyRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[57]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UnshareFilesViaPublicKeyRequest.ProtoReflect.Descriptor instead.\nfunc (*UnshareFilesViaPublicKeyRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{57}\n}\n\nfunc (x *UnshareFilesViaPublicKeyRequest) GetPublicKeys() []string {\n\tif x != nil {\n\t\treturn x.PublicKeys\n\t}\n\treturn nil\n}\n\nfunc (x *UnshareFilesViaPublicKeyRequest) GetPaths() []*FullPath {\n\tif x != nil {\n\t\treturn x.Paths\n\t}\n\treturn nil\n}\n\ntype UnshareFilesViaPublicKeyResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *UnshareFilesViaPublicKeyResponse) Reset() {\n\t*x = UnshareFilesViaPublicKeyResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[58]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *UnshareFilesViaPublicKeyResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UnshareFilesViaPublicKeyResponse) ProtoMessage() {}\n\nfunc (x *UnshareFilesViaPublicKeyResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[58]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UnshareFilesViaPublicKeyResponse.ProtoReflect.Descriptor instead.\nfunc (*UnshareFilesViaPublicKeyResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{58}\n}\n\ntype GeneratePublicFileLinkRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBucket    string   `protobuf:\"bytes,1,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n\tItemPaths []string `protobuf:\"bytes,2,rep,name=itemPaths,proto3\" json:\"itemPaths,omitempty\"`\n\tPassword  string   `protobuf:\"bytes,3,opt,name=password,proto3\" json:\"password,omitempty\"`\n\t// optional field to specify db id\n\t// for shared with me files\n\tDbId string `protobuf:\"bytes,4,opt,name=dbId,proto3\" json:\"dbId,omitempty\"`\n}\n\nfunc (x *GeneratePublicFileLinkRequest) Reset() {\n\t*x = GeneratePublicFileLinkRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[59]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GeneratePublicFileLinkRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GeneratePublicFileLinkRequest) ProtoMessage() {}\n\nfunc (x *GeneratePublicFileLinkRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[59]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GeneratePublicFileLinkRequest.ProtoReflect.Descriptor instead.\nfunc (*GeneratePublicFileLinkRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{59}\n}\n\nfunc (x *GeneratePublicFileLinkRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\nfunc (x *GeneratePublicFileLinkRequest) GetItemPaths() []string {\n\tif x != nil {\n\t\treturn x.ItemPaths\n\t}\n\treturn nil\n}\n\nfunc (x *GeneratePublicFileLinkRequest) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\nfunc (x *GeneratePublicFileLinkRequest) GetDbId() string {\n\tif x != nil {\n\t\treturn x.DbId\n\t}\n\treturn \"\"\n}\n\ntype GeneratePublicFileLinkResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLink    string `protobuf:\"bytes,1,opt,name=link,proto3\" json:\"link,omitempty\"`\n\tFileCid string `protobuf:\"bytes,2,opt,name=fileCid,proto3\" json:\"fileCid,omitempty\"`\n}\n\nfunc (x *GeneratePublicFileLinkResponse) Reset() {\n\t*x = GeneratePublicFileLinkResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[60]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GeneratePublicFileLinkResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GeneratePublicFileLinkResponse) ProtoMessage() {}\n\nfunc (x *GeneratePublicFileLinkResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[60]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GeneratePublicFileLinkResponse.ProtoReflect.Descriptor instead.\nfunc (*GeneratePublicFileLinkResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{60}\n}\n\nfunc (x *GeneratePublicFileLinkResponse) GetLink() string {\n\tif x != nil {\n\t\treturn x.Link\n\t}\n\treturn \"\"\n}\n\nfunc (x *GeneratePublicFileLinkResponse) GetFileCid() string {\n\tif x != nil {\n\t\treturn x.FileCid\n\t}\n\treturn \"\"\n}\n\ntype ToggleFuseRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMountDrive bool `protobuf:\"varint,1,opt,name=mountDrive,proto3\" json:\"mountDrive,omitempty\"`\n}\n\nfunc (x *ToggleFuseRequest) Reset() {\n\t*x = ToggleFuseRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[61]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ToggleFuseRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ToggleFuseRequest) ProtoMessage() {}\n\nfunc (x *ToggleFuseRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[61]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ToggleFuseRequest.ProtoReflect.Descriptor instead.\nfunc (*ToggleFuseRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{61}\n}\n\nfunc (x *ToggleFuseRequest) GetMountDrive() bool {\n\tif x != nil {\n\t\treturn x.MountDrive\n\t}\n\treturn false\n}\n\ntype FuseDriveResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tState     FuseState `protobuf:\"varint,1,opt,name=state,proto3,enum=space.FuseState\" json:\"state,omitempty\"`\n\tMountPath string    `protobuf:\"bytes,2,opt,name=mountPath,proto3\" json:\"mountPath,omitempty\"`\n}\n\nfunc (x *FuseDriveResponse) Reset() {\n\t*x = FuseDriveResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[62]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *FuseDriveResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FuseDriveResponse) ProtoMessage() {}\n\nfunc (x *FuseDriveResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[62]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FuseDriveResponse.ProtoReflect.Descriptor instead.\nfunc (*FuseDriveResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{62}\n}\n\nfunc (x *FuseDriveResponse) GetState() FuseState {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn FuseState_UNSUPPORTED\n}\n\nfunc (x *FuseDriveResponse) GetMountPath() string {\n\tif x != nil {\n\t\treturn x.MountPath\n\t}\n\treturn \"\"\n}\n\ntype ListBucketsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *ListBucketsRequest) Reset() {\n\t*x = ListBucketsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[63]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListBucketsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListBucketsRequest) ProtoMessage() {}\n\nfunc (x *ListBucketsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[63]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListBucketsRequest.ProtoReflect.Descriptor instead.\nfunc (*ListBucketsRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{63}\n}\n\ntype ListBucketsResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tBuckets []*Bucket `protobuf:\"bytes,1,rep,name=buckets,proto3\" json:\"buckets,omitempty\"`\n}\n\nfunc (x *ListBucketsResponse) Reset() {\n\t*x = ListBucketsResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[64]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ListBucketsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListBucketsResponse) ProtoMessage() {}\n\nfunc (x *ListBucketsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[64]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListBucketsResponse.ProtoReflect.Descriptor instead.\nfunc (*ListBucketsResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{64}\n}\n\nfunc (x *ListBucketsResponse) GetBuckets() []*Bucket {\n\tif x != nil {\n\t\treturn x.Buckets\n\t}\n\treturn nil\n}\n\ntype Invitation struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInviterPublicKey string           `protobuf:\"bytes,1,opt,name=inviterPublicKey,proto3\" json:\"inviterPublicKey,omitempty\"`\n\tInvitationID     string           `protobuf:\"bytes,2,opt,name=invitationID,proto3\" json:\"invitationID,omitempty\"`\n\tStatus           InvitationStatus `protobuf:\"varint,4,opt,name=status,proto3,enum=space.InvitationStatus\" json:\"status,omitempty\"`\n\tItemPaths        []*FullPath      `protobuf:\"bytes,5,rep,name=itemPaths,proto3\" json:\"itemPaths,omitempty\"`\n}\n\nfunc (x *Invitation) Reset() {\n\t*x = Invitation{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[65]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Invitation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Invitation) ProtoMessage() {}\n\nfunc (x *Invitation) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[65]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Invitation.ProtoReflect.Descriptor instead.\nfunc (*Invitation) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{65}\n}\n\nfunc (x *Invitation) GetInviterPublicKey() string {\n\tif x != nil {\n\t\treturn x.InviterPublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *Invitation) GetInvitationID() string {\n\tif x != nil {\n\t\treturn x.InvitationID\n\t}\n\treturn \"\"\n}\n\nfunc (x *Invitation) GetStatus() InvitationStatus {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn InvitationStatus_PENDING\n}\n\nfunc (x *Invitation) GetItemPaths() []*FullPath {\n\tif x != nil {\n\t\treturn x.ItemPaths\n\t}\n\treturn nil\n}\n\ntype UsageAlert struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUsed    int64  `protobuf:\"varint,1,opt,name=used,proto3\" json:\"used,omitempty\"`\n\tLimit   int64  `protobuf:\"varint,2,opt,name=limit,proto3\" json:\"limit,omitempty\"`\n\tMessage string `protobuf:\"bytes,3,opt,name=message,proto3\" json:\"message,omitempty\"`\n}\n\nfunc (x *UsageAlert) Reset() {\n\t*x = UsageAlert{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[66]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *UsageAlert) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UsageAlert) ProtoMessage() {}\n\nfunc (x *UsageAlert) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[66]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UsageAlert.ProtoReflect.Descriptor instead.\nfunc (*UsageAlert) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{66}\n}\n\nfunc (x *UsageAlert) GetUsed() int64 {\n\tif x != nil {\n\t\treturn x.Used\n\t}\n\treturn 0\n}\n\nfunc (x *UsageAlert) GetLimit() int64 {\n\tif x != nil {\n\t\treturn x.Limit\n\t}\n\treturn 0\n}\n\nfunc (x *UsageAlert) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\ntype InvitationAccept struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInvitationID string `protobuf:\"bytes,2,opt,name=invitationID,proto3\" json:\"invitationID,omitempty\"`\n}\n\nfunc (x *InvitationAccept) Reset() {\n\t*x = InvitationAccept{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[67]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *InvitationAccept) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InvitationAccept) ProtoMessage() {}\n\nfunc (x *InvitationAccept) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[67]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InvitationAccept.ProtoReflect.Descriptor instead.\nfunc (*InvitationAccept) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{67}\n}\n\nfunc (x *InvitationAccept) GetInvitationID() string {\n\tif x != nil {\n\t\treturn x.InvitationID\n\t}\n\treturn \"\"\n}\n\ntype RevokedInvitation struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInviterPublicKey string      `protobuf:\"bytes,1,opt,name=inviterPublicKey,proto3\" json:\"inviterPublicKey,omitempty\"`\n\tItemPaths        []*FullPath `protobuf:\"bytes,5,rep,name=itemPaths,proto3\" json:\"itemPaths,omitempty\"`\n}\n\nfunc (x *RevokedInvitation) Reset() {\n\t*x = RevokedInvitation{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[68]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RevokedInvitation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RevokedInvitation) ProtoMessage() {}\n\nfunc (x *RevokedInvitation) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[68]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RevokedInvitation.ProtoReflect.Descriptor instead.\nfunc (*RevokedInvitation) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{68}\n}\n\nfunc (x *RevokedInvitation) GetInviterPublicKey() string {\n\tif x != nil {\n\t\treturn x.InviterPublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *RevokedInvitation) GetItemPaths() []*FullPath {\n\tif x != nil {\n\t\treturn x.ItemPaths\n\t}\n\treturn nil\n}\n\ntype Notification struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tID      string `protobuf:\"bytes,1,opt,name=ID,proto3\" json:\"ID,omitempty\"` // underlying message id from textile\n\tSubject string `protobuf:\"bytes,2,opt,name=subject,proto3\" json:\"subject,omitempty\"`\n\tBody    string `protobuf:\"bytes,3,opt,name=body,proto3\" json:\"body,omitempty\"`\n\t// Types that are assignable to RelatedObject:\n\t//\t*Notification_InvitationValue\n\t//\t*Notification_UsageAlert\n\t//\t*Notification_InvitationAccept\n\t//\t*Notification_RevokedInvitation\n\tRelatedObject isNotification_RelatedObject `protobuf_oneof:\"relatedObject\"`\n\tType          NotificationType             `protobuf:\"varint,8,opt,name=type,proto3,enum=space.NotificationType\" json:\"type,omitempty\"`\n\tCreatedAt     int64                        `protobuf:\"varint,9,opt,name=createdAt,proto3\" json:\"createdAt,omitempty\"`\n\tReadAt        int64                        `protobuf:\"varint,10,opt,name=readAt,proto3\" json:\"readAt,omitempty\"`\n}\n\nfunc (x *Notification) Reset() {\n\t*x = Notification{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[69]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Notification) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Notification) ProtoMessage() {}\n\nfunc (x *Notification) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[69]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Notification.ProtoReflect.Descriptor instead.\nfunc (*Notification) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{69}\n}\n\nfunc (x *Notification) GetID() string {\n\tif x != nil {\n\t\treturn x.ID\n\t}\n\treturn \"\"\n}\n\nfunc (x *Notification) GetSubject() string {\n\tif x != nil {\n\t\treturn x.Subject\n\t}\n\treturn \"\"\n}\n\nfunc (x *Notification) GetBody() string {\n\tif x != nil {\n\t\treturn x.Body\n\t}\n\treturn \"\"\n}\n\nfunc (m *Notification) GetRelatedObject() isNotification_RelatedObject {\n\tif m != nil {\n\t\treturn m.RelatedObject\n\t}\n\treturn nil\n}\n\nfunc (x *Notification) GetInvitationValue() *Invitation {\n\tif x, ok := x.GetRelatedObject().(*Notification_InvitationValue); ok {\n\t\treturn x.InvitationValue\n\t}\n\treturn nil\n}\n\nfunc (x *Notification) GetUsageAlert() *UsageAlert {\n\tif x, ok := x.GetRelatedObject().(*Notification_UsageAlert); ok {\n\t\treturn x.UsageAlert\n\t}\n\treturn nil\n}\n\nfunc (x *Notification) GetInvitationAccept() *InvitationAccept {\n\tif x, ok := x.GetRelatedObject().(*Notification_InvitationAccept); ok {\n\t\treturn x.InvitationAccept\n\t}\n\treturn nil\n}\n\nfunc (x *Notification) GetRevokedInvitation() *RevokedInvitation {\n\tif x, ok := x.GetRelatedObject().(*Notification_RevokedInvitation); ok {\n\t\treturn x.RevokedInvitation\n\t}\n\treturn nil\n}\n\nfunc (x *Notification) GetType() NotificationType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn NotificationType_UNKNOWN\n}\n\nfunc (x *Notification) GetCreatedAt() int64 {\n\tif x != nil {\n\t\treturn x.CreatedAt\n\t}\n\treturn 0\n}\n\nfunc (x *Notification) GetReadAt() int64 {\n\tif x != nil {\n\t\treturn x.ReadAt\n\t}\n\treturn 0\n}\n\ntype isNotification_RelatedObject interface {\n\tisNotification_RelatedObject()\n}\n\ntype Notification_InvitationValue struct {\n\tInvitationValue *Invitation `protobuf:\"bytes,4,opt,name=invitationValue,proto3,oneof\"`\n}\n\ntype Notification_UsageAlert struct {\n\tUsageAlert *UsageAlert `protobuf:\"bytes,5,opt,name=usageAlert,proto3,oneof\"`\n}\n\ntype Notification_InvitationAccept struct {\n\tInvitationAccept *InvitationAccept `protobuf:\"bytes,6,opt,name=invitationAccept,proto3,oneof\"`\n}\n\ntype Notification_RevokedInvitation struct {\n\tRevokedInvitation *RevokedInvitation `protobuf:\"bytes,7,opt,name=revokedInvitation,proto3,oneof\"`\n}\n\nfunc (*Notification_InvitationValue) isNotification_RelatedObject() {}\n\nfunc (*Notification_UsageAlert) isNotification_RelatedObject() {}\n\nfunc (*Notification_InvitationAccept) isNotification_RelatedObject() {}\n\nfunc (*Notification_RevokedInvitation) isNotification_RelatedObject() {}\n\ntype HandleFilesInvitationRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tInvitationID string `protobuf:\"bytes,1,opt,name=invitationID,proto3\" json:\"invitationID,omitempty\"`\n\tAccept       bool   `protobuf:\"varint,2,opt,name=accept,proto3\" json:\"accept,omitempty\"`\n}\n\nfunc (x *HandleFilesInvitationRequest) Reset() {\n\t*x = HandleFilesInvitationRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[70]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *HandleFilesInvitationRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HandleFilesInvitationRequest) ProtoMessage() {}\n\nfunc (x *HandleFilesInvitationRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[70]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HandleFilesInvitationRequest.ProtoReflect.Descriptor instead.\nfunc (*HandleFilesInvitationRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{70}\n}\n\nfunc (x *HandleFilesInvitationRequest) GetInvitationID() string {\n\tif x != nil {\n\t\treturn x.InvitationID\n\t}\n\treturn \"\"\n}\n\nfunc (x *HandleFilesInvitationRequest) GetAccept() bool {\n\tif x != nil {\n\t\treturn x.Accept\n\t}\n\treturn false\n}\n\ntype HandleFilesInvitationResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *HandleFilesInvitationResponse) Reset() {\n\t*x = HandleFilesInvitationResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[71]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *HandleFilesInvitationResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HandleFilesInvitationResponse) ProtoMessage() {}\n\nfunc (x *HandleFilesInvitationResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[71]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HandleFilesInvitationResponse.ProtoReflect.Descriptor instead.\nfunc (*HandleFilesInvitationResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{71}\n}\n\ntype NotificationEventResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tNotification *Notification `protobuf:\"bytes,1,opt,name=notification,proto3\" json:\"notification,omitempty\"`\n}\n\nfunc (x *NotificationEventResponse) Reset() {\n\t*x = NotificationEventResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[72]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *NotificationEventResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NotificationEventResponse) ProtoMessage() {}\n\nfunc (x *NotificationEventResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[72]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NotificationEventResponse.ProtoReflect.Descriptor instead.\nfunc (*NotificationEventResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{72}\n}\n\nfunc (x *NotificationEventResponse) GetNotification() *Notification {\n\tif x != nil {\n\t\treturn x.Notification\n\t}\n\treturn nil\n}\n\ntype GetNotificationsRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSeek  string `protobuf:\"bytes,1,opt,name=seek,proto3\" json:\"seek,omitempty\"`\n\tLimit int64  `protobuf:\"varint,2,opt,name=limit,proto3\" json:\"limit,omitempty\"`\n}\n\nfunc (x *GetNotificationsRequest) Reset() {\n\t*x = GetNotificationsRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[73]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetNotificationsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetNotificationsRequest) ProtoMessage() {}\n\nfunc (x *GetNotificationsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[73]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetNotificationsRequest.ProtoReflect.Descriptor instead.\nfunc (*GetNotificationsRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{73}\n}\n\nfunc (x *GetNotificationsRequest) GetSeek() string {\n\tif x != nil {\n\t\treturn x.Seek\n\t}\n\treturn \"\"\n}\n\nfunc (x *GetNotificationsRequest) GetLimit() int64 {\n\tif x != nil {\n\t\treturn x.Limit\n\t}\n\treturn 0\n}\n\ntype GetNotificationsResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tNotifications []*Notification `protobuf:\"bytes,1,rep,name=notifications,proto3\" json:\"notifications,omitempty\"`\n\tNextOffset    string          `protobuf:\"bytes,2,opt,name=nextOffset,proto3\" json:\"nextOffset,omitempty\"`\n\tLastSeenAt    int64           `protobuf:\"varint,3,opt,name=lastSeenAt,proto3\" json:\"lastSeenAt,omitempty\"`\n}\n\nfunc (x *GetNotificationsResponse) Reset() {\n\t*x = GetNotificationsResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[74]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetNotificationsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetNotificationsResponse) ProtoMessage() {}\n\nfunc (x *GetNotificationsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[74]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetNotificationsResponse.ProtoReflect.Descriptor instead.\nfunc (*GetNotificationsResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{74}\n}\n\nfunc (x *GetNotificationsResponse) GetNotifications() []*Notification {\n\tif x != nil {\n\t\treturn x.Notifications\n\t}\n\treturn nil\n}\n\nfunc (x *GetNotificationsResponse) GetNextOffset() string {\n\tif x != nil {\n\t\treturn x.NextOffset\n\t}\n\treturn \"\"\n}\n\nfunc (x *GetNotificationsResponse) GetLastSeenAt() int64 {\n\tif x != nil {\n\t\treturn x.LastSeenAt\n\t}\n\treturn 0\n}\n\ntype ReadNotificationRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tID string `protobuf:\"bytes,1,opt,name=ID,proto3\" json:\"ID,omitempty\"`\n}\n\nfunc (x *ReadNotificationRequest) Reset() {\n\t*x = ReadNotificationRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[75]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ReadNotificationRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadNotificationRequest) ProtoMessage() {}\n\nfunc (x *ReadNotificationRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[75]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReadNotificationRequest.ProtoReflect.Descriptor instead.\nfunc (*ReadNotificationRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{75}\n}\n\nfunc (x *ReadNotificationRequest) GetID() string {\n\tif x != nil {\n\t\treturn x.ID\n\t}\n\treturn \"\"\n}\n\ntype ReadNotificationResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *ReadNotificationResponse) Reset() {\n\t*x = ReadNotificationResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[76]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ReadNotificationResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadNotificationResponse) ProtoMessage() {}\n\nfunc (x *ReadNotificationResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[76]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReadNotificationResponse.ProtoReflect.Descriptor instead.\nfunc (*ReadNotificationResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{76}\n}\n\ntype GetPublicKeyRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *GetPublicKeyRequest) Reset() {\n\t*x = GetPublicKeyRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[77]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetPublicKeyRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetPublicKeyRequest) ProtoMessage() {}\n\nfunc (x *GetPublicKeyRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[77]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetPublicKeyRequest.ProtoReflect.Descriptor instead.\nfunc (*GetPublicKeyRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{77}\n}\n\ntype GetPublicKeyResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Public key encoded in hex\n\tPublicKey string `protobuf:\"bytes,1,opt,name=publicKey,proto3\" json:\"publicKey,omitempty\"`\n}\n\nfunc (x *GetPublicKeyResponse) Reset() {\n\t*x = GetPublicKeyResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[78]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetPublicKeyResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetPublicKeyResponse) ProtoMessage() {}\n\nfunc (x *GetPublicKeyResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[78]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetPublicKeyResponse.ProtoReflect.Descriptor instead.\nfunc (*GetPublicKeyResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{78}\n}\n\nfunc (x *GetPublicKeyResponse) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\ntype RecoverKeysByLocalBackupRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPathToKeyBackup string `protobuf:\"bytes,1,opt,name=pathToKeyBackup,proto3\" json:\"pathToKeyBackup,omitempty\"`\n}\n\nfunc (x *RecoverKeysByLocalBackupRequest) Reset() {\n\t*x = RecoverKeysByLocalBackupRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[79]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RecoverKeysByLocalBackupRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RecoverKeysByLocalBackupRequest) ProtoMessage() {}\n\nfunc (x *RecoverKeysByLocalBackupRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[79]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RecoverKeysByLocalBackupRequest.ProtoReflect.Descriptor instead.\nfunc (*RecoverKeysByLocalBackupRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{79}\n}\n\nfunc (x *RecoverKeysByLocalBackupRequest) GetPathToKeyBackup() string {\n\tif x != nil {\n\t\treturn x.PathToKeyBackup\n\t}\n\treturn \"\"\n}\n\ntype RecoverKeysByLocalBackupResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RecoverKeysByLocalBackupResponse) Reset() {\n\t*x = RecoverKeysByLocalBackupResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[80]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RecoverKeysByLocalBackupResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RecoverKeysByLocalBackupResponse) ProtoMessage() {}\n\nfunc (x *RecoverKeysByLocalBackupResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[80]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RecoverKeysByLocalBackupResponse.ProtoReflect.Descriptor instead.\nfunc (*RecoverKeysByLocalBackupResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{80}\n}\n\ntype CreateLocalKeysBackupRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The path in which to save the backup\n\tPathToKeyBackup string `protobuf:\"bytes,1,opt,name=pathToKeyBackup,proto3\" json:\"pathToKeyBackup,omitempty\"`\n}\n\nfunc (x *CreateLocalKeysBackupRequest) Reset() {\n\t*x = CreateLocalKeysBackupRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[81]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateLocalKeysBackupRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateLocalKeysBackupRequest) ProtoMessage() {}\n\nfunc (x *CreateLocalKeysBackupRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[81]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateLocalKeysBackupRequest.ProtoReflect.Descriptor instead.\nfunc (*CreateLocalKeysBackupRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{81}\n}\n\nfunc (x *CreateLocalKeysBackupRequest) GetPathToKeyBackup() string {\n\tif x != nil {\n\t\treturn x.PathToKeyBackup\n\t}\n\treturn \"\"\n}\n\ntype CreateLocalKeysBackupResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *CreateLocalKeysBackupResponse) Reset() {\n\t*x = CreateLocalKeysBackupResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[82]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateLocalKeysBackupResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateLocalKeysBackupResponse) ProtoMessage() {}\n\nfunc (x *CreateLocalKeysBackupResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[82]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateLocalKeysBackupResponse.ProtoReflect.Descriptor instead.\nfunc (*CreateLocalKeysBackupResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{82}\n}\n\ntype DeleteAccountRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *DeleteAccountRequest) Reset() {\n\t*x = DeleteAccountRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[83]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DeleteAccountRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DeleteAccountRequest) ProtoMessage() {}\n\nfunc (x *DeleteAccountRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[83]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DeleteAccountRequest.ProtoReflect.Descriptor instead.\nfunc (*DeleteAccountRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{83}\n}\n\ntype DeleteAccountResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *DeleteAccountResponse) Reset() {\n\t*x = DeleteAccountResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[84]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DeleteAccountResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DeleteAccountResponse) ProtoMessage() {}\n\nfunc (x *DeleteAccountResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[84]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DeleteAccountResponse.ProtoReflect.Descriptor instead.\nfunc (*DeleteAccountResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{84}\n}\n\ntype DeleteKeyPairRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *DeleteKeyPairRequest) Reset() {\n\t*x = DeleteKeyPairRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[85]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DeleteKeyPairRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DeleteKeyPairRequest) ProtoMessage() {}\n\nfunc (x *DeleteKeyPairRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[85]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DeleteKeyPairRequest.ProtoReflect.Descriptor instead.\nfunc (*DeleteKeyPairRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{85}\n}\n\ntype DeleteKeyPairResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *DeleteKeyPairResponse) Reset() {\n\t*x = DeleteKeyPairResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[86]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *DeleteKeyPairResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DeleteKeyPairResponse) ProtoMessage() {}\n\nfunc (x *DeleteKeyPairResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[86]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DeleteKeyPairResponse.ProtoReflect.Descriptor instead.\nfunc (*DeleteKeyPairResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{86}\n}\n\ntype GetAPISessionTokensRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *GetAPISessionTokensRequest) Reset() {\n\t*x = GetAPISessionTokensRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[87]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetAPISessionTokensRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetAPISessionTokensRequest) ProtoMessage() {}\n\nfunc (x *GetAPISessionTokensRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[87]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetAPISessionTokensRequest.ProtoReflect.Descriptor instead.\nfunc (*GetAPISessionTokensRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{87}\n}\n\ntype GetAPISessionTokensResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tHubToken      string `protobuf:\"bytes,1,opt,name=hubToken,proto3\" json:\"hubToken,omitempty\"`\n\tServicesToken string `protobuf:\"bytes,2,opt,name=servicesToken,proto3\" json:\"servicesToken,omitempty\"`\n}\n\nfunc (x *GetAPISessionTokensResponse) Reset() {\n\t*x = GetAPISessionTokensResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[88]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetAPISessionTokensResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetAPISessionTokensResponse) ProtoMessage() {}\n\nfunc (x *GetAPISessionTokensResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[88]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetAPISessionTokensResponse.ProtoReflect.Descriptor instead.\nfunc (*GetAPISessionTokensResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{88}\n}\n\nfunc (x *GetAPISessionTokensResponse) GetHubToken() string {\n\tif x != nil {\n\t\treturn x.HubToken\n\t}\n\treturn \"\"\n}\n\nfunc (x *GetAPISessionTokensResponse) GetServicesToken() string {\n\tif x != nil {\n\t\treturn x.ServicesToken\n\t}\n\treturn \"\"\n}\n\ntype GetRecentlySharedWithRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *GetRecentlySharedWithRequest) Reset() {\n\t*x = GetRecentlySharedWithRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[89]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetRecentlySharedWithRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetRecentlySharedWithRequest) ProtoMessage() {}\n\nfunc (x *GetRecentlySharedWithRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[89]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetRecentlySharedWithRequest.ProtoReflect.Descriptor instead.\nfunc (*GetRecentlySharedWithRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{89}\n}\n\ntype GetRecentlySharedWithResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMembers []*FileMember `protobuf:\"bytes,1,rep,name=members,proto3\" json:\"members,omitempty\"`\n}\n\nfunc (x *GetRecentlySharedWithResponse) Reset() {\n\t*x = GetRecentlySharedWithResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[90]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GetRecentlySharedWithResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GetRecentlySharedWithResponse) ProtoMessage() {}\n\nfunc (x *GetRecentlySharedWithResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[90]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GetRecentlySharedWithResponse.ProtoReflect.Descriptor instead.\nfunc (*GetRecentlySharedWithResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{90}\n}\n\nfunc (x *GetRecentlySharedWithResponse) GetMembers() []*FileMember {\n\tif x != nil {\n\t\treturn x.Members\n\t}\n\treturn nil\n}\n\ntype InitializeMasterAppTokenRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *InitializeMasterAppTokenRequest) Reset() {\n\t*x = InitializeMasterAppTokenRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[91]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *InitializeMasterAppTokenRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InitializeMasterAppTokenRequest) ProtoMessage() {}\n\nfunc (x *InitializeMasterAppTokenRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[91]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InitializeMasterAppTokenRequest.ProtoReflect.Descriptor instead.\nfunc (*InitializeMasterAppTokenRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{91}\n}\n\ntype InitializeMasterAppTokenResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAppToken string `protobuf:\"bytes,1,opt,name=appToken,proto3\" json:\"appToken,omitempty\"`\n}\n\nfunc (x *InitializeMasterAppTokenResponse) Reset() {\n\t*x = InitializeMasterAppTokenResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[92]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *InitializeMasterAppTokenResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InitializeMasterAppTokenResponse) ProtoMessage() {}\n\nfunc (x *InitializeMasterAppTokenResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[92]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InitializeMasterAppTokenResponse.ProtoReflect.Descriptor instead.\nfunc (*InitializeMasterAppTokenResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{92}\n}\n\nfunc (x *InitializeMasterAppTokenResponse) GetAppToken() string {\n\tif x != nil {\n\t\treturn x.AppToken\n\t}\n\treturn \"\"\n}\n\ntype AllowedMethod struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMethodName string `protobuf:\"bytes,1,opt,name=methodName,proto3\" json:\"methodName,omitempty\"`\n}\n\nfunc (x *AllowedMethod) Reset() {\n\t*x = AllowedMethod{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[93]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AllowedMethod) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AllowedMethod) ProtoMessage() {}\n\nfunc (x *AllowedMethod) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[93]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AllowedMethod.ProtoReflect.Descriptor instead.\nfunc (*AllowedMethod) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{93}\n}\n\nfunc (x *AllowedMethod) GetMethodName() string {\n\tif x != nil {\n\t\treturn x.MethodName\n\t}\n\treturn \"\"\n}\n\ntype GenerateAppTokenRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAllowedMethods []*AllowedMethod `protobuf:\"bytes,1,rep,name=allowedMethods,proto3\" json:\"allowedMethods,omitempty\"`\n}\n\nfunc (x *GenerateAppTokenRequest) Reset() {\n\t*x = GenerateAppTokenRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[94]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GenerateAppTokenRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateAppTokenRequest) ProtoMessage() {}\n\nfunc (x *GenerateAppTokenRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[94]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateAppTokenRequest.ProtoReflect.Descriptor instead.\nfunc (*GenerateAppTokenRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{94}\n}\n\nfunc (x *GenerateAppTokenRequest) GetAllowedMethods() []*AllowedMethod {\n\tif x != nil {\n\t\treturn x.AllowedMethods\n\t}\n\treturn nil\n}\n\ntype GenerateAppTokenResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tAppToken string `protobuf:\"bytes,1,opt,name=appToken,proto3\" json:\"appToken,omitempty\"`\n}\n\nfunc (x *GenerateAppTokenResponse) Reset() {\n\t*x = GenerateAppTokenResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[95]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GenerateAppTokenResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateAppTokenResponse) ProtoMessage() {}\n\nfunc (x *GenerateAppTokenResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[95]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateAppTokenResponse.ProtoReflect.Descriptor instead.\nfunc (*GenerateAppTokenResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{95}\n}\n\nfunc (x *GenerateAppTokenResponse) GetAppToken() string {\n\tif x != nil {\n\t\treturn x.AppToken\n\t}\n\treturn \"\"\n}\n\ntype RemoveDirOrFileRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tPath   string `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tBucket string `protobuf:\"bytes,2,opt,name=bucket,proto3\" json:\"bucket,omitempty\"`\n}\n\nfunc (x *RemoveDirOrFileRequest) Reset() {\n\t*x = RemoveDirOrFileRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[96]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveDirOrFileRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveDirOrFileRequest) ProtoMessage() {}\n\nfunc (x *RemoveDirOrFileRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[96]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveDirOrFileRequest.ProtoReflect.Descriptor instead.\nfunc (*RemoveDirOrFileRequest) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{96}\n}\n\nfunc (x *RemoveDirOrFileRequest) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\nfunc (x *RemoveDirOrFileRequest) GetBucket() string {\n\tif x != nil {\n\t\treturn x.Bucket\n\t}\n\treturn \"\"\n}\n\ntype RemoveDirOrFileResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *RemoveDirOrFileResponse) Reset() {\n\t*x = RemoveDirOrFileResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_space_proto_msgTypes[97]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RemoveDirOrFileResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RemoveDirOrFileResponse) ProtoMessage() {}\n\nfunc (x *RemoveDirOrFileResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_space_proto_msgTypes[97]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RemoveDirOrFileResponse.ProtoReflect.Descriptor instead.\nfunc (*RemoveDirOrFileResponse) Descriptor() ([]byte, []int) {\n\treturn file_space_proto_rawDescGZIP(), []int{97}\n}\n\nvar File_space_proto protoreflect.FileDescriptor\n\nvar file_space_proto_rawDesc = []byte{\n\t0x0a, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e,\n\t0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,\n\t0x2a, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x67, 0x0a, 0x13, 0x53,\n\t0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x61, 0x72,\n\t0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79,\n\t0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x14,\n\t0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71,\n\t0x75, 0x65, 0x72, 0x79, 0x22, 0x78, 0x0a, 0x19, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69,\n\t0x6c, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72,\n\t0x79, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72,\n\t0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74,\n\t0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x04, 0x64, 0x62, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x41,\n\t0x0a, 0x21, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x41, 0x74, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,\n\t0x70, 0x22, 0x24, 0x0a, 0x22, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x41, 0x74, 0x52,\n\t0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x53, 0x68,\n\t0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69,\n\t0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74,\n\t0x22, 0x75, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74,\n\t0x68, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x12, 0x35, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4c, 0x69,\n\t0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79,\n\t0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x4f,\n\t0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x65, 0x78,\n\t0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x45, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x68,\n\t0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69,\n\t0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x73,\n\t0x0a, 0x1a, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x4d, 0x65, 0x46,\n\t0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x05,\n\t0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x70,\n\t0x61, 0x63, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69,\n\t0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x69, 0x74,\n\t0x65, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65,\n\t0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x4f, 0x66, 0x66,\n\t0x73, 0x65, 0x74, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x49,\n\t0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xee, 0x01, 0x0a, 0x14, 0x47,\n\t0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,\n\t0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x72,\n\t0x6f, 0x67, 0x65, 0x55, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c,\n\t0x6f, 0x63, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x72, 0x6f, 0x67, 0x65, 0x55, 0x73, 0x65, 0x64, 0x12,\n\t0x2e, 0x0a, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74,\n\t0x68, 0x55, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x6c, 0x6f, 0x63,\n\t0x61, 0x6c, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x73, 0x65, 0x64, 0x12,\n\t0x2a, 0x0a, 0x10, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x55,\n\t0x73, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x55, 0x73, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x73, 0x65,\n\t0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x61,\n\t0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x75,\n\t0x73, 0x61, 0x67, 0x65, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52,\n\t0x0a, 0x75, 0x73, 0x61, 0x67, 0x65, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x22, 0x4b, 0x0a, 0x19, 0x54,\n\t0x6f, 0x67, 0x67, 0x6c, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75,\n\t0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74,\n\t0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x1c, 0x0a, 0x1a, 0x54, 0x6f, 0x67, 0x67,\n\t0x6c, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x1a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74,\n\t0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x1d, 0x0a, 0x1b,\n\t0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x74,\n\t0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x16, 0x4c,\n\t0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x20, 0x0a,\n\t0x0b, 0x6f, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x0b, 0x6f, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22,\n\t0x44, 0x0a, 0x0a, 0x46, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a,\n\t0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61,\n\t0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,\n\t0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xcb, 0x03, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69,\n\t0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04,\n\t0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68,\n\t0x12, 0x14, 0x0a, 0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x05, 0x69, 0x73, 0x44, 0x69, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x69,\n\t0x7a, 0x65, 0x49, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x0b, 0x73, 0x69, 0x7a, 0x65, 0x49, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07,\n\t0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63,\n\t0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,\n\t0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,\n\t0x12, 0x24, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,\n\t0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74,\n\t0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x66, 0x73, 0x48, 0x61,\n\t0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x70, 0x66, 0x73, 0x48, 0x61,\n\t0x73, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x41,\n\t0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12,\n\t0x69, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62,\n\t0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x43, 0x6f, 0x75, 0x6e,\n\t0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x43,\n\t0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18,\n\t0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x46, 0x69,\n\t0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72,\n\t0x73, 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x73, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x50,\n\t0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69,\n\t0x73, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,\n\t0x73, 0x12, 0x30, 0x0a, 0x13, 0x69, 0x73, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e,\n\t0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13,\n\t0x69, 0x73, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72,\n\t0x65, 0x73, 0x73, 0x22, 0xb7, 0x01, 0x0a, 0x18, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4c, 0x69,\n\t0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79,\n\t0x12, 0x2f, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65,\n\t0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72,\n\t0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x04, 0x64, 0x62, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x22, 0x0a,\n\t0x0c, 0x69, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20,\n\t0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4c, 0x69, 0x6e,\n\t0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x18, 0x05, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x22, 0x4e, 0x0a,\n\t0x17, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72,\n\t0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63,\n\t0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45,\n\t0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x64, 0x0a,\n\t0x14, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6f, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x6d, 0x62,\n\t0x65, 0x72, 0x73, 0x22, 0x4c, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63,\n\t0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07,\n\t0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74,\n\t0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65,\n\t0x73, 0x22, 0x29, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x22, 0x7e, 0x0a, 0x0c,\n\t0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07,\n\t0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61,\n\t0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69,\n\t0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x73, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x1c,\n\t0x0a, 0x09, 0x68, 0x61, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x09, 0x68, 0x61, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x22, 0xa3, 0x02, 0x0a,\n\t0x06, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,\n\t0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,\n\t0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,\n\t0x68, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04,\n\t0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12,\n\t0x1c, 0x0a, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x05, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2d, 0x0a,\n\t0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x65, 0x6d,\n\t0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10,\n\t0x69, 0x73, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74,\n\t0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e,\n\t0x61, 0x6c, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x73, 0x42, 0x61,\n\t0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x0f, 0x69, 0x73, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x61, 0x62, 0x6c,\n\t0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,\n\t0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x43, 0x6f, 0x75,\n\t0x6e, 0x74, 0x22, 0x3d, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x62, 0x75,\n\t0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x70, 0x61,\n\t0x63, 0x65, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x22, 0x18, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79,\n\t0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x35, 0x0a, 0x17, 0x47,\n\t0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e,\n\t0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e,\n\t0x69, 0x63, 0x22, 0x1a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x4d,\n\t0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x37,\n\t0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x4d, 0x6e, 0x65, 0x6d, 0x6f,\n\t0x6e, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d,\n\t0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d,\n\t0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x22, 0x3e, 0x0a, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6f,\n\t0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x56, 0x69, 0x61, 0x4d, 0x6e, 0x65, 0x6d,\n\t0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d,\n\t0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d,\n\t0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x22, 0x23, 0x0a, 0x21, 0x52, 0x65, 0x73, 0x74, 0x6f,\n\t0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x56, 0x69, 0x61, 0x4d, 0x6e, 0x65, 0x6d,\n\t0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x96, 0x01, 0x0a,\n\t0x11, 0x46, 0x69, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x12, 0x24, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,\n\t0x32, 0x10, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79,\n\t0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72,\n\t0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e,\n\t0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74,\n\t0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x04, 0x64, 0x62, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x14, 0x54, 0x65, 0x78, 0x74, 0x69, 0x6c, 0x65,\n\t0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a,\n\t0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62,\n\t0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x51, 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x46, 0x69, 0x6c,\n\t0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06,\n\t0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75,\n\t0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x64, 0x62, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e,\n\t0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08,\n\t0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,\n\t0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x69, 0x0a, 0x15, 0x4f, 0x70, 0x65, 0x6e,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70,\n\t0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,\n\t0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e,\n\t0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e,\n\t0x61, 0x6d, 0x65, 0x22, 0x34, 0x0a, 0x16, 0x4f, 0x70, 0x65, 0x6e, 0x50, 0x75, 0x62, 0x6c, 0x69,\n\t0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a,\n\t0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6b, 0x0a, 0x0f, 0x41, 0x64, 0x64,\n\t0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b,\n\t0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1e,\n\t0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16,\n\t0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,\n\t0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x65, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65,\n\t0x6d, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63,\n\t0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75,\n\t0x72, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xd0, 0x01,\n\t0x0a, 0x10, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x74,\n\t0x65, 0x6d, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,\n\t0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x73,\n\t0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73,\n\t0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c,\n\t0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65,\n\t0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70,\n\t0x6c, 0x65, 0x74, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,\n\t0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73,\n\t0x22, 0x41, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x62,\n\t0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x6c,\n\t0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7d, 0x0a, 0x1d, 0x42,\n\t0x61, 0x63, 0x6b, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70,\n\t0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,\n\t0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64,\n\t0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65,\n\t0x12, 0x28, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,\n\t0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x42, 0x61,\n\t0x63, 0x6b, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68,\n\t0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7e, 0x0a, 0x1e,\n\t0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73,\n\t0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,\n\t0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75,\n\t0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61,\n\t0x73, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e,\n\t0x32, 0x14, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x63, 0x6b,\n\t0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x21, 0x0a, 0x1f,\n\t0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73,\n\t0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,\n\t0x4f, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x50, 0x61, 0x73, 0x73, 0x70,\n\t0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,\n\t0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64,\n\t0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65,\n\t0x22, 0x1c, 0x0a, 0x1a, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x50, 0x61, 0x73, 0x73,\n\t0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c,\n\t0x0a, 0x0a, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09,\n\t0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,\n\t0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,\n\t0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x2c, 0x0a, 0x12,\n\t0x53, 0x68, 0x61, 0x72, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x48, 0x0a, 0x13, 0x53, 0x68,\n\t0x61, 0x72, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x12, 0x31, 0x0a, 0x0a, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x66, 0x6f, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x54, 0x68,\n\t0x72, 0x65, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64,\n\t0x69, 0x6e, 0x66, 0x6f, 0x22, 0x5e, 0x0a, 0x11, 0x4a, 0x6f, 0x69, 0x6e, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x0a, 0x74, 0x68, 0x72,\n\t0x65, 0x61, 0x64, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f,\n\t0x52, 0x0a, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06,\n\t0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75,\n\t0x63, 0x6b, 0x65, 0x74, 0x22, 0x2c, 0x0a, 0x12, 0x4a, 0x6f, 0x69, 0x6e, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65,\n\t0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75,\n\t0x6c, 0x74, 0x22, 0x66, 0x0a, 0x1d, 0x53, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73,\n\t0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,\n\t0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,\n\t0x65, 0x79, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03,\n\t0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x50,\n\t0x61, 0x74, 0x68, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x22, 0x4a, 0x0a, 0x08, 0x46, 0x75,\n\t0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x64, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x62, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75,\n\t0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x46,\n\t0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x68, 0x0a, 0x1f, 0x55, 0x6e, 0x73, 0x68,\n\t0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69,\n\t0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x70,\n\t0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,\n\t0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x70,\n\t0x61, 0x74, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x70, 0x61,\n\t0x63, 0x65, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x52, 0x05, 0x70, 0x61, 0x74,\n\t0x68, 0x73, 0x22, 0x22, 0x0a, 0x20, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c,\n\t0x65, 0x73, 0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x6e, 0x65, 0x72,\n\t0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x6e,\n\t0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74,\n\t0x12, 0x1c, 0x0a, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x18, 0x02, 0x20,\n\t0x03, 0x28, 0x09, 0x52, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1a,\n\t0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62,\n\t0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x62, 0x49, 0x64, 0x22, 0x4e,\n\t0x0a, 0x1e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,\n\t0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x69, 0x64, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x69, 0x64, 0x22, 0x33,\n\t0x0a, 0x11, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x46, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x72, 0x69, 0x76,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x44, 0x72,\n\t0x69, 0x76, 0x65, 0x22, 0x59, 0x0a, 0x11, 0x46, 0x75, 0x73, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e,\n\t0x46, 0x75, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,\n\t0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x22, 0x14,\n\t0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x07, 0x62,\n\t0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x07, 0x62, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x50, 0x75,\n\t0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69,\n\t0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12,\n\t0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x49, 0x44, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20,\n\t0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x69,\n\t0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,\n\t0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x74, 0x68,\n\t0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e,\n\t0x46, 0x75, 0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x52, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x50, 0x61,\n\t0x74, 0x68, 0x73, 0x22, 0x50, 0x0a, 0x0a, 0x55, 0x73, 0x61, 0x67, 0x65, 0x41, 0x6c, 0x65, 0x72,\n\t0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,\n\t0x04, 0x75, 0x73, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d,\n\t0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,\n\t0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x36, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x76,\n\t0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x0c, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x6e, 0x0a,\n\t0x11, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x50, 0x75, 0x62,\n\t0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e,\n\t0x76, 0x69, 0x74, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2d,\n\t0x0a, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x50, 0x61,\n\t0x74, 0x68, 0x52, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0xc5, 0x03,\n\t0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e,\n\t0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x18,\n\t0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3d, 0x0a, 0x0f,\n\t0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18,\n\t0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x49, 0x6e,\n\t0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x69,\n\t0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x75,\n\t0x73, 0x61, 0x67, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x41, 0x6c, 0x65,\n\t0x72, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x75, 0x73, 0x61, 0x67, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74,\n\t0x12, 0x45, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63,\n\t0x63, 0x65, 0x70, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x61,\n\t0x63, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63,\n\t0x65, 0x70, 0x74, 0x48, 0x00, 0x52, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x48, 0x0a, 0x11, 0x72, 0x65, 0x76, 0x6f, 0x6b,\n\t0x65, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b,\n\t0x65, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x11,\n\t0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x12, 0x2b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32,\n\t0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c,\n\t0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28,\n\t0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, 0x06,\n\t0x72, 0x65, 0x61, 0x64, 0x41, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x72, 0x65,\n\t0x61, 0x64, 0x41, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x4f,\n\t0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x5a, 0x0a, 0x1c, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x46,\n\t0x69, 0x6c, 0x65, 0x73, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x76,\n\t0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x63,\n\t0x65, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70,\n\t0x74, 0x22, 0x1f, 0x0a, 0x1d, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73,\n\t0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x22, 0x54, 0x0a, 0x19, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,\n\t0x37, 0x0a, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4e, 0x6f,\n\t0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69,\n\t0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4e,\n\t0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x95, 0x01,\n\t0x0a, 0x18, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0d, 0x6e, 0x6f,\n\t0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x13, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,\n\t0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x4f, 0x66, 0x66,\n\t0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x4f,\n\t0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,\n\t0x6e, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x53,\n\t0x65, 0x65, 0x6e, 0x41, 0x74, 0x22, 0x29, 0x0a, 0x17, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x74,\n\t0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44,\n\t0x22, 0x1a, 0x0a, 0x18, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x0a, 0x13,\n\t0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70,\n\t0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,\n\t0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x1f, 0x52, 0x65, 0x63,\n\t0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42,\n\t0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f,\n\t0x70, 0x61, 0x74, 0x68, 0x54, 0x6f, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x74, 0x68, 0x54, 0x6f, 0x4b, 0x65, 0x79,\n\t0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x22, 0x0a, 0x20, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65,\n\t0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b,\n\t0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x0a, 0x1c, 0x43, 0x72,\n\t0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x61, 0x63,\n\t0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x61,\n\t0x74, 0x68, 0x54, 0x6f, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x74, 0x68, 0x54, 0x6f, 0x4b, 0x65, 0x79, 0x42, 0x61,\n\t0x63, 0x6b, 0x75, 0x70, 0x22, 0x1f, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f,\n\t0x63, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41,\n\t0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x17, 0x0a,\n\t0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,\n\t0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x17,\n\t0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52,\n\t0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x41, 0x50,\n\t0x49, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5f, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x41, 0x50, 0x49, 0x53,\n\t0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x75, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x75, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e,\n\t0x12, 0x24, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x54, 0x6f, 0x6b, 0x65,\n\t0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,\n\t0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1e, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63,\n\t0x65, 0x6e, 0x74, 0x6c, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4c, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63,\n\t0x65, 0x6e, 0x74, 0x6c, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x52,\n\t0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65,\n\t0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d,\n\t0x62, 0x65, 0x72, 0x73, 0x22, 0x21, 0x0a, 0x1f, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69,\n\t0x7a, 0x65, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x20, 0x49, 0x6e, 0x69, 0x74, 0x69,\n\t0x61, 0x6c, 0x69, 0x7a, 0x65, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41, 0x70, 0x70, 0x54, 0x6f,\n\t0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61,\n\t0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61,\n\t0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2f, 0x0a, 0x0d, 0x41, 0x6c, 0x6c, 0x6f, 0x77,\n\t0x65, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x74, 0x68,\n\t0x6f, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65,\n\t0x74, 0x68, 0x6f, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x17, 0x47, 0x65, 0x6e, 0x65,\n\t0x72, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x4d, 0x65,\n\t0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x70,\n\t0x61, 0x63, 0x65, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f,\n\t0x64, 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,\n\t0x73, 0x22, 0x36, 0x0a, 0x18, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70,\n\t0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a,\n\t0x08, 0x61, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x08, 0x61, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x44, 0x0a, 0x16, 0x52, 0x65, 0x6d,\n\t0x6f, 0x76, 0x65, 0x44, 0x69, 0x72, 0x4f, 0x72, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22,\n\t0x19, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x69, 0x72, 0x4f, 0x72, 0x46, 0x69,\n\t0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0xea, 0x01, 0x0a, 0x09, 0x45,\n\t0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x4e, 0x54, 0x52,\n\t0x59, 0x5f, 0x41, 0x44, 0x44, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x4e, 0x54,\n\t0x52, 0x59, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d,\n\t0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12,\n\t0x1c, 0x0a, 0x18, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f,\n\t0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x03, 0x12, 0x16, 0x0a,\n\t0x12, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x52, 0x45,\n\t0x41, 0x44, 0x59, 0x10, 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x52,\n\t0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45,\n\t0x53, 0x53, 0x10, 0x05, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x52, 0x45,\n\t0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x06, 0x12, 0x10, 0x0a,\n\t0x0c, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x41, 0x44, 0x44, 0x45, 0x44, 0x10, 0x07, 0x12,\n\t0x12, 0x0a, 0x0e, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,\n\t0x44, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x55, 0x50,\n\t0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x09, 0x2a, 0x41, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x42, 0x61,\n\t0x63, 0x6b, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53,\n\t0x57, 0x4f, 0x52, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45,\n\t0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x57, 0x49, 0x54, 0x54, 0x45, 0x52, 0x10, 0x02, 0x12,\n\t0x09, 0x0a, 0x05, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x10, 0x03, 0x2a, 0x4b, 0x0a, 0x09, 0x46, 0x75,\n\t0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50,\n\t0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4e, 0x4f, 0x54, 0x5f,\n\t0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x55,\n\t0x4e, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x4f,\n\t0x55, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x6d, 0x0a, 0x10, 0x4e, 0x6f, 0x74, 0x69, 0x66,\n\t0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55,\n\t0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x56, 0x49,\n\t0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x53, 0x41, 0x47,\n\t0x45, 0x41, 0x4c, 0x45, 0x52, 0x54, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x56, 0x49,\n\t0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x50, 0x4c, 0x59, 0x10, 0x03, 0x12, 0x16,\n\t0x0a, 0x12, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x49, 0x54, 0x41,\n\t0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x2a, 0x3b, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45,\n\t0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50,\n\t0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x45,\n\t0x44, 0x10, 0x02, 0x32, 0xd2, 0x29, 0x0a, 0x08, 0x53, 0x70, 0x61, 0x63, 0x65, 0x41, 0x70, 0x69,\n\t0x12, 0x6d, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72,\n\t0x69, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74,\n\t0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44,\n\t0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f,\n\t0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x61, 0x6c, 0x6c, 0x12,\n\t0x63, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79,\n\t0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72,\n\t0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74,\n\t0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4,\n\t0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f,\n\t0x72, 0x69, 0x65, 0x73, 0x12, 0x72, 0x0a, 0x0f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65,\n\t0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x1d, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e,\n\t0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47,\n\t0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15,\n\t0x2f, 0x76, 0x31, 0x2f, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, 0x67, 0x65, 0x6e,\n\t0x65, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x75, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53,\n\t0x74, 0x6f, 0x72, 0x65, 0x64, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x1f, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x4d,\n\t0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x64,\n\t0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x6b, 0x65,\n\t0x79, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x12,\n\t0x9b, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61,\n\t0x69, 0x72, 0x56, 0x69, 0x61, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x27, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79,\n\t0x50, 0x61, 0x69, 0x72, 0x56, 0x69, 0x61, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52,\n\t0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x56, 0x69, 0x61,\n\t0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x6b, 0x65,\n\t0x79, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x57, 0x69,\n\t0x74, 0x68, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a,\n\t0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x1b,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79,\n\t0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x70,\n\t0x61, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69,\n\t0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02,\n\t0x18, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f,\n\t0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x80, 0x01, 0x0a, 0x18, 0x47, 0x65,\n\t0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x57, 0x69, 0x74,\n\t0x68, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47,\n\t0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65,\n\t0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f,\n\t0x76, 0x31, 0x2f, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, 0x66, 0x6f, 0x72, 0x63,\n\t0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x61, 0x0a, 0x0c,\n\t0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x2e, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,\n\t0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f,\n\t0x76, 0x31, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x3a, 0x01, 0x2a, 0x12,\n\t0x5f, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x16, 0x2e, 0x67,\n\t0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,\n\t0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x46, 0x69, 0x6c,\n\t0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e,\n\t0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x73,\n\t0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x30, 0x01,\n\t0x12, 0x68, 0x0a, 0x0c, 0x54, 0x78, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,\n\t0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,\n\t0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x54, 0x65, 0x78, 0x74, 0x69, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f,\n\t0x76, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,\n\t0x2f, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6c, 0x65, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x08, 0x4f, 0x70,\n\t0x65, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4f,\n\t0x70, 0x65, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x52,\n\t0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22,\n\t0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x3a,\n\t0x01, 0x2a, 0x12, 0x63, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x69, 0x72, 0x4f,\n\t0x72, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65,\n\t0x6d, 0x6f, 0x76, 0x65, 0x44, 0x69, 0x72, 0x4f, 0x72, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x6d,\n\t0x6f, 0x76, 0x65, 0x44, 0x69, 0x72, 0x4f, 0x72, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x2a, 0x09, 0x2f, 0x76,\n\t0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65,\n\t0x72, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69,\n\t0x6e, 0x6b, 0x12, 0x24, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72,\n\t0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x6e,\n\t0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46,\n\t0x69, 0x6c, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,\n\t0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22, 0x2b, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x7d, 0x2f, 0x67, 0x65,\n\t0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65,\n\t0x4c, 0x69, 0x6e, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x7f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x53, 0x68,\n\t0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,\n\t0x22, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65,\n\t0x64, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53,\n\t0x68, 0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18,\n\t0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72,\n\t0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x65, 0x12, 0x77, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53,\n\t0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x20,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,\n\t0x42, 0x79, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x1a, 0x21, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72,\n\t0x65, 0x64, 0x42, 0x79, 0x4d, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,\n\t0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31,\n\t0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x4d,\n\t0x65, 0x12, 0x6b, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46,\n\t0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x50, 0x75,\n\t0x62, 0x6c, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69,\n\t0x6c, 0x65, 0x73, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x53,\n\t0x0a, 0x08, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x16, 0x2e, 0x73, 0x70, 0x61,\n\t0x63, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x74,\n\t0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4,\n\t0x93, 0x02, 0x0e, 0x22, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x01,\n\t0x2a, 0x30, 0x01, 0x12, 0x63, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x6c,\n\t0x64, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61,\n\t0x74, 0x65, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,\n\t0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f,\n\t0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3,\n\t0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,\n\t0x6f, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x60, 0x0a, 0x0f, 0x54, 0x6f, 0x67, 0x67,\n\t0x6c, 0x65, 0x46, 0x75, 0x73, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x70,\n\t0x61, 0x63, 0x65, 0x2e, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x46, 0x75, 0x73, 0x65, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x46, 0x75,\n\t0x73, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,\n\t0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x67,\n\t0x67, 0x6c, 0x65, 0x46, 0x75, 0x73, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x58, 0x0a, 0x12, 0x47, 0x65,\n\t0x74, 0x46, 0x75, 0x73, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,\n\t0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x46, 0x75, 0x73, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, 0x76, 0x31, 0x2f,\n\t0x66, 0x75, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x75,\n\t0x63, 0x6b, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65,\n\t0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42,\n\t0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82,\n\t0xd3, 0xe4, 0x93, 0x02, 0x10, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x88, 0x01, 0x0a, 0x16, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,\n\t0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65,\n\t0x12, 0x24, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4b,\n\t0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x42,\n\t0x61, 0x63, 0x6b, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70,\n\t0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82,\n\t0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x70,\n\t0x68, 0x72, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x01, 0x2a,\n\t0x12, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73,\n\t0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x12, 0x25, 0x2e, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73,\n\t0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f,\n\t0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72,\n\t0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4,\n\t0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72,\n\t0x61, 0x73, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12,\n\t0x7a, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x50, 0x61, 0x73, 0x73, 0x70,\n\t0x68, 0x72, 0x61, 0x73, 0x65, 0x12, 0x20, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x54, 0x65,\n\t0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e,\n\t0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61,\n\t0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93,\n\t0x02, 0x19, 0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61,\n\t0x73, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x86, 0x01, 0x0a, 0x15,\n\t0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x73, 0x42,\n\t0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x23, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x43, 0x72,\n\t0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x61, 0x63,\n\t0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x70, 0x61,\n\t0x63, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4b, 0x65,\n\t0x79, 0x73, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x6f,\n\t0x63, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75,\n\t0x70, 0x3a, 0x01, 0x2a, 0x12, 0x90, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72,\n\t0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75,\n\t0x70, 0x12, 0x26, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65,\n\t0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b,\n\t0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73, 0x70, 0x61, 0x63,\n\t0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x79, 0x4c,\n\t0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,\n\t0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f,\n\t0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x72, 0x65, 0x63,\n\t0x6f, 0x76, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x6b, 0x0a, 0x0b, 0x53, 0x68, 0x61, 0x72, 0x65,\n\t0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53,\n\t0x68, 0x61, 0x72, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x42,\n\t0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82,\n\t0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x73, 0x2f, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x7d, 0x2f, 0x73, 0x68, 0x61, 0x72,\n\t0x65, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x0a, 0x4a, 0x6f, 0x69, 0x6e, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x12, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x42,\n\t0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52,\n\t0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22,\n\t0x19, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x7b, 0x62, 0x75,\n\t0x63, 0x6b, 0x65, 0x74, 0x7d, 0x2f, 0x6a, 0x6f, 0x69, 0x6e, 0x3a, 0x01, 0x2a, 0x12, 0x8c, 0x01,\n\t0x0a, 0x16, 0x53, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61, 0x50,\n\t0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61, 0x50, 0x75,\n\t0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65,\n\t0x73, 0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,\n\t0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f,\n\t0x76, 0x31, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x94, 0x01, 0x0a,\n\t0x18, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61,\n\t0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x2e, 0x73, 0x70, 0x61, 0x63,\n\t0x65, 0x2e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69,\n\t0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x1a, 0x27, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x55, 0x6e, 0x73, 0x68, 0x61, 0x72,\n\t0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,\n\t0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93,\n\t0x02, 0x21, 0x22, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x6e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x46,\n\t0x69, 0x6c, 0x65, 0x73, 0x56, 0x69, 0x61, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,\n\t0x3a, 0x01, 0x2a, 0x12, 0x91, 0x01, 0x0a, 0x15, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x46, 0x69,\n\t0x6c, 0x65, 0x73, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65,\n\t0x73, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c,\n\t0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27,\n\t0x22, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x69, 0x6e, 0x76, 0x69, 0x74,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x7b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x49, 0x44, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x7b, 0x0a, 0x15, 0x4e, 0x6f, 0x74, 0x69, 0x66,\n\t0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,\n\t0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,\n\t0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65,\n\t0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93,\n\t0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,\n\t0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x30, 0x01, 0x12, 0x59, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x73, 0x12, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74,\n\t0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93,\n\t0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12,\n\t0x6e, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4e,\n\t0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4e,\n\t0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76,\n\t0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,\n\t0x7b, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64,\n\t0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64,\n\t0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x22, 0x1b, 0x2f, 0x76,\n\t0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f,\n\t0x7b, 0x49, 0x44, 0x7d, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x68, 0x0a, 0x0d,\n\t0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f,\n\t0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61,\n\t0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16,\n\t0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f,\n\t0x75, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x70, 0x0a, 0x12, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65,\n\t0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x2e, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,\n\t0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x42, 0x75, 0x63,\n\t0x6b, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x62,\n\t0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0x7b, 0x0a, 0x13, 0x42, 0x75, 0x63, 0x6b,\n\t0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12,\n\t0x21, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x61,\n\t0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,\n\t0x73, 0x74, 0x1a, 0x22, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65,\n\t0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12,\n\t0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f,\n\t0x72, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67,\n\t0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65,\n\t0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x61,\n\t0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11,\n\t0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x61, 0x67,\n\t0x65, 0x12, 0x7a, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x50, 0x49, 0x53, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65,\n\t0x2e, 0x47, 0x65, 0x74, 0x41, 0x50, 0x49, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f,\n\t0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x73, 0x70,\n\t0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x50, 0x49, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,\n\t0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,\n\t0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69,\n\t0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x7e, 0x0a,\n\t0x15, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x53, 0x68, 0x61, 0x72,\n\t0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x12, 0x23, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47,\n\t0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,\n\t0x57, 0x69, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x70,\n\t0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x53,\n\t0x68, 0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x73,\n\t0x68, 0x61, 0x72, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x9a, 0x01,\n\t0x0a, 0x1a, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x41, 0x74, 0x12, 0x28, 0x2e, 0x73,\n\t0x70, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x41, 0x74, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53,\n\t0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4c,\n\t0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x41, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x6e,\n\t0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6c, 0x61, 0x73,\n\t0x74, 0x53, 0x65, 0x65, 0x6e, 0x41, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, 0x0b, 0x53, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63,\n\t0x65, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x61,\n\t0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,\n\t0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65,\n\t0x61, 0x72, 0x63, 0x68, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x8c, 0x01, 0x0a, 0x18, 0x49,\n\t0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41,\n\t0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x26, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e,\n\t0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72,\n\t0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,\n\t0x27, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69,\n\t0x7a, 0x65, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19,\n\t0x22, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2f,\n\t0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x6d, 0x0a, 0x10, 0x47, 0x65, 0x6e,\n\t0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1e, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x70,\n\t0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,\n\t0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x70,\n\t0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18,\n\t0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x70, 0x54,\n\t0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x3a, 0x01, 0x2a, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_space_proto_rawDescOnce sync.Once\n\tfile_space_proto_rawDescData = file_space_proto_rawDesc\n)\n\nfunc file_space_proto_rawDescGZIP() []byte {\n\tfile_space_proto_rawDescOnce.Do(func() {\n\t\tfile_space_proto_rawDescData = protoimpl.X.CompressGZIP(file_space_proto_rawDescData)\n\t})\n\treturn file_space_proto_rawDescData\n}\n\nvar file_space_proto_enumTypes = make([]protoimpl.EnumInfo, 5)\nvar file_space_proto_msgTypes = make([]protoimpl.MessageInfo, 98)\nvar file_space_proto_goTypes = []interface{}{\n\t(EventType)(0),                             // 0: space.EventType\n\t(KeyBackupType)(0),                         // 1: space.KeyBackupType\n\t(FuseState)(0),                             // 2: space.FuseState\n\t(NotificationType)(0),                      // 3: space.NotificationType\n\t(InvitationStatus)(0),                      // 4: space.InvitationStatus\n\t(*SearchFilesRequest)(nil),                 // 5: space.SearchFilesRequest\n\t(*SearchFilesResponse)(nil),                // 6: space.SearchFilesResponse\n\t(*SearchFilesDirectoryEntry)(nil),          // 7: space.SearchFilesDirectoryEntry\n\t(*SetNotificationsLastSeenAtRequest)(nil),  // 8: space.SetNotificationsLastSeenAtRequest\n\t(*SetNotificationsLastSeenAtResponse)(nil), // 9: space.SetNotificationsLastSeenAtResponse\n\t(*GetSharedWithMeFilesRequest)(nil),        // 10: space.GetSharedWithMeFilesRequest\n\t(*GetSharedWithMeFilesResponse)(nil),       // 11: space.GetSharedWithMeFilesResponse\n\t(*GetSharedByMeFilesRequest)(nil),          // 12: space.GetSharedByMeFilesRequest\n\t(*GetSharedByMeFilesResponse)(nil),         // 13: space.GetSharedByMeFilesResponse\n\t(*GetUsageInfoRequest)(nil),                // 14: space.GetUsageInfoRequest\n\t(*GetUsageInfoResponse)(nil),               // 15: space.GetUsageInfoResponse\n\t(*ToggleBucketBackupRequest)(nil),          // 16: space.ToggleBucketBackupRequest\n\t(*ToggleBucketBackupResponse)(nil),         // 17: space.ToggleBucketBackupResponse\n\t(*BucketBackupRestoreRequest)(nil),         // 18: space.BucketBackupRestoreRequest\n\t(*BucketBackupRestoreResponse)(nil),        // 19: space.BucketBackupRestoreResponse\n\t(*ListDirectoriesRequest)(nil),             // 20: space.ListDirectoriesRequest\n\t(*FileMember)(nil),                         // 21: space.FileMember\n\t(*ListDirectoryEntry)(nil),                 // 22: space.ListDirectoryEntry\n\t(*SharedListDirectoryEntry)(nil),           // 23: space.SharedListDirectoryEntry\n\t(*ListDirectoriesResponse)(nil),            // 24: space.ListDirectoriesResponse\n\t(*ListDirectoryRequest)(nil),               // 25: space.ListDirectoryRequest\n\t(*ListDirectoryResponse)(nil),              // 26: space.ListDirectoryResponse\n\t(*CreateBucketRequest)(nil),                // 27: space.CreateBucketRequest\n\t(*BucketMember)(nil),                       // 28: space.BucketMember\n\t(*Bucket)(nil),                             // 29: space.Bucket\n\t(*CreateBucketResponse)(nil),               // 30: space.CreateBucketResponse\n\t(*GenerateKeyPairRequest)(nil),             // 31: space.GenerateKeyPairRequest\n\t(*GenerateKeyPairResponse)(nil),            // 32: space.GenerateKeyPairResponse\n\t(*GetStoredMnemonicRequest)(nil),           // 33: space.GetStoredMnemonicRequest\n\t(*GetStoredMnemonicResponse)(nil),          // 34: space.GetStoredMnemonicResponse\n\t(*RestoreKeyPairViaMnemonicRequest)(nil),   // 35: space.RestoreKeyPairViaMnemonicRequest\n\t(*RestoreKeyPairViaMnemonicResponse)(nil),  // 36: space.RestoreKeyPairViaMnemonicResponse\n\t(*FileEventResponse)(nil),                  // 37: space.FileEventResponse\n\t(*TextileEventResponse)(nil),               // 38: space.TextileEventResponse\n\t(*OpenFileRequest)(nil),                    // 39: space.OpenFileRequest\n\t(*OpenFileResponse)(nil),                   // 40: space.OpenFileResponse\n\t(*OpenPublicFileRequest)(nil),              // 41: space.OpenPublicFileRequest\n\t(*OpenPublicFileResponse)(nil),             // 42: space.OpenPublicFileResponse\n\t(*AddItemsRequest)(nil),                    // 43: space.AddItemsRequest\n\t(*AddItemResult)(nil),                      // 44: space.AddItemResult\n\t(*AddItemsResponse)(nil),                   // 45: space.AddItemsResponse\n\t(*CreateFolderRequest)(nil),                // 46: space.CreateFolderRequest\n\t(*CreateFolderResponse)(nil),               // 47: space.CreateFolderResponse\n\t(*BackupKeysByPassphraseRequest)(nil),      // 48: space.BackupKeysByPassphraseRequest\n\t(*BackupKeysByPassphraseResponse)(nil),     // 49: space.BackupKeysByPassphraseResponse\n\t(*RecoverKeysByPassphraseRequest)(nil),     // 50: space.RecoverKeysByPassphraseRequest\n\t(*RecoverKeysByPassphraseResponse)(nil),    // 51: space.RecoverKeysByPassphraseResponse\n\t(*TestKeysPassphraseRequest)(nil),          // 52: space.TestKeysPassphraseRequest\n\t(*TestKeysPassphraseResponse)(nil),         // 53: space.TestKeysPassphraseResponse\n\t(*ThreadInfo)(nil),                         // 54: space.ThreadInfo\n\t(*ShareBucketRequest)(nil),                 // 55: space.ShareBucketRequest\n\t(*ShareBucketResponse)(nil),                // 56: space.ShareBucketResponse\n\t(*JoinBucketRequest)(nil),                  // 57: space.JoinBucketRequest\n\t(*JoinBucketResponse)(nil),                 // 58: space.JoinBucketResponse\n\t(*ShareFilesViaPublicKeyRequest)(nil),      // 59: space.ShareFilesViaPublicKeyRequest\n\t(*FullPath)(nil),                           // 60: space.FullPath\n\t(*ShareFilesViaPublicKeyResponse)(nil),     // 61: space.ShareFilesViaPublicKeyResponse\n\t(*UnshareFilesViaPublicKeyRequest)(nil),    // 62: space.UnshareFilesViaPublicKeyRequest\n\t(*UnshareFilesViaPublicKeyResponse)(nil),   // 63: space.UnshareFilesViaPublicKeyResponse\n\t(*GeneratePublicFileLinkRequest)(nil),      // 64: space.GeneratePublicFileLinkRequest\n\t(*GeneratePublicFileLinkResponse)(nil),     // 65: space.GeneratePublicFileLinkResponse\n\t(*ToggleFuseRequest)(nil),                  // 66: space.ToggleFuseRequest\n\t(*FuseDriveResponse)(nil),                  // 67: space.FuseDriveResponse\n\t(*ListBucketsRequest)(nil),                 // 68: space.ListBucketsRequest\n\t(*ListBucketsResponse)(nil),                // 69: space.ListBucketsResponse\n\t(*Invitation)(nil),                         // 70: space.Invitation\n\t(*UsageAlert)(nil),                         // 71: space.UsageAlert\n\t(*InvitationAccept)(nil),                   // 72: space.InvitationAccept\n\t(*RevokedInvitation)(nil),                  // 73: space.RevokedInvitation\n\t(*Notification)(nil),                       // 74: space.Notification\n\t(*HandleFilesInvitationRequest)(nil),       // 75: space.HandleFilesInvitationRequest\n\t(*HandleFilesInvitationResponse)(nil),      // 76: space.HandleFilesInvitationResponse\n\t(*NotificationEventResponse)(nil),          // 77: space.NotificationEventResponse\n\t(*GetNotificationsRequest)(nil),            // 78: space.GetNotificationsRequest\n\t(*GetNotificationsResponse)(nil),           // 79: space.GetNotificationsResponse\n\t(*ReadNotificationRequest)(nil),            // 80: space.ReadNotificationRequest\n\t(*ReadNotificationResponse)(nil),           // 81: space.ReadNotificationResponse\n\t(*GetPublicKeyRequest)(nil),                // 82: space.GetPublicKeyRequest\n\t(*GetPublicKeyResponse)(nil),               // 83: space.GetPublicKeyResponse\n\t(*RecoverKeysByLocalBackupRequest)(nil),    // 84: space.RecoverKeysByLocalBackupRequest\n\t(*RecoverKeysByLocalBackupResponse)(nil),   // 85: space.RecoverKeysByLocalBackupResponse\n\t(*CreateLocalKeysBackupRequest)(nil),       // 86: space.CreateLocalKeysBackupRequest\n\t(*CreateLocalKeysBackupResponse)(nil),      // 87: space.CreateLocalKeysBackupResponse\n\t(*DeleteAccountRequest)(nil),               // 88: space.DeleteAccountRequest\n\t(*DeleteAccountResponse)(nil),              // 89: space.DeleteAccountResponse\n\t(*DeleteKeyPairRequest)(nil),               // 90: space.DeleteKeyPairRequest\n\t(*DeleteKeyPairResponse)(nil),              // 91: space.DeleteKeyPairResponse\n\t(*GetAPISessionTokensRequest)(nil),         // 92: space.GetAPISessionTokensRequest\n\t(*GetAPISessionTokensResponse)(nil),        // 93: space.GetAPISessionTokensResponse\n\t(*GetRecentlySharedWithRequest)(nil),       // 94: space.GetRecentlySharedWithRequest\n\t(*GetRecentlySharedWithResponse)(nil),      // 95: space.GetRecentlySharedWithResponse\n\t(*InitializeMasterAppTokenRequest)(nil),    // 96: space.InitializeMasterAppTokenRequest\n\t(*InitializeMasterAppTokenResponse)(nil),   // 97: space.InitializeMasterAppTokenResponse\n\t(*AllowedMethod)(nil),                      // 98: space.AllowedMethod\n\t(*GenerateAppTokenRequest)(nil),            // 99: space.GenerateAppTokenRequest\n\t(*GenerateAppTokenResponse)(nil),           // 100: space.GenerateAppTokenResponse\n\t(*RemoveDirOrFileRequest)(nil),             // 101: space.RemoveDirOrFileRequest\n\t(*RemoveDirOrFileResponse)(nil),            // 102: space.RemoveDirOrFileResponse\n\t(*empty.Empty)(nil),                        // 103: google.protobuf.Empty\n}\nvar file_space_proto_depIdxs = []int32{\n\t7,   // 0: space.SearchFilesResponse.entries:type_name -> space.SearchFilesDirectoryEntry\n\t22,  // 1: space.SearchFilesDirectoryEntry.entry:type_name -> space.ListDirectoryEntry\n\t23,  // 2: space.GetSharedWithMeFilesResponse.items:type_name -> space.SharedListDirectoryEntry\n\t23,  // 3: space.GetSharedByMeFilesResponse.items:type_name -> space.SharedListDirectoryEntry\n\t21,  // 4: space.ListDirectoryEntry.members:type_name -> space.FileMember\n\t22,  // 5: space.SharedListDirectoryEntry.entry:type_name -> space.ListDirectoryEntry\n\t22,  // 6: space.ListDirectoriesResponse.entries:type_name -> space.ListDirectoryEntry\n\t22,  // 7: space.ListDirectoryResponse.entries:type_name -> space.ListDirectoryEntry\n\t28,  // 8: space.Bucket.members:type_name -> space.BucketMember\n\t29,  // 9: space.CreateBucketResponse.bucket:type_name -> space.Bucket\n\t0,   // 10: space.FileEventResponse.type:type_name -> space.EventType\n\t22,  // 11: space.FileEventResponse.entry:type_name -> space.ListDirectoryEntry\n\t44,  // 12: space.AddItemsResponse.result:type_name -> space.AddItemResult\n\t1,   // 13: space.BackupKeysByPassphraseRequest.type:type_name -> space.KeyBackupType\n\t1,   // 14: space.RecoverKeysByPassphraseRequest.type:type_name -> space.KeyBackupType\n\t54,  // 15: space.ShareBucketResponse.threadinfo:type_name -> space.ThreadInfo\n\t54,  // 16: space.JoinBucketRequest.threadinfo:type_name -> space.ThreadInfo\n\t60,  // 17: space.ShareFilesViaPublicKeyRequest.paths:type_name -> space.FullPath\n\t60,  // 18: space.UnshareFilesViaPublicKeyRequest.paths:type_name -> space.FullPath\n\t2,   // 19: space.FuseDriveResponse.state:type_name -> space.FuseState\n\t29,  // 20: space.ListBucketsResponse.buckets:type_name -> space.Bucket\n\t4,   // 21: space.Invitation.status:type_name -> space.InvitationStatus\n\t60,  // 22: space.Invitation.itemPaths:type_name -> space.FullPath\n\t60,  // 23: space.RevokedInvitation.itemPaths:type_name -> space.FullPath\n\t70,  // 24: space.Notification.invitationValue:type_name -> space.Invitation\n\t71,  // 25: space.Notification.usageAlert:type_name -> space.UsageAlert\n\t72,  // 26: space.Notification.invitationAccept:type_name -> space.InvitationAccept\n\t73,  // 27: space.Notification.revokedInvitation:type_name -> space.RevokedInvitation\n\t3,   // 28: space.Notification.type:type_name -> space.NotificationType\n\t74,  // 29: space.NotificationEventResponse.notification:type_name -> space.Notification\n\t74,  // 30: space.GetNotificationsResponse.notifications:type_name -> space.Notification\n\t21,  // 31: space.GetRecentlySharedWithResponse.members:type_name -> space.FileMember\n\t98,  // 32: space.GenerateAppTokenRequest.allowedMethods:type_name -> space.AllowedMethod\n\t20,  // 33: space.SpaceApi.ListDirectories:input_type -> space.ListDirectoriesRequest\n\t25,  // 34: space.SpaceApi.ListDirectory:input_type -> space.ListDirectoryRequest\n\t31,  // 35: space.SpaceApi.GenerateKeyPair:input_type -> space.GenerateKeyPairRequest\n\t33,  // 36: space.SpaceApi.GetStoredMnemonic:input_type -> space.GetStoredMnemonicRequest\n\t35,  // 37: space.SpaceApi.RestoreKeyPairViaMnemonic:input_type -> space.RestoreKeyPairViaMnemonicRequest\n\t90,  // 38: space.SpaceApi.DeleteKeyPair:input_type -> space.DeleteKeyPairRequest\n\t31,  // 39: space.SpaceApi.GenerateKeyPairWithForce:input_type -> space.GenerateKeyPairRequest\n\t82,  // 40: space.SpaceApi.GetPublicKey:input_type -> space.GetPublicKeyRequest\n\t103, // 41: space.SpaceApi.Subscribe:input_type -> google.protobuf.Empty\n\t103, // 42: space.SpaceApi.TxlSubscribe:input_type -> google.protobuf.Empty\n\t39,  // 43: space.SpaceApi.OpenFile:input_type -> space.OpenFileRequest\n\t101, // 44: space.SpaceApi.RemoveDirOrFile:input_type -> space.RemoveDirOrFileRequest\n\t64,  // 45: space.SpaceApi.GeneratePublicFileLink:input_type -> space.GeneratePublicFileLinkRequest\n\t10,  // 46: space.SpaceApi.GetSharedWithMeFiles:input_type -> space.GetSharedWithMeFilesRequest\n\t12,  // 47: space.SpaceApi.GetSharedByMeFiles:input_type -> space.GetSharedByMeFilesRequest\n\t41,  // 48: space.SpaceApi.OpenPublicFile:input_type -> space.OpenPublicFileRequest\n\t43,  // 49: space.SpaceApi.AddItems:input_type -> space.AddItemsRequest\n\t46,  // 50: space.SpaceApi.CreateFolder:input_type -> space.CreateFolderRequest\n\t66,  // 51: space.SpaceApi.ToggleFuseDrive:input_type -> space.ToggleFuseRequest\n\t103, // 52: space.SpaceApi.GetFuseDriveStatus:input_type -> google.protobuf.Empty\n\t27,  // 53: space.SpaceApi.CreateBucket:input_type -> space.CreateBucketRequest\n\t48,  // 54: space.SpaceApi.BackupKeysByPassphrase:input_type -> space.BackupKeysByPassphraseRequest\n\t50,  // 55: space.SpaceApi.RecoverKeysByPassphrase:input_type -> space.RecoverKeysByPassphraseRequest\n\t52,  // 56: space.SpaceApi.TestKeysPassphrase:input_type -> space.TestKeysPassphraseRequest\n\t86,  // 57: space.SpaceApi.CreateLocalKeysBackup:input_type -> space.CreateLocalKeysBackupRequest\n\t84,  // 58: space.SpaceApi.RecoverKeysByLocalBackup:input_type -> space.RecoverKeysByLocalBackupRequest\n\t55,  // 59: space.SpaceApi.ShareBucket:input_type -> space.ShareBucketRequest\n\t57,  // 60: space.SpaceApi.JoinBucket:input_type -> space.JoinBucketRequest\n\t59,  // 61: space.SpaceApi.ShareFilesViaPublicKey:input_type -> space.ShareFilesViaPublicKeyRequest\n\t62,  // 62: space.SpaceApi.UnshareFilesViaPublicKey:input_type -> space.UnshareFilesViaPublicKeyRequest\n\t75,  // 63: space.SpaceApi.HandleFilesInvitation:input_type -> space.HandleFilesInvitationRequest\n\t103, // 64: space.SpaceApi.NotificationSubscribe:input_type -> google.protobuf.Empty\n\t68,  // 65: space.SpaceApi.ListBuckets:input_type -> space.ListBucketsRequest\n\t78,  // 66: space.SpaceApi.GetNotifications:input_type -> space.GetNotificationsRequest\n\t80,  // 67: space.SpaceApi.ReadNotification:input_type -> space.ReadNotificationRequest\n\t88,  // 68: space.SpaceApi.DeleteAccount:input_type -> space.DeleteAccountRequest\n\t16,  // 69: space.SpaceApi.ToggleBucketBackup:input_type -> space.ToggleBucketBackupRequest\n\t18,  // 70: space.SpaceApi.BucketBackupRestore:input_type -> space.BucketBackupRestoreRequest\n\t14,  // 71: space.SpaceApi.GetUsageInfo:input_type -> space.GetUsageInfoRequest\n\t92,  // 72: space.SpaceApi.GetAPISessionTokens:input_type -> space.GetAPISessionTokensRequest\n\t94,  // 73: space.SpaceApi.GetRecentlySharedWith:input_type -> space.GetRecentlySharedWithRequest\n\t8,   // 74: space.SpaceApi.SetNotificationsLastSeenAt:input_type -> space.SetNotificationsLastSeenAtRequest\n\t5,   // 75: space.SpaceApi.SearchFiles:input_type -> space.SearchFilesRequest\n\t96,  // 76: space.SpaceApi.InitializeMasterAppToken:input_type -> space.InitializeMasterAppTokenRequest\n\t99,  // 77: space.SpaceApi.GenerateAppToken:input_type -> space.GenerateAppTokenRequest\n\t24,  // 78: space.SpaceApi.ListDirectories:output_type -> space.ListDirectoriesResponse\n\t26,  // 79: space.SpaceApi.ListDirectory:output_type -> space.ListDirectoryResponse\n\t32,  // 80: space.SpaceApi.GenerateKeyPair:output_type -> space.GenerateKeyPairResponse\n\t34,  // 81: space.SpaceApi.GetStoredMnemonic:output_type -> space.GetStoredMnemonicResponse\n\t36,  // 82: space.SpaceApi.RestoreKeyPairViaMnemonic:output_type -> space.RestoreKeyPairViaMnemonicResponse\n\t91,  // 83: space.SpaceApi.DeleteKeyPair:output_type -> space.DeleteKeyPairResponse\n\t32,  // 84: space.SpaceApi.GenerateKeyPairWithForce:output_type -> space.GenerateKeyPairResponse\n\t83,  // 85: space.SpaceApi.GetPublicKey:output_type -> space.GetPublicKeyResponse\n\t37,  // 86: space.SpaceApi.Subscribe:output_type -> space.FileEventResponse\n\t38,  // 87: space.SpaceApi.TxlSubscribe:output_type -> space.TextileEventResponse\n\t40,  // 88: space.SpaceApi.OpenFile:output_type -> space.OpenFileResponse\n\t102, // 89: space.SpaceApi.RemoveDirOrFile:output_type -> space.RemoveDirOrFileResponse\n\t65,  // 90: space.SpaceApi.GeneratePublicFileLink:output_type -> space.GeneratePublicFileLinkResponse\n\t11,  // 91: space.SpaceApi.GetSharedWithMeFiles:output_type -> space.GetSharedWithMeFilesResponse\n\t13,  // 92: space.SpaceApi.GetSharedByMeFiles:output_type -> space.GetSharedByMeFilesResponse\n\t42,  // 93: space.SpaceApi.OpenPublicFile:output_type -> space.OpenPublicFileResponse\n\t45,  // 94: space.SpaceApi.AddItems:output_type -> space.AddItemsResponse\n\t47,  // 95: space.SpaceApi.CreateFolder:output_type -> space.CreateFolderResponse\n\t67,  // 96: space.SpaceApi.ToggleFuseDrive:output_type -> space.FuseDriveResponse\n\t67,  // 97: space.SpaceApi.GetFuseDriveStatus:output_type -> space.FuseDriveResponse\n\t30,  // 98: space.SpaceApi.CreateBucket:output_type -> space.CreateBucketResponse\n\t49,  // 99: space.SpaceApi.BackupKeysByPassphrase:output_type -> space.BackupKeysByPassphraseResponse\n\t51,  // 100: space.SpaceApi.RecoverKeysByPassphrase:output_type -> space.RecoverKeysByPassphraseResponse\n\t53,  // 101: space.SpaceApi.TestKeysPassphrase:output_type -> space.TestKeysPassphraseResponse\n\t87,  // 102: space.SpaceApi.CreateLocalKeysBackup:output_type -> space.CreateLocalKeysBackupResponse\n\t85,  // 103: space.SpaceApi.RecoverKeysByLocalBackup:output_type -> space.RecoverKeysByLocalBackupResponse\n\t56,  // 104: space.SpaceApi.ShareBucket:output_type -> space.ShareBucketResponse\n\t58,  // 105: space.SpaceApi.JoinBucket:output_type -> space.JoinBucketResponse\n\t61,  // 106: space.SpaceApi.ShareFilesViaPublicKey:output_type -> space.ShareFilesViaPublicKeyResponse\n\t63,  // 107: space.SpaceApi.UnshareFilesViaPublicKey:output_type -> space.UnshareFilesViaPublicKeyResponse\n\t76,  // 108: space.SpaceApi.HandleFilesInvitation:output_type -> space.HandleFilesInvitationResponse\n\t77,  // 109: space.SpaceApi.NotificationSubscribe:output_type -> space.NotificationEventResponse\n\t69,  // 110: space.SpaceApi.ListBuckets:output_type -> space.ListBucketsResponse\n\t79,  // 111: space.SpaceApi.GetNotifications:output_type -> space.GetNotificationsResponse\n\t81,  // 112: space.SpaceApi.ReadNotification:output_type -> space.ReadNotificationResponse\n\t89,  // 113: space.SpaceApi.DeleteAccount:output_type -> space.DeleteAccountResponse\n\t17,  // 114: space.SpaceApi.ToggleBucketBackup:output_type -> space.ToggleBucketBackupResponse\n\t19,  // 115: space.SpaceApi.BucketBackupRestore:output_type -> space.BucketBackupRestoreResponse\n\t15,  // 116: space.SpaceApi.GetUsageInfo:output_type -> space.GetUsageInfoResponse\n\t93,  // 117: space.SpaceApi.GetAPISessionTokens:output_type -> space.GetAPISessionTokensResponse\n\t95,  // 118: space.SpaceApi.GetRecentlySharedWith:output_type -> space.GetRecentlySharedWithResponse\n\t9,   // 119: space.SpaceApi.SetNotificationsLastSeenAt:output_type -> space.SetNotificationsLastSeenAtResponse\n\t6,   // 120: space.SpaceApi.SearchFiles:output_type -> space.SearchFilesResponse\n\t97,  // 121: space.SpaceApi.InitializeMasterAppToken:output_type -> space.InitializeMasterAppTokenResponse\n\t100, // 122: space.SpaceApi.GenerateAppToken:output_type -> space.GenerateAppTokenResponse\n\t78,  // [78:123] is the sub-list for method output_type\n\t33,  // [33:78] is the sub-list for method input_type\n\t33,  // [33:33] is the sub-list for extension type_name\n\t33,  // [33:33] is the sub-list for extension extendee\n\t0,   // [0:33] is the sub-list for field type_name\n}\n\nfunc init() { file_space_proto_init() }\nfunc file_space_proto_init() {\n\tif File_space_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_space_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SearchFilesRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SearchFilesResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SearchFilesDirectoryEntry); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SetNotificationsLastSeenAtRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SetNotificationsLastSeenAtResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetSharedWithMeFilesRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetSharedWithMeFilesResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetSharedByMeFilesRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetSharedByMeFilesResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetUsageInfoRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetUsageInfoResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ToggleBucketBackupRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ToggleBucketBackupResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BucketBackupRestoreRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BucketBackupRestoreResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListDirectoriesRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FileMember); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListDirectoryEntry); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SharedListDirectoryEntry); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListDirectoriesResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListDirectoryRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListDirectoryResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateBucketRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BucketMember); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Bucket); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateBucketResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GenerateKeyPairRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GenerateKeyPairResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetStoredMnemonicRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetStoredMnemonicResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RestoreKeyPairViaMnemonicRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RestoreKeyPairViaMnemonicResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FileEventResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TextileEventResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OpenFileRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OpenFileResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OpenPublicFileRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*OpenPublicFileResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddItemsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddItemResult); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AddItemsResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateFolderRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateFolderResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BackupKeysByPassphraseRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BackupKeysByPassphraseResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RecoverKeysByPassphraseRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RecoverKeysByPassphraseResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TestKeysPassphraseRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TestKeysPassphraseResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ThreadInfo); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ShareBucketRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ShareBucketResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*JoinBucketRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*JoinBucketResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ShareFilesViaPublicKeyRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FullPath); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ShareFilesViaPublicKeyResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*UnshareFilesViaPublicKeyRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*UnshareFilesViaPublicKeyResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GeneratePublicFileLinkRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GeneratePublicFileLinkResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ToggleFuseRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*FuseDriveResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListBucketsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ListBucketsResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Invitation); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*UsageAlert); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*InvitationAccept); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RevokedInvitation); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Notification); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*HandleFilesInvitationRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*HandleFilesInvitationResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*NotificationEventResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetNotificationsRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetNotificationsResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ReadNotificationRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ReadNotificationResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetPublicKeyRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetPublicKeyResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RecoverKeysByLocalBackupRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RecoverKeysByLocalBackupResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateLocalKeysBackupRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateLocalKeysBackupResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DeleteAccountRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DeleteAccountResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DeleteKeyPairRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*DeleteKeyPairResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetAPISessionTokensRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetAPISessionTokensResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetRecentlySharedWithRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GetRecentlySharedWithResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*InitializeMasterAppTokenRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*InitializeMasterAppTokenResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AllowedMethod); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GenerateAppTokenRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GenerateAppTokenResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveDirOrFileRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_space_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RemoveDirOrFileResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_space_proto_msgTypes[69].OneofWrappers = []interface{}{\n\t\t(*Notification_InvitationValue)(nil),\n\t\t(*Notification_UsageAlert)(nil),\n\t\t(*Notification_InvitationAccept)(nil),\n\t\t(*Notification_RevokedInvitation)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_space_proto_rawDesc,\n\t\t\tNumEnums:      5,\n\t\t\tNumMessages:   98,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_space_proto_goTypes,\n\t\tDependencyIndexes: file_space_proto_depIdxs,\n\t\tEnumInfos:         file_space_proto_enumTypes,\n\t\tMessageInfos:      file_space_proto_msgTypes,\n\t}.Build()\n\tFile_space_proto = out.File\n\tfile_space_proto_rawDesc = nil\n\tfile_space_proto_goTypes = nil\n\tfile_space_proto_depIdxs = nil\n}\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ context.Context\nvar _ grpc.ClientConnInterface\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion6\n\n// SpaceApiClient is the client API for SpaceApi service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.\ntype SpaceApiClient interface {\n\t// Get all folder or files in the default bucket. It fetches all subdirectories too.\n\tListDirectories(ctx context.Context, in *ListDirectoriesRequest, opts ...grpc.CallOption) (*ListDirectoriesResponse, error)\n\t// Get the folder or files in the path directory.\n\t// Unlike ListDirectories, this only returns immediate children at path.\n\tListDirectory(ctx context.Context, in *ListDirectoryRequest, opts ...grpc.CallOption) (*ListDirectoryResponse, error)\n\t// Generate Key Pair for current account.\n\t// This will return error if daemon account already has keypairs\n\tGenerateKeyPair(ctx context.Context, in *GenerateKeyPairRequest, opts ...grpc.CallOption) (*GenerateKeyPairResponse, error)\n\tGetStoredMnemonic(ctx context.Context, in *GetStoredMnemonicRequest, opts ...grpc.CallOption) (*GetStoredMnemonicResponse, error)\n\t// Restores a keypair given a mnemonic.\n\t// This will override any existing key pair\n\tRestoreKeyPairViaMnemonic(ctx context.Context, in *RestoreKeyPairViaMnemonicRequest, opts ...grpc.CallOption) (*RestoreKeyPairViaMnemonicResponse, error)\n\tDeleteKeyPair(ctx context.Context, in *DeleteKeyPairRequest, opts ...grpc.CallOption) (*DeleteKeyPairResponse, error)\n\t// Force Generation of KeyPair. This will override existing keys stored in daemon.\n\tGenerateKeyPairWithForce(ctx context.Context, in *GenerateKeyPairRequest, opts ...grpc.CallOption) (*GenerateKeyPairResponse, error)\n\tGetPublicKey(ctx context.Context, in *GetPublicKeyRequest, opts ...grpc.CallOption) (*GetPublicKeyResponse, error)\n\t// Subscribe to file events. This streams responses to the caller\n\tSubscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (SpaceApi_SubscribeClient, error)\n\t// Subscribe to textile events. This streams responses to the caller\n\tTxlSubscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (SpaceApi_TxlSubscribeClient, error)\n\t// Open a file in the daemon.\n\t// Daemon keeps track of all open files and closes them if no activity is noticed after a while\n\tOpenFile(ctx context.Context, in *OpenFileRequest, opts ...grpc.CallOption) (*OpenFileResponse, error)\n\t// Removes a file or dir from a bucket\n\tRemoveDirOrFile(ctx context.Context, in *RemoveDirOrFileRequest, opts ...grpc.CallOption) (*RemoveDirOrFileResponse, error)\n\t// Generates a copy of the file that's accessible through IPFS gateways\n\tGeneratePublicFileLink(ctx context.Context, in *GeneratePublicFileLinkRequest, opts ...grpc.CallOption) (*GeneratePublicFileLinkResponse, error)\n\t// Gets the files that are shared with this recipient\n\tGetSharedWithMeFiles(ctx context.Context, in *GetSharedWithMeFilesRequest, opts ...grpc.CallOption) (*GetSharedWithMeFilesResponse, error)\n\t// Gets the files that are shared by the sender\n\tGetSharedByMeFiles(ctx context.Context, in *GetSharedByMeFilesRequest, opts ...grpc.CallOption) (*GetSharedByMeFilesResponse, error)\n\t// Open an encrypted public shared file in the daemon.\n\t// This requires the decryption key and file hash/cid to work\n\tOpenPublicFile(ctx context.Context, in *OpenPublicFileRequest, opts ...grpc.CallOption) (*OpenPublicFileResponse, error)\n\t// Adds items (files/folders) to be uploaded to the bucket.\n\tAddItems(ctx context.Context, in *AddItemsRequest, opts ...grpc.CallOption) (SpaceApi_AddItemsClient, error)\n\t// Creates a folder/directory at the specified path\n\tCreateFolder(ctx context.Context, in *CreateFolderRequest, opts ...grpc.CallOption) (*CreateFolderResponse, error)\n\t// Toggle FUSE drive to be mounted or unmounted\n\tToggleFuseDrive(ctx context.Context, in *ToggleFuseRequest, opts ...grpc.CallOption) (*FuseDriveResponse, error)\n\t// Get status of FUSE drive. If mounted or unmounted\n\tGetFuseDriveStatus(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*FuseDriveResponse, error)\n\t// Create a new bucket owned by current user (aka keypair)\n\tCreateBucket(ctx context.Context, in *CreateBucketRequest, opts ...grpc.CallOption) (*CreateBucketResponse, error)\n\t// Backup Key by Passphrase\n\tBackupKeysByPassphrase(ctx context.Context, in *BackupKeysByPassphraseRequest, opts ...grpc.CallOption) (*BackupKeysByPassphraseResponse, error)\n\t// Recover Keys by Passphrase\n\tRecoverKeysByPassphrase(ctx context.Context, in *RecoverKeysByPassphraseRequest, opts ...grpc.CallOption) (*RecoverKeysByPassphraseResponse, error)\n\t// Tests a passphrase to see if it matches the one previously used\n\tTestKeysPassphrase(ctx context.Context, in *TestKeysPassphraseRequest, opts ...grpc.CallOption) (*TestKeysPassphraseResponse, error)\n\tCreateLocalKeysBackup(ctx context.Context, in *CreateLocalKeysBackupRequest, opts ...grpc.CallOption) (*CreateLocalKeysBackupResponse, error)\n\tRecoverKeysByLocalBackup(ctx context.Context, in *RecoverKeysByLocalBackupRequest, opts ...grpc.CallOption) (*RecoverKeysByLocalBackupResponse, error)\n\t// Share bucket\n\tShareBucket(ctx context.Context, in *ShareBucketRequest, opts ...grpc.CallOption) (*ShareBucketResponse, error)\n\t// Join bucket\n\tJoinBucket(ctx context.Context, in *JoinBucketRequest, opts ...grpc.CallOption) (*JoinBucketResponse, error)\n\t// Share bucket via public key using Textile Hub inboxing\n\tShareFilesViaPublicKey(ctx context.Context, in *ShareFilesViaPublicKeyRequest, opts ...grpc.CallOption) (*ShareFilesViaPublicKeyResponse, error)\n\t// Remove public keys for shared files in buckets\n\tUnshareFilesViaPublicKey(ctx context.Context, in *UnshareFilesViaPublicKeyRequest, opts ...grpc.CallOption) (*UnshareFilesViaPublicKeyResponse, error)\n\tHandleFilesInvitation(ctx context.Context, in *HandleFilesInvitationRequest, opts ...grpc.CallOption) (*HandleFilesInvitationResponse, error)\n\tNotificationSubscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (SpaceApi_NotificationSubscribeClient, error)\n\tListBuckets(ctx context.Context, in *ListBucketsRequest, opts ...grpc.CallOption) (*ListBucketsResponse, error)\n\tGetNotifications(ctx context.Context, in *GetNotificationsRequest, opts ...grpc.CallOption) (*GetNotificationsResponse, error)\n\tReadNotification(ctx context.Context, in *ReadNotificationRequest, opts ...grpc.CallOption) (*ReadNotificationResponse, error)\n\tDeleteAccount(ctx context.Context, in *DeleteAccountRequest, opts ...grpc.CallOption) (*DeleteAccountResponse, error)\n\tToggleBucketBackup(ctx context.Context, in *ToggleBucketBackupRequest, opts ...grpc.CallOption) (*ToggleBucketBackupResponse, error)\n\tBucketBackupRestore(ctx context.Context, in *BucketBackupRestoreRequest, opts ...grpc.CallOption) (*BucketBackupRestoreResponse, error)\n\tGetUsageInfo(ctx context.Context, in *GetUsageInfoRequest, opts ...grpc.CallOption) (*GetUsageInfoResponse, error)\n\tGetAPISessionTokens(ctx context.Context, in *GetAPISessionTokensRequest, opts ...grpc.CallOption) (*GetAPISessionTokensResponse, error)\n\t// Returns a list of addresses / public keys of clients to which files where shared or received, ordered by date\n\tGetRecentlySharedWith(ctx context.Context, in *GetRecentlySharedWithRequest, opts ...grpc.CallOption) (*GetRecentlySharedWithResponse, error)\n\t// This will set the last read timestamp for the user so that the client\n\t// can check if newer notifications are present for UX\n\tSetNotificationsLastSeenAt(ctx context.Context, in *SetNotificationsLastSeenAtRequest, opts ...grpc.CallOption) (*SetNotificationsLastSeenAtResponse, error)\n\t// Search for files across all users bucket\n\tSearchFiles(ctx context.Context, in *SearchFilesRequest, opts ...grpc.CallOption) (*SearchFilesResponse, error)\n\t// Initialize master app token\n\t// App tokens are used to authorize scoped access to a range of methods\n\t// Master token can only be generated once and has access to all methods\n\tInitializeMasterAppToken(ctx context.Context, in *InitializeMasterAppTokenRequest, opts ...grpc.CallOption) (*InitializeMasterAppTokenResponse, error)\n\t// Generates an app token with scoped access.\n\tGenerateAppToken(ctx context.Context, in *GenerateAppTokenRequest, opts ...grpc.CallOption) (*GenerateAppTokenResponse, error)\n}\n\ntype spaceApiClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewSpaceApiClient(cc grpc.ClientConnInterface) SpaceApiClient {\n\treturn &spaceApiClient{cc}\n}\n\nfunc (c *spaceApiClient) ListDirectories(ctx context.Context, in *ListDirectoriesRequest, opts ...grpc.CallOption) (*ListDirectoriesResponse, error) {\n\tout := new(ListDirectoriesResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ListDirectories\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) ListDirectory(ctx context.Context, in *ListDirectoryRequest, opts ...grpc.CallOption) (*ListDirectoryResponse, error) {\n\tout := new(ListDirectoryResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ListDirectory\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GenerateKeyPair(ctx context.Context, in *GenerateKeyPairRequest, opts ...grpc.CallOption) (*GenerateKeyPairResponse, error) {\n\tout := new(GenerateKeyPairResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GenerateKeyPair\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetStoredMnemonic(ctx context.Context, in *GetStoredMnemonicRequest, opts ...grpc.CallOption) (*GetStoredMnemonicResponse, error) {\n\tout := new(GetStoredMnemonicResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetStoredMnemonic\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) RestoreKeyPairViaMnemonic(ctx context.Context, in *RestoreKeyPairViaMnemonicRequest, opts ...grpc.CallOption) (*RestoreKeyPairViaMnemonicResponse, error) {\n\tout := new(RestoreKeyPairViaMnemonicResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/RestoreKeyPairViaMnemonic\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) DeleteKeyPair(ctx context.Context, in *DeleteKeyPairRequest, opts ...grpc.CallOption) (*DeleteKeyPairResponse, error) {\n\tout := new(DeleteKeyPairResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/DeleteKeyPair\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GenerateKeyPairWithForce(ctx context.Context, in *GenerateKeyPairRequest, opts ...grpc.CallOption) (*GenerateKeyPairResponse, error) {\n\tout := new(GenerateKeyPairResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GenerateKeyPairWithForce\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetPublicKey(ctx context.Context, in *GetPublicKeyRequest, opts ...grpc.CallOption) (*GetPublicKeyResponse, error) {\n\tout := new(GetPublicKeyResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetPublicKey\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) Subscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (SpaceApi_SubscribeClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &_SpaceApi_serviceDesc.Streams[0], \"/space.SpaceApi/Subscribe\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &spaceApiSubscribeClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype SpaceApi_SubscribeClient interface {\n\tRecv() (*FileEventResponse, error)\n\tgrpc.ClientStream\n}\n\ntype spaceApiSubscribeClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *spaceApiSubscribeClient) Recv() (*FileEventResponse, error) {\n\tm := new(FileEventResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *spaceApiClient) TxlSubscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (SpaceApi_TxlSubscribeClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &_SpaceApi_serviceDesc.Streams[1], \"/space.SpaceApi/TxlSubscribe\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &spaceApiTxlSubscribeClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype SpaceApi_TxlSubscribeClient interface {\n\tRecv() (*TextileEventResponse, error)\n\tgrpc.ClientStream\n}\n\ntype spaceApiTxlSubscribeClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *spaceApiTxlSubscribeClient) Recv() (*TextileEventResponse, error) {\n\tm := new(TextileEventResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *spaceApiClient) OpenFile(ctx context.Context, in *OpenFileRequest, opts ...grpc.CallOption) (*OpenFileResponse, error) {\n\tout := new(OpenFileResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/OpenFile\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) RemoveDirOrFile(ctx context.Context, in *RemoveDirOrFileRequest, opts ...grpc.CallOption) (*RemoveDirOrFileResponse, error) {\n\tout := new(RemoveDirOrFileResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/RemoveDirOrFile\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GeneratePublicFileLink(ctx context.Context, in *GeneratePublicFileLinkRequest, opts ...grpc.CallOption) (*GeneratePublicFileLinkResponse, error) {\n\tout := new(GeneratePublicFileLinkResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GeneratePublicFileLink\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetSharedWithMeFiles(ctx context.Context, in *GetSharedWithMeFilesRequest, opts ...grpc.CallOption) (*GetSharedWithMeFilesResponse, error) {\n\tout := new(GetSharedWithMeFilesResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetSharedWithMeFiles\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetSharedByMeFiles(ctx context.Context, in *GetSharedByMeFilesRequest, opts ...grpc.CallOption) (*GetSharedByMeFilesResponse, error) {\n\tout := new(GetSharedByMeFilesResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetSharedByMeFiles\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) OpenPublicFile(ctx context.Context, in *OpenPublicFileRequest, opts ...grpc.CallOption) (*OpenPublicFileResponse, error) {\n\tout := new(OpenPublicFileResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/OpenPublicFile\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) AddItems(ctx context.Context, in *AddItemsRequest, opts ...grpc.CallOption) (SpaceApi_AddItemsClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &_SpaceApi_serviceDesc.Streams[2], \"/space.SpaceApi/AddItems\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &spaceApiAddItemsClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype SpaceApi_AddItemsClient interface {\n\tRecv() (*AddItemsResponse, error)\n\tgrpc.ClientStream\n}\n\ntype spaceApiAddItemsClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *spaceApiAddItemsClient) Recv() (*AddItemsResponse, error) {\n\tm := new(AddItemsResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *spaceApiClient) CreateFolder(ctx context.Context, in *CreateFolderRequest, opts ...grpc.CallOption) (*CreateFolderResponse, error) {\n\tout := new(CreateFolderResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/CreateFolder\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) ToggleFuseDrive(ctx context.Context, in *ToggleFuseRequest, opts ...grpc.CallOption) (*FuseDriveResponse, error) {\n\tout := new(FuseDriveResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ToggleFuseDrive\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetFuseDriveStatus(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*FuseDriveResponse, error) {\n\tout := new(FuseDriveResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetFuseDriveStatus\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) CreateBucket(ctx context.Context, in *CreateBucketRequest, opts ...grpc.CallOption) (*CreateBucketResponse, error) {\n\tout := new(CreateBucketResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/CreateBucket\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) BackupKeysByPassphrase(ctx context.Context, in *BackupKeysByPassphraseRequest, opts ...grpc.CallOption) (*BackupKeysByPassphraseResponse, error) {\n\tout := new(BackupKeysByPassphraseResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/BackupKeysByPassphrase\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) RecoverKeysByPassphrase(ctx context.Context, in *RecoverKeysByPassphraseRequest, opts ...grpc.CallOption) (*RecoverKeysByPassphraseResponse, error) {\n\tout := new(RecoverKeysByPassphraseResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/RecoverKeysByPassphrase\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) TestKeysPassphrase(ctx context.Context, in *TestKeysPassphraseRequest, opts ...grpc.CallOption) (*TestKeysPassphraseResponse, error) {\n\tout := new(TestKeysPassphraseResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/TestKeysPassphrase\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) CreateLocalKeysBackup(ctx context.Context, in *CreateLocalKeysBackupRequest, opts ...grpc.CallOption) (*CreateLocalKeysBackupResponse, error) {\n\tout := new(CreateLocalKeysBackupResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/CreateLocalKeysBackup\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) RecoverKeysByLocalBackup(ctx context.Context, in *RecoverKeysByLocalBackupRequest, opts ...grpc.CallOption) (*RecoverKeysByLocalBackupResponse, error) {\n\tout := new(RecoverKeysByLocalBackupResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/RecoverKeysByLocalBackup\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) ShareBucket(ctx context.Context, in *ShareBucketRequest, opts ...grpc.CallOption) (*ShareBucketResponse, error) {\n\tout := new(ShareBucketResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ShareBucket\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) JoinBucket(ctx context.Context, in *JoinBucketRequest, opts ...grpc.CallOption) (*JoinBucketResponse, error) {\n\tout := new(JoinBucketResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/JoinBucket\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) ShareFilesViaPublicKey(ctx context.Context, in *ShareFilesViaPublicKeyRequest, opts ...grpc.CallOption) (*ShareFilesViaPublicKeyResponse, error) {\n\tout := new(ShareFilesViaPublicKeyResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ShareFilesViaPublicKey\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) UnshareFilesViaPublicKey(ctx context.Context, in *UnshareFilesViaPublicKeyRequest, opts ...grpc.CallOption) (*UnshareFilesViaPublicKeyResponse, error) {\n\tout := new(UnshareFilesViaPublicKeyResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/UnshareFilesViaPublicKey\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) HandleFilesInvitation(ctx context.Context, in *HandleFilesInvitationRequest, opts ...grpc.CallOption) (*HandleFilesInvitationResponse, error) {\n\tout := new(HandleFilesInvitationResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/HandleFilesInvitation\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) NotificationSubscribe(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (SpaceApi_NotificationSubscribeClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &_SpaceApi_serviceDesc.Streams[3], \"/space.SpaceApi/NotificationSubscribe\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &spaceApiNotificationSubscribeClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype SpaceApi_NotificationSubscribeClient interface {\n\tRecv() (*NotificationEventResponse, error)\n\tgrpc.ClientStream\n}\n\ntype spaceApiNotificationSubscribeClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *spaceApiNotificationSubscribeClient) Recv() (*NotificationEventResponse, error) {\n\tm := new(NotificationEventResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *spaceApiClient) ListBuckets(ctx context.Context, in *ListBucketsRequest, opts ...grpc.CallOption) (*ListBucketsResponse, error) {\n\tout := new(ListBucketsResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ListBuckets\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetNotifications(ctx context.Context, in *GetNotificationsRequest, opts ...grpc.CallOption) (*GetNotificationsResponse, error) {\n\tout := new(GetNotificationsResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetNotifications\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) ReadNotification(ctx context.Context, in *ReadNotificationRequest, opts ...grpc.CallOption) (*ReadNotificationResponse, error) {\n\tout := new(ReadNotificationResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ReadNotification\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) DeleteAccount(ctx context.Context, in *DeleteAccountRequest, opts ...grpc.CallOption) (*DeleteAccountResponse, error) {\n\tout := new(DeleteAccountResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/DeleteAccount\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) ToggleBucketBackup(ctx context.Context, in *ToggleBucketBackupRequest, opts ...grpc.CallOption) (*ToggleBucketBackupResponse, error) {\n\tout := new(ToggleBucketBackupResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/ToggleBucketBackup\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) BucketBackupRestore(ctx context.Context, in *BucketBackupRestoreRequest, opts ...grpc.CallOption) (*BucketBackupRestoreResponse, error) {\n\tout := new(BucketBackupRestoreResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/BucketBackupRestore\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetUsageInfo(ctx context.Context, in *GetUsageInfoRequest, opts ...grpc.CallOption) (*GetUsageInfoResponse, error) {\n\tout := new(GetUsageInfoResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetUsageInfo\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetAPISessionTokens(ctx context.Context, in *GetAPISessionTokensRequest, opts ...grpc.CallOption) (*GetAPISessionTokensResponse, error) {\n\tout := new(GetAPISessionTokensResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetAPISessionTokens\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GetRecentlySharedWith(ctx context.Context, in *GetRecentlySharedWithRequest, opts ...grpc.CallOption) (*GetRecentlySharedWithResponse, error) {\n\tout := new(GetRecentlySharedWithResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GetRecentlySharedWith\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) SetNotificationsLastSeenAt(ctx context.Context, in *SetNotificationsLastSeenAtRequest, opts ...grpc.CallOption) (*SetNotificationsLastSeenAtResponse, error) {\n\tout := new(SetNotificationsLastSeenAtResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/SetNotificationsLastSeenAt\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) SearchFiles(ctx context.Context, in *SearchFilesRequest, opts ...grpc.CallOption) (*SearchFilesResponse, error) {\n\tout := new(SearchFilesResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/SearchFiles\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) InitializeMasterAppToken(ctx context.Context, in *InitializeMasterAppTokenRequest, opts ...grpc.CallOption) (*InitializeMasterAppTokenResponse, error) {\n\tout := new(InitializeMasterAppTokenResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/InitializeMasterAppToken\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *spaceApiClient) GenerateAppToken(ctx context.Context, in *GenerateAppTokenRequest, opts ...grpc.CallOption) (*GenerateAppTokenResponse, error) {\n\tout := new(GenerateAppTokenResponse)\n\terr := c.cc.Invoke(ctx, \"/space.SpaceApi/GenerateAppToken\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// SpaceApiServer is the server API for SpaceApi service.\ntype SpaceApiServer interface {\n\t// Get all folder or files in the default bucket. It fetches all subdirectories too.\n\tListDirectories(context.Context, *ListDirectoriesRequest) (*ListDirectoriesResponse, error)\n\t// Get the folder or files in the path directory.\n\t// Unlike ListDirectories, this only returns immediate children at path.\n\tListDirectory(context.Context, *ListDirectoryRequest) (*ListDirectoryResponse, error)\n\t// Generate Key Pair for current account.\n\t// This will return error if daemon account already has keypairs\n\tGenerateKeyPair(context.Context, *GenerateKeyPairRequest) (*GenerateKeyPairResponse, error)\n\tGetStoredMnemonic(context.Context, *GetStoredMnemonicRequest) (*GetStoredMnemonicResponse, error)\n\t// Restores a keypair given a mnemonic.\n\t// This will override any existing key pair\n\tRestoreKeyPairViaMnemonic(context.Context, *RestoreKeyPairViaMnemonicRequest) (*RestoreKeyPairViaMnemonicResponse, error)\n\tDeleteKeyPair(context.Context, *DeleteKeyPairRequest) (*DeleteKeyPairResponse, error)\n\t// Force Generation of KeyPair. This will override existing keys stored in daemon.\n\tGenerateKeyPairWithForce(context.Context, *GenerateKeyPairRequest) (*GenerateKeyPairResponse, error)\n\tGetPublicKey(context.Context, *GetPublicKeyRequest) (*GetPublicKeyResponse, error)\n\t// Subscribe to file events. This streams responses to the caller\n\tSubscribe(*empty.Empty, SpaceApi_SubscribeServer) error\n\t// Subscribe to textile events. This streams responses to the caller\n\tTxlSubscribe(*empty.Empty, SpaceApi_TxlSubscribeServer) error\n\t// Open a file in the daemon.\n\t// Daemon keeps track of all open files and closes them if no activity is noticed after a while\n\tOpenFile(context.Context, *OpenFileRequest) (*OpenFileResponse, error)\n\t// Removes a file or dir from a bucket\n\tRemoveDirOrFile(context.Context, *RemoveDirOrFileRequest) (*RemoveDirOrFileResponse, error)\n\t// Generates a copy of the file that's accessible through IPFS gateways\n\tGeneratePublicFileLink(context.Context, *GeneratePublicFileLinkRequest) (*GeneratePublicFileLinkResponse, error)\n\t// Gets the files that are shared with this recipient\n\tGetSharedWithMeFiles(context.Context, *GetSharedWithMeFilesRequest) (*GetSharedWithMeFilesResponse, error)\n\t// Gets the files that are shared by the sender\n\tGetSharedByMeFiles(context.Context, *GetSharedByMeFilesRequest) (*GetSharedByMeFilesResponse, error)\n\t// Open an encrypted public shared file in the daemon.\n\t// This requires the decryption key and file hash/cid to work\n\tOpenPublicFile(context.Context, *OpenPublicFileRequest) (*OpenPublicFileResponse, error)\n\t// Adds items (files/folders) to be uploaded to the bucket.\n\tAddItems(*AddItemsRequest, SpaceApi_AddItemsServer) error\n\t// Creates a folder/directory at the specified path\n\tCreateFolder(context.Context, *CreateFolderRequest) (*CreateFolderResponse, error)\n\t// Toggle FUSE drive to be mounted or unmounted\n\tToggleFuseDrive(context.Context, *ToggleFuseRequest) (*FuseDriveResponse, error)\n\t// Get status of FUSE drive. If mounted or unmounted\n\tGetFuseDriveStatus(context.Context, *empty.Empty) (*FuseDriveResponse, error)\n\t// Create a new bucket owned by current user (aka keypair)\n\tCreateBucket(context.Context, *CreateBucketRequest) (*CreateBucketResponse, error)\n\t// Backup Key by Passphrase\n\tBackupKeysByPassphrase(context.Context, *BackupKeysByPassphraseRequest) (*BackupKeysByPassphraseResponse, error)\n\t// Recover Keys by Passphrase\n\tRecoverKeysByPassphrase(context.Context, *RecoverKeysByPassphraseRequest) (*RecoverKeysByPassphraseResponse, error)\n\t// Tests a passphrase to see if it matches the one previously used\n\tTestKeysPassphrase(context.Context, *TestKeysPassphraseRequest) (*TestKeysPassphraseResponse, error)\n\tCreateLocalKeysBackup(context.Context, *CreateLocalKeysBackupRequest) (*CreateLocalKeysBackupResponse, error)\n\tRecoverKeysByLocalBackup(context.Context, *RecoverKeysByLocalBackupRequest) (*RecoverKeysByLocalBackupResponse, error)\n\t// Share bucket\n\tShareBucket(context.Context, *ShareBucketRequest) (*ShareBucketResponse, error)\n\t// Join bucket\n\tJoinBucket(context.Context, *JoinBucketRequest) (*JoinBucketResponse, error)\n\t// Share bucket via public key using Textile Hub inboxing\n\tShareFilesViaPublicKey(context.Context, *ShareFilesViaPublicKeyRequest) (*ShareFilesViaPublicKeyResponse, error)\n\t// Remove public keys for shared files in buckets\n\tUnshareFilesViaPublicKey(context.Context, *UnshareFilesViaPublicKeyRequest) (*UnshareFilesViaPublicKeyResponse, error)\n\tHandleFilesInvitation(context.Context, *HandleFilesInvitationRequest) (*HandleFilesInvitationResponse, error)\n\tNotificationSubscribe(*empty.Empty, SpaceApi_NotificationSubscribeServer) error\n\tListBuckets(context.Context, *ListBucketsRequest) (*ListBucketsResponse, error)\n\tGetNotifications(context.Context, *GetNotificationsRequest) (*GetNotificationsResponse, error)\n\tReadNotification(context.Context, *ReadNotificationRequest) (*ReadNotificationResponse, error)\n\tDeleteAccount(context.Context, *DeleteAccountRequest) (*DeleteAccountResponse, error)\n\tToggleBucketBackup(context.Context, *ToggleBucketBackupRequest) (*ToggleBucketBackupResponse, error)\n\tBucketBackupRestore(context.Context, *BucketBackupRestoreRequest) (*BucketBackupRestoreResponse, error)\n\tGetUsageInfo(context.Context, *GetUsageInfoRequest) (*GetUsageInfoResponse, error)\n\tGetAPISessionTokens(context.Context, *GetAPISessionTokensRequest) (*GetAPISessionTokensResponse, error)\n\t// Returns a list of addresses / public keys of clients to which files where shared or received, ordered by date\n\tGetRecentlySharedWith(context.Context, *GetRecentlySharedWithRequest) (*GetRecentlySharedWithResponse, error)\n\t// This will set the last read timestamp for the user so that the client\n\t// can check if newer notifications are present for UX\n\tSetNotificationsLastSeenAt(context.Context, *SetNotificationsLastSeenAtRequest) (*SetNotificationsLastSeenAtResponse, error)\n\t// Search for files across all users bucket\n\tSearchFiles(context.Context, *SearchFilesRequest) (*SearchFilesResponse, error)\n\t// Initialize master app token\n\t// App tokens are used to authorize scoped access to a range of methods\n\t// Master token can only be generated once and has access to all methods\n\tInitializeMasterAppToken(context.Context, *InitializeMasterAppTokenRequest) (*InitializeMasterAppTokenResponse, error)\n\t// Generates an app token with scoped access.\n\tGenerateAppToken(context.Context, *GenerateAppTokenRequest) (*GenerateAppTokenResponse, error)\n}\n\n// UnimplementedSpaceApiServer can be embedded to have forward compatible implementations.\ntype UnimplementedSpaceApiServer struct {\n}\n\nfunc (*UnimplementedSpaceApiServer) ListDirectories(context.Context, *ListDirectoriesRequest) (*ListDirectoriesResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ListDirectories not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ListDirectory(context.Context, *ListDirectoryRequest) (*ListDirectoryResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ListDirectory not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GenerateKeyPair(context.Context, *GenerateKeyPairRequest) (*GenerateKeyPairResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GenerateKeyPair not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetStoredMnemonic(context.Context, *GetStoredMnemonicRequest) (*GetStoredMnemonicResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetStoredMnemonic not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) RestoreKeyPairViaMnemonic(context.Context, *RestoreKeyPairViaMnemonicRequest) (*RestoreKeyPairViaMnemonicResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RestoreKeyPairViaMnemonic not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) DeleteKeyPair(context.Context, *DeleteKeyPairRequest) (*DeleteKeyPairResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method DeleteKeyPair not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GenerateKeyPairWithForce(context.Context, *GenerateKeyPairRequest) (*GenerateKeyPairResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GenerateKeyPairWithForce not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetPublicKey(context.Context, *GetPublicKeyRequest) (*GetPublicKeyResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetPublicKey not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) Subscribe(*empty.Empty, SpaceApi_SubscribeServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method Subscribe not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) TxlSubscribe(*empty.Empty, SpaceApi_TxlSubscribeServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method TxlSubscribe not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) OpenFile(context.Context, *OpenFileRequest) (*OpenFileResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method OpenFile not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) RemoveDirOrFile(context.Context, *RemoveDirOrFileRequest) (*RemoveDirOrFileResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RemoveDirOrFile not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GeneratePublicFileLink(context.Context, *GeneratePublicFileLinkRequest) (*GeneratePublicFileLinkResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GeneratePublicFileLink not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetSharedWithMeFiles(context.Context, *GetSharedWithMeFilesRequest) (*GetSharedWithMeFilesResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetSharedWithMeFiles not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetSharedByMeFiles(context.Context, *GetSharedByMeFilesRequest) (*GetSharedByMeFilesResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetSharedByMeFiles not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) OpenPublicFile(context.Context, *OpenPublicFileRequest) (*OpenPublicFileResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method OpenPublicFile not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) AddItems(*AddItemsRequest, SpaceApi_AddItemsServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method AddItems not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) CreateFolder(context.Context, *CreateFolderRequest) (*CreateFolderResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method CreateFolder not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ToggleFuseDrive(context.Context, *ToggleFuseRequest) (*FuseDriveResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ToggleFuseDrive not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetFuseDriveStatus(context.Context, *empty.Empty) (*FuseDriveResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetFuseDriveStatus not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) CreateBucket(context.Context, *CreateBucketRequest) (*CreateBucketResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method CreateBucket not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) BackupKeysByPassphrase(context.Context, *BackupKeysByPassphraseRequest) (*BackupKeysByPassphraseResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method BackupKeysByPassphrase not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) RecoverKeysByPassphrase(context.Context, *RecoverKeysByPassphraseRequest) (*RecoverKeysByPassphraseResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RecoverKeysByPassphrase not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) TestKeysPassphrase(context.Context, *TestKeysPassphraseRequest) (*TestKeysPassphraseResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestKeysPassphrase not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) CreateLocalKeysBackup(context.Context, *CreateLocalKeysBackupRequest) (*CreateLocalKeysBackupResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method CreateLocalKeysBackup not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) RecoverKeysByLocalBackup(context.Context, *RecoverKeysByLocalBackupRequest) (*RecoverKeysByLocalBackupResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RecoverKeysByLocalBackup not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ShareBucket(context.Context, *ShareBucketRequest) (*ShareBucketResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ShareBucket not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) JoinBucket(context.Context, *JoinBucketRequest) (*JoinBucketResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method JoinBucket not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ShareFilesViaPublicKey(context.Context, *ShareFilesViaPublicKeyRequest) (*ShareFilesViaPublicKeyResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ShareFilesViaPublicKey not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) UnshareFilesViaPublicKey(context.Context, *UnshareFilesViaPublicKeyRequest) (*UnshareFilesViaPublicKeyResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method UnshareFilesViaPublicKey not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) HandleFilesInvitation(context.Context, *HandleFilesInvitationRequest) (*HandleFilesInvitationResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method HandleFilesInvitation not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) NotificationSubscribe(*empty.Empty, SpaceApi_NotificationSubscribeServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method NotificationSubscribe not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ListBuckets(context.Context, *ListBucketsRequest) (*ListBucketsResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ListBuckets not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetNotifications(context.Context, *GetNotificationsRequest) (*GetNotificationsResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetNotifications not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ReadNotification(context.Context, *ReadNotificationRequest) (*ReadNotificationResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ReadNotification not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) DeleteAccount(context.Context, *DeleteAccountRequest) (*DeleteAccountResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method DeleteAccount not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) ToggleBucketBackup(context.Context, *ToggleBucketBackupRequest) (*ToggleBucketBackupResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ToggleBucketBackup not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) BucketBackupRestore(context.Context, *BucketBackupRestoreRequest) (*BucketBackupRestoreResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method BucketBackupRestore not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetUsageInfo(context.Context, *GetUsageInfoRequest) (*GetUsageInfoResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetUsageInfo not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetAPISessionTokens(context.Context, *GetAPISessionTokensRequest) (*GetAPISessionTokensResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetAPISessionTokens not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GetRecentlySharedWith(context.Context, *GetRecentlySharedWithRequest) (*GetRecentlySharedWithResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetRecentlySharedWith not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) SetNotificationsLastSeenAt(context.Context, *SetNotificationsLastSeenAtRequest) (*SetNotificationsLastSeenAtResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method SetNotificationsLastSeenAt not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) SearchFiles(context.Context, *SearchFilesRequest) (*SearchFilesResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method SearchFiles not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) InitializeMasterAppToken(context.Context, *InitializeMasterAppTokenRequest) (*InitializeMasterAppTokenResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method InitializeMasterAppToken not implemented\")\n}\nfunc (*UnimplementedSpaceApiServer) GenerateAppToken(context.Context, *GenerateAppTokenRequest) (*GenerateAppTokenResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GenerateAppToken not implemented\")\n}\n\nfunc RegisterSpaceApiServer(s *grpc.Server, srv SpaceApiServer) {\n\ts.RegisterService(&_SpaceApi_serviceDesc, srv)\n}\n\nfunc _SpaceApi_ListDirectories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ListDirectoriesRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ListDirectories(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ListDirectories\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ListDirectories(ctx, req.(*ListDirectoriesRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_ListDirectory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ListDirectoryRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ListDirectory(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ListDirectory\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ListDirectory(ctx, req.(*ListDirectoryRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GenerateKeyPair_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GenerateKeyPairRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GenerateKeyPair(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GenerateKeyPair\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GenerateKeyPair(ctx, req.(*GenerateKeyPairRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetStoredMnemonic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetStoredMnemonicRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetStoredMnemonic(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetStoredMnemonic\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetStoredMnemonic(ctx, req.(*GetStoredMnemonicRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_RestoreKeyPairViaMnemonic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RestoreKeyPairViaMnemonicRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).RestoreKeyPairViaMnemonic(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/RestoreKeyPairViaMnemonic\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).RestoreKeyPairViaMnemonic(ctx, req.(*RestoreKeyPairViaMnemonicRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_DeleteKeyPair_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(DeleteKeyPairRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).DeleteKeyPair(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/DeleteKeyPair\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).DeleteKeyPair(ctx, req.(*DeleteKeyPairRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GenerateKeyPairWithForce_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GenerateKeyPairRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GenerateKeyPairWithForce(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GenerateKeyPairWithForce\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GenerateKeyPairWithForce(ctx, req.(*GenerateKeyPairRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetPublicKeyRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetPublicKey(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetPublicKey\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetPublicKey(ctx, req.(*GetPublicKeyRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(empty.Empty)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(SpaceApiServer).Subscribe(m, &spaceApiSubscribeServer{stream})\n}\n\ntype SpaceApi_SubscribeServer interface {\n\tSend(*FileEventResponse) error\n\tgrpc.ServerStream\n}\n\ntype spaceApiSubscribeServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *spaceApiSubscribeServer) Send(m *FileEventResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _SpaceApi_TxlSubscribe_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(empty.Empty)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(SpaceApiServer).TxlSubscribe(m, &spaceApiTxlSubscribeServer{stream})\n}\n\ntype SpaceApi_TxlSubscribeServer interface {\n\tSend(*TextileEventResponse) error\n\tgrpc.ServerStream\n}\n\ntype spaceApiTxlSubscribeServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *spaceApiTxlSubscribeServer) Send(m *TextileEventResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _SpaceApi_OpenFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(OpenFileRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).OpenFile(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/OpenFile\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).OpenFile(ctx, req.(*OpenFileRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_RemoveDirOrFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RemoveDirOrFileRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).RemoveDirOrFile(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/RemoveDirOrFile\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).RemoveDirOrFile(ctx, req.(*RemoveDirOrFileRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GeneratePublicFileLink_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GeneratePublicFileLinkRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GeneratePublicFileLink(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GeneratePublicFileLink\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GeneratePublicFileLink(ctx, req.(*GeneratePublicFileLinkRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetSharedWithMeFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetSharedWithMeFilesRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetSharedWithMeFiles(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetSharedWithMeFiles\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetSharedWithMeFiles(ctx, req.(*GetSharedWithMeFilesRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetSharedByMeFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetSharedByMeFilesRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetSharedByMeFiles(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetSharedByMeFiles\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetSharedByMeFiles(ctx, req.(*GetSharedByMeFilesRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_OpenPublicFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(OpenPublicFileRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).OpenPublicFile(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/OpenPublicFile\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).OpenPublicFile(ctx, req.(*OpenPublicFileRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_AddItems_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(AddItemsRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(SpaceApiServer).AddItems(m, &spaceApiAddItemsServer{stream})\n}\n\ntype SpaceApi_AddItemsServer interface {\n\tSend(*AddItemsResponse) error\n\tgrpc.ServerStream\n}\n\ntype spaceApiAddItemsServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *spaceApiAddItemsServer) Send(m *AddItemsResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _SpaceApi_CreateFolder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CreateFolderRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).CreateFolder(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/CreateFolder\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).CreateFolder(ctx, req.(*CreateFolderRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_ToggleFuseDrive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ToggleFuseRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ToggleFuseDrive(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ToggleFuseDrive\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ToggleFuseDrive(ctx, req.(*ToggleFuseRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetFuseDriveStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetFuseDriveStatus(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetFuseDriveStatus\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetFuseDriveStatus(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_CreateBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CreateBucketRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).CreateBucket(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/CreateBucket\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).CreateBucket(ctx, req.(*CreateBucketRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_BackupKeysByPassphrase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(BackupKeysByPassphraseRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).BackupKeysByPassphrase(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/BackupKeysByPassphrase\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).BackupKeysByPassphrase(ctx, req.(*BackupKeysByPassphraseRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_RecoverKeysByPassphrase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RecoverKeysByPassphraseRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).RecoverKeysByPassphrase(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/RecoverKeysByPassphrase\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).RecoverKeysByPassphrase(ctx, req.(*RecoverKeysByPassphraseRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_TestKeysPassphrase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(TestKeysPassphraseRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).TestKeysPassphrase(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/TestKeysPassphrase\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).TestKeysPassphrase(ctx, req.(*TestKeysPassphraseRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_CreateLocalKeysBackup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CreateLocalKeysBackupRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).CreateLocalKeysBackup(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/CreateLocalKeysBackup\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).CreateLocalKeysBackup(ctx, req.(*CreateLocalKeysBackupRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_RecoverKeysByLocalBackup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RecoverKeysByLocalBackupRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).RecoverKeysByLocalBackup(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/RecoverKeysByLocalBackup\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).RecoverKeysByLocalBackup(ctx, req.(*RecoverKeysByLocalBackupRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_ShareBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ShareBucketRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ShareBucket(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ShareBucket\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ShareBucket(ctx, req.(*ShareBucketRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_JoinBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(JoinBucketRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).JoinBucket(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/JoinBucket\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).JoinBucket(ctx, req.(*JoinBucketRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_ShareFilesViaPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ShareFilesViaPublicKeyRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ShareFilesViaPublicKey(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ShareFilesViaPublicKey\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ShareFilesViaPublicKey(ctx, req.(*ShareFilesViaPublicKeyRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_UnshareFilesViaPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(UnshareFilesViaPublicKeyRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).UnshareFilesViaPublicKey(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/UnshareFilesViaPublicKey\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).UnshareFilesViaPublicKey(ctx, req.(*UnshareFilesViaPublicKeyRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_HandleFilesInvitation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(HandleFilesInvitationRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).HandleFilesInvitation(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/HandleFilesInvitation\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).HandleFilesInvitation(ctx, req.(*HandleFilesInvitationRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_NotificationSubscribe_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(empty.Empty)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(SpaceApiServer).NotificationSubscribe(m, &spaceApiNotificationSubscribeServer{stream})\n}\n\ntype SpaceApi_NotificationSubscribeServer interface {\n\tSend(*NotificationEventResponse) error\n\tgrpc.ServerStream\n}\n\ntype spaceApiNotificationSubscribeServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *spaceApiNotificationSubscribeServer) Send(m *NotificationEventResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _SpaceApi_ListBuckets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ListBucketsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ListBuckets(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ListBuckets\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ListBuckets(ctx, req.(*ListBucketsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetNotificationsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetNotifications(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetNotifications\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetNotifications(ctx, req.(*GetNotificationsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_ReadNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ReadNotificationRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ReadNotification(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ReadNotification\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ReadNotification(ctx, req.(*ReadNotificationRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_DeleteAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(DeleteAccountRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).DeleteAccount(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/DeleteAccount\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).DeleteAccount(ctx, req.(*DeleteAccountRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_ToggleBucketBackup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ToggleBucketBackupRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).ToggleBucketBackup(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/ToggleBucketBackup\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).ToggleBucketBackup(ctx, req.(*ToggleBucketBackupRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_BucketBackupRestore_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(BucketBackupRestoreRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).BucketBackupRestore(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/BucketBackupRestore\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).BucketBackupRestore(ctx, req.(*BucketBackupRestoreRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetUsageInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetUsageInfoRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetUsageInfo(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetUsageInfo\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetUsageInfo(ctx, req.(*GetUsageInfoRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetAPISessionTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetAPISessionTokensRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetAPISessionTokens(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetAPISessionTokens\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetAPISessionTokens(ctx, req.(*GetAPISessionTokensRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GetRecentlySharedWith_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetRecentlySharedWithRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GetRecentlySharedWith(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GetRecentlySharedWith\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GetRecentlySharedWith(ctx, req.(*GetRecentlySharedWithRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_SetNotificationsLastSeenAt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(SetNotificationsLastSeenAtRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).SetNotificationsLastSeenAt(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/SetNotificationsLastSeenAt\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).SetNotificationsLastSeenAt(ctx, req.(*SetNotificationsLastSeenAtRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_SearchFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(SearchFilesRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).SearchFiles(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/SearchFiles\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).SearchFiles(ctx, req.(*SearchFilesRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_InitializeMasterAppToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(InitializeMasterAppTokenRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).InitializeMasterAppToken(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/InitializeMasterAppToken\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).InitializeMasterAppToken(ctx, req.(*InitializeMasterAppTokenRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SpaceApi_GenerateAppToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GenerateAppTokenRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SpaceApiServer).GenerateAppToken(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/space.SpaceApi/GenerateAppToken\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SpaceApiServer).GenerateAppToken(ctx, req.(*GenerateAppTokenRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _SpaceApi_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"space.SpaceApi\",\n\tHandlerType: (*SpaceApiServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"ListDirectories\",\n\t\t\tHandler:    _SpaceApi_ListDirectories_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ListDirectory\",\n\t\t\tHandler:    _SpaceApi_ListDirectory_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GenerateKeyPair\",\n\t\t\tHandler:    _SpaceApi_GenerateKeyPair_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetStoredMnemonic\",\n\t\t\tHandler:    _SpaceApi_GetStoredMnemonic_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"RestoreKeyPairViaMnemonic\",\n\t\t\tHandler:    _SpaceApi_RestoreKeyPairViaMnemonic_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"DeleteKeyPair\",\n\t\t\tHandler:    _SpaceApi_DeleteKeyPair_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GenerateKeyPairWithForce\",\n\t\t\tHandler:    _SpaceApi_GenerateKeyPairWithForce_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetPublicKey\",\n\t\t\tHandler:    _SpaceApi_GetPublicKey_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"OpenFile\",\n\t\t\tHandler:    _SpaceApi_OpenFile_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"RemoveDirOrFile\",\n\t\t\tHandler:    _SpaceApi_RemoveDirOrFile_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GeneratePublicFileLink\",\n\t\t\tHandler:    _SpaceApi_GeneratePublicFileLink_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetSharedWithMeFiles\",\n\t\t\tHandler:    _SpaceApi_GetSharedWithMeFiles_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetSharedByMeFiles\",\n\t\t\tHandler:    _SpaceApi_GetSharedByMeFiles_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"OpenPublicFile\",\n\t\t\tHandler:    _SpaceApi_OpenPublicFile_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"CreateFolder\",\n\t\t\tHandler:    _SpaceApi_CreateFolder_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ToggleFuseDrive\",\n\t\t\tHandler:    _SpaceApi_ToggleFuseDrive_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetFuseDriveStatus\",\n\t\t\tHandler:    _SpaceApi_GetFuseDriveStatus_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"CreateBucket\",\n\t\t\tHandler:    _SpaceApi_CreateBucket_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"BackupKeysByPassphrase\",\n\t\t\tHandler:    _SpaceApi_BackupKeysByPassphrase_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"RecoverKeysByPassphrase\",\n\t\t\tHandler:    _SpaceApi_RecoverKeysByPassphrase_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"TestKeysPassphrase\",\n\t\t\tHandler:    _SpaceApi_TestKeysPassphrase_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"CreateLocalKeysBackup\",\n\t\t\tHandler:    _SpaceApi_CreateLocalKeysBackup_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"RecoverKeysByLocalBackup\",\n\t\t\tHandler:    _SpaceApi_RecoverKeysByLocalBackup_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ShareBucket\",\n\t\t\tHandler:    _SpaceApi_ShareBucket_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"JoinBucket\",\n\t\t\tHandler:    _SpaceApi_JoinBucket_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ShareFilesViaPublicKey\",\n\t\t\tHandler:    _SpaceApi_ShareFilesViaPublicKey_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"UnshareFilesViaPublicKey\",\n\t\t\tHandler:    _SpaceApi_UnshareFilesViaPublicKey_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"HandleFilesInvitation\",\n\t\t\tHandler:    _SpaceApi_HandleFilesInvitation_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ListBuckets\",\n\t\t\tHandler:    _SpaceApi_ListBuckets_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetNotifications\",\n\t\t\tHandler:    _SpaceApi_GetNotifications_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ReadNotification\",\n\t\t\tHandler:    _SpaceApi_ReadNotification_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"DeleteAccount\",\n\t\t\tHandler:    _SpaceApi_DeleteAccount_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ToggleBucketBackup\",\n\t\t\tHandler:    _SpaceApi_ToggleBucketBackup_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"BucketBackupRestore\",\n\t\t\tHandler:    _SpaceApi_BucketBackupRestore_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetUsageInfo\",\n\t\t\tHandler:    _SpaceApi_GetUsageInfo_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetAPISessionTokens\",\n\t\t\tHandler:    _SpaceApi_GetAPISessionTokens_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GetRecentlySharedWith\",\n\t\t\tHandler:    _SpaceApi_GetRecentlySharedWith_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"SetNotificationsLastSeenAt\",\n\t\t\tHandler:    _SpaceApi_SetNotificationsLastSeenAt_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"SearchFiles\",\n\t\t\tHandler:    _SpaceApi_SearchFiles_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"InitializeMasterAppToken\",\n\t\t\tHandler:    _SpaceApi_InitializeMasterAppToken_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GenerateAppToken\",\n\t\t\tHandler:    _SpaceApi_GenerateAppToken_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"Subscribe\",\n\t\t\tHandler:       _SpaceApi_Subscribe_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"TxlSubscribe\",\n\t\t\tHandler:       _SpaceApi_TxlSubscribe_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"AddItems\",\n\t\t\tHandler:       _SpaceApi_AddItems_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"NotificationSubscribe\",\n\t\t\tHandler:       _SpaceApi_NotificationSubscribe_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"space.proto\",\n}\n"
  },
  {
    "path": "grpc/pb/space.pb.gw.go",
    "content": "// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.\n// source: space.proto\n\n/*\nPackage pb is a reverse proxy.\n\nIt translates gRPC into RESTful JSON APIs.\n*/\npackage pb\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/golang/protobuf/descriptor\"\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\t\"github.com/grpc-ecosystem/grpc-gateway/runtime\"\n\t\"github.com/grpc-ecosystem/grpc-gateway/utilities\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/grpclog\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// Suppress \"imported and not used\" errors\nvar _ codes.Code\nvar _ io.Reader\nvar _ status.Status\nvar _ = runtime.String\nvar _ = utilities.NewDoubleArray\nvar _ = descriptor.ForMessage\n\nvar (\n\tfilter_SpaceApi_ListDirectories_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_ListDirectories_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ListDirectoriesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_ListDirectories_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.ListDirectories(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ListDirectories_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ListDirectoriesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_ListDirectories_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.ListDirectories(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_ListDirectory_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_ListDirectory_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ListDirectoryRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_ListDirectory_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.ListDirectory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ListDirectory_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ListDirectoryRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_ListDirectory_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.ListDirectory(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GenerateKeyPair_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GenerateKeyPairRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GenerateKeyPair(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GenerateKeyPair_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GenerateKeyPairRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GenerateKeyPair(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GetStoredMnemonic_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetStoredMnemonicRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.GetStoredMnemonic(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetStoredMnemonic_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetStoredMnemonicRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.GetStoredMnemonic(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_RestoreKeyPairViaMnemonic_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RestoreKeyPairViaMnemonicRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.RestoreKeyPairViaMnemonic(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_RestoreKeyPairViaMnemonic_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RestoreKeyPairViaMnemonicRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.RestoreKeyPairViaMnemonic(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_DeleteKeyPair_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq DeleteKeyPairRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.DeleteKeyPair(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_DeleteKeyPair_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq DeleteKeyPairRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.DeleteKeyPair(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GenerateKeyPairWithForce_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GenerateKeyPairRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GenerateKeyPairWithForce(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GenerateKeyPairWithForce_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GenerateKeyPairRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GenerateKeyPairWithForce(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GetPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetPublicKeyRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GetPublicKey(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetPublicKeyRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GetPublicKey(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_Subscribe_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (SpaceApi_SubscribeClient, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tstream, err := client.Subscribe(ctx, &protoReq)\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\theader, err := stream.Header()\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\tmetadata.HeaderMD = header\n\treturn stream, metadata, nil\n\n}\n\nfunc request_SpaceApi_TxlSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (SpaceApi_TxlSubscribeClient, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tstream, err := client.TxlSubscribe(ctx, &protoReq)\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\theader, err := stream.Header()\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\tmetadata.HeaderMD = header\n\treturn stream, metadata, nil\n\n}\n\nfunc request_SpaceApi_OpenFile_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq OpenFileRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.OpenFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_OpenFile_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq OpenFileRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.OpenFile(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_RemoveDirOrFile_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_RemoveDirOrFile_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RemoveDirOrFileRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_RemoveDirOrFile_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.RemoveDirOrFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_RemoveDirOrFile_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RemoveDirOrFileRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_RemoveDirOrFile_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.RemoveDirOrFile(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GeneratePublicFileLink_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GeneratePublicFileLinkRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"bucket\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"bucket\")\n\t}\n\n\tprotoReq.Bucket, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"bucket\", err)\n\t}\n\n\tmsg, err := client.GeneratePublicFileLink(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GeneratePublicFileLink_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GeneratePublicFileLinkRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"bucket\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"bucket\")\n\t}\n\n\tprotoReq.Bucket, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"bucket\", err)\n\t}\n\n\tmsg, err := server.GeneratePublicFileLink(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_GetSharedWithMeFiles_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_GetSharedWithMeFiles_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetSharedWithMeFilesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_GetSharedWithMeFiles_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GetSharedWithMeFiles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetSharedWithMeFiles_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetSharedWithMeFilesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_GetSharedWithMeFiles_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GetSharedWithMeFiles(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_GetSharedByMeFiles_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_GetSharedByMeFiles_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetSharedByMeFilesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_GetSharedByMeFiles_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GetSharedByMeFiles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetSharedByMeFiles_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetSharedByMeFilesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_GetSharedByMeFiles_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GetSharedByMeFiles(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_OpenPublicFile_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_OpenPublicFile_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq OpenPublicFileRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_OpenPublicFile_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.OpenPublicFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_OpenPublicFile_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq OpenPublicFileRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_OpenPublicFile_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.OpenPublicFile(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_AddItems_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (SpaceApi_AddItemsClient, runtime.ServerMetadata, error) {\n\tvar protoReq AddItemsRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tstream, err := client.AddItems(ctx, &protoReq)\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\theader, err := stream.Header()\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\tmetadata.HeaderMD = header\n\treturn stream, metadata, nil\n\n}\n\nfunc request_SpaceApi_CreateFolder_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq CreateFolderRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.CreateFolder(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_CreateFolder_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq CreateFolderRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.CreateFolder(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_ToggleFuseDrive_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ToggleFuseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.ToggleFuseDrive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ToggleFuseDrive_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ToggleFuseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.ToggleFuseDrive(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GetFuseDriveStatus_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.GetFuseDriveStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetFuseDriveStatus_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.GetFuseDriveStatus(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_CreateBucket_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq CreateBucketRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.CreateBucket(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_CreateBucket_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq CreateBucketRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.CreateBucket(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_BackupKeysByPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq BackupKeysByPassphraseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.BackupKeysByPassphrase(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_BackupKeysByPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq BackupKeysByPassphraseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.BackupKeysByPassphrase(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_RecoverKeysByPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RecoverKeysByPassphraseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.RecoverKeysByPassphrase(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_RecoverKeysByPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RecoverKeysByPassphraseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.RecoverKeysByPassphrase(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_TestKeysPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq TestKeysPassphraseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.TestKeysPassphrase(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_TestKeysPassphrase_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq TestKeysPassphraseRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.TestKeysPassphrase(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_CreateLocalKeysBackup_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq CreateLocalKeysBackupRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.CreateLocalKeysBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_CreateLocalKeysBackup_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq CreateLocalKeysBackupRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.CreateLocalKeysBackup(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_RecoverKeysByLocalBackup_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RecoverKeysByLocalBackupRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.RecoverKeysByLocalBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_RecoverKeysByLocalBackup_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq RecoverKeysByLocalBackupRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.RecoverKeysByLocalBackup(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_ShareBucket_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ShareBucketRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"bucket\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"bucket\")\n\t}\n\n\tprotoReq.Bucket, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"bucket\", err)\n\t}\n\n\tmsg, err := client.ShareBucket(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ShareBucket_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ShareBucketRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"bucket\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"bucket\")\n\t}\n\n\tprotoReq.Bucket, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"bucket\", err)\n\t}\n\n\tmsg, err := server.ShareBucket(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_JoinBucket_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq JoinBucketRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"bucket\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"bucket\")\n\t}\n\n\tprotoReq.Bucket, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"bucket\", err)\n\t}\n\n\tmsg, err := client.JoinBucket(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_JoinBucket_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq JoinBucketRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"bucket\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"bucket\")\n\t}\n\n\tprotoReq.Bucket, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"bucket\", err)\n\t}\n\n\tmsg, err := server.JoinBucket(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_ShareFilesViaPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ShareFilesViaPublicKeyRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.ShareFilesViaPublicKey(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ShareFilesViaPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ShareFilesViaPublicKeyRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.ShareFilesViaPublicKey(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_UnshareFilesViaPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq UnshareFilesViaPublicKeyRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.UnshareFilesViaPublicKey(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_UnshareFilesViaPublicKey_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq UnshareFilesViaPublicKeyRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.UnshareFilesViaPublicKey(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_HandleFilesInvitation_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq HandleFilesInvitationRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"invitationID\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"invitationID\")\n\t}\n\n\tprotoReq.InvitationID, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"invitationID\", err)\n\t}\n\n\tmsg, err := client.HandleFilesInvitation(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_HandleFilesInvitation_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq HandleFilesInvitationRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"invitationID\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"invitationID\")\n\t}\n\n\tprotoReq.InvitationID, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"invitationID\", err)\n\t}\n\n\tmsg, err := server.HandleFilesInvitation(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_NotificationSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (SpaceApi_NotificationSubscribeClient, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tstream, err := client.NotificationSubscribe(ctx, &protoReq)\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\theader, err := stream.Header()\n\tif err != nil {\n\t\treturn nil, metadata, err\n\t}\n\tmetadata.HeaderMD = header\n\treturn stream, metadata, nil\n\n}\n\nfunc request_SpaceApi_ListBuckets_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ListBucketsRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.ListBuckets(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ListBuckets_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ListBucketsRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.ListBuckets(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_GetNotifications_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_GetNotifications_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetNotificationsRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_GetNotifications_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GetNotifications(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetNotifications_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetNotificationsRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_GetNotifications_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GetNotifications(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_ReadNotification_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ReadNotificationRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"ID\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"ID\")\n\t}\n\n\tprotoReq.ID, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"ID\", err)\n\t}\n\n\tmsg, err := client.ReadNotification(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ReadNotification_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ReadNotificationRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"ID\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"ID\")\n\t}\n\n\tprotoReq.ID, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"ID\", err)\n\t}\n\n\tmsg, err := server.ReadNotification(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_DeleteAccount_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq DeleteAccountRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.DeleteAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_DeleteAccount_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq DeleteAccountRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.DeleteAccount(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_ToggleBucketBackup_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ToggleBucketBackupRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.ToggleBucketBackup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_ToggleBucketBackup_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ToggleBucketBackupRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.ToggleBucketBackup(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_BucketBackupRestore_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq BucketBackupRestoreRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.BucketBackupRestore(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_BucketBackupRestore_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq BucketBackupRestoreRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.BucketBackupRestore(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GetUsageInfo_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetUsageInfoRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.GetUsageInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetUsageInfo_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetUsageInfoRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.GetUsageInfo(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GetAPISessionTokens_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetAPISessionTokensRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.GetAPISessionTokens(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetAPISessionTokens_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetAPISessionTokensRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.GetAPISessionTokens(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GetRecentlySharedWith_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetRecentlySharedWithRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.GetRecentlySharedWith(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GetRecentlySharedWith_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetRecentlySharedWithRequest\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.GetRecentlySharedWith(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_SetNotificationsLastSeenAt_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq SetNotificationsLastSeenAtRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.SetNotificationsLastSeenAt(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_SetNotificationsLastSeenAt_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq SetNotificationsLastSeenAtRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.SetNotificationsLastSeenAt(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nvar (\n\tfilter_SpaceApi_SearchFiles_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}\n)\n\nfunc request_SpaceApi_SearchFiles_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq SearchFilesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_SearchFiles_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.SearchFiles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_SearchFiles_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq SearchFilesRequest\n\tvar metadata runtime.ServerMetadata\n\n\tif err := req.ParseForm(); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\tif err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SpaceApi_SearchFiles_0); err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.SearchFiles(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_InitializeMasterAppToken_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq InitializeMasterAppTokenRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.InitializeMasterAppToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_InitializeMasterAppToken_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq InitializeMasterAppTokenRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.InitializeMasterAppToken(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_SpaceApi_GenerateAppToken_0(ctx context.Context, marshaler runtime.Marshaler, client SpaceApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GenerateAppTokenRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := client.GenerateAppToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_SpaceApi_GenerateAppToken_0(ctx context.Context, marshaler runtime.Marshaler, server SpaceApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GenerateAppTokenRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tmsg, err := server.GenerateAppToken(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\n// RegisterSpaceApiHandlerServer registers the http handlers for service SpaceApi to \"mux\".\n// UnaryRPC     :call SpaceApiServer directly.\n// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.\n// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterSpaceApiHandlerFromEndpoint instead.\nfunc RegisterSpaceApiHandlerServer(ctx context.Context, mux *runtime.ServeMux, server SpaceApiServer) error {\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_ListDirectories_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ListDirectories_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ListDirectories_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_ListDirectory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ListDirectory_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ListDirectory_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GenerateKeyPair_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GenerateKeyPair_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GenerateKeyPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetStoredMnemonic_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetStoredMnemonic_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetStoredMnemonic_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_RestoreKeyPairViaMnemonic_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_RestoreKeyPairViaMnemonic_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RestoreKeyPairViaMnemonic_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_DeleteKeyPair_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_DeleteKeyPair_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_DeleteKeyPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GenerateKeyPairWithForce_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GenerateKeyPairWithForce_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GenerateKeyPairWithForce_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GetPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetPublicKey_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_Subscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\terr := status.Error(codes.Unimplemented, \"streaming calls are not yet supported in the in-process transport\")\n\t\t_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\treturn\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_TxlSubscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\terr := status.Error(codes.Unimplemented, \"streaming calls are not yet supported in the in-process transport\")\n\t\t_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\treturn\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_OpenFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_OpenFile_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_OpenFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"DELETE\", pattern_SpaceApi_RemoveDirOrFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_RemoveDirOrFile_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RemoveDirOrFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GeneratePublicFileLink_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GeneratePublicFileLink_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GeneratePublicFileLink_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetSharedWithMeFiles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetSharedWithMeFiles_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetSharedWithMeFiles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetSharedByMeFiles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetSharedByMeFiles_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetSharedByMeFiles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_OpenPublicFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_OpenPublicFile_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_OpenPublicFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_AddItems_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\terr := status.Error(codes.Unimplemented, \"streaming calls are not yet supported in the in-process transport\")\n\t\t_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\treturn\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_CreateFolder_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_CreateFolder_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_CreateFolder_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ToggleFuseDrive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ToggleFuseDrive_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ToggleFuseDrive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetFuseDriveStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetFuseDriveStatus_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetFuseDriveStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_CreateBucket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_CreateBucket_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_CreateBucket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_BackupKeysByPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_BackupKeysByPassphrase_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_BackupKeysByPassphrase_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_RecoverKeysByPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_RecoverKeysByPassphrase_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RecoverKeysByPassphrase_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_TestKeysPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_TestKeysPassphrase_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_TestKeysPassphrase_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_CreateLocalKeysBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_CreateLocalKeysBackup_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_CreateLocalKeysBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_RecoverKeysByLocalBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_RecoverKeysByLocalBackup_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RecoverKeysByLocalBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ShareBucket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ShareBucket_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ShareBucket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_JoinBucket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_JoinBucket_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_JoinBucket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ShareFilesViaPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ShareFilesViaPublicKey_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ShareFilesViaPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_UnshareFilesViaPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_UnshareFilesViaPublicKey_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_UnshareFilesViaPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_HandleFilesInvitation_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_HandleFilesInvitation_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_HandleFilesInvitation_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_NotificationSubscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\terr := status.Error(codes.Unimplemented, \"streaming calls are not yet supported in the in-process transport\")\n\t\t_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\treturn\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_ListBuckets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ListBuckets_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ListBuckets_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetNotifications_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetNotifications_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetNotifications_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ReadNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ReadNotification_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ReadNotification_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_DeleteAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_DeleteAccount_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_DeleteAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ToggleBucketBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_ToggleBucketBackup_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ToggleBucketBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_BucketBackupRestore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_BucketBackupRestore_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_BucketBackupRestore_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetUsageInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetUsageInfo_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetUsageInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetAPISessionTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetAPISessionTokens_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetAPISessionTokens_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetRecentlySharedWith_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GetRecentlySharedWith_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetRecentlySharedWith_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_SetNotificationsLastSeenAt_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_SetNotificationsLastSeenAt_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_SetNotificationsLastSeenAt_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_SearchFiles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_SearchFiles_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_SearchFiles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_InitializeMasterAppToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_InitializeMasterAppToken_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_InitializeMasterAppToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GenerateAppToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_SpaceApi_GenerateAppToken_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GenerateAppToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\treturn nil\n}\n\n// RegisterSpaceApiHandlerFromEndpoint is same as RegisterSpaceApiHandler but\n// automatically dials to \"endpoint\" and closes the connection when \"ctx\" gets done.\nfunc RegisterSpaceApiHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {\n\tconn, err := grpc.Dial(endpoint, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tif cerr := conn.Close(); cerr != nil {\n\t\t\t\tgrpclog.Infof(\"Failed to close conn to %s: %v\", endpoint, cerr)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tgo func() {\n\t\t\t<-ctx.Done()\n\t\t\tif cerr := conn.Close(); cerr != nil {\n\t\t\t\tgrpclog.Infof(\"Failed to close conn to %s: %v\", endpoint, cerr)\n\t\t\t}\n\t\t}()\n\t}()\n\n\treturn RegisterSpaceApiHandler(ctx, mux, conn)\n}\n\n// RegisterSpaceApiHandler registers the http handlers for service SpaceApi to \"mux\".\n// The handlers forward requests to the grpc endpoint over \"conn\".\nfunc RegisterSpaceApiHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {\n\treturn RegisterSpaceApiHandlerClient(ctx, mux, NewSpaceApiClient(conn))\n}\n\n// RegisterSpaceApiHandlerClient registers the http handlers for service SpaceApi\n// to \"mux\". The handlers forward requests to the grpc endpoint over the given implementation of \"SpaceApiClient\".\n// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in \"SpaceApiClient\"\n// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in\n// \"SpaceApiClient\" to call the correct interceptors.\nfunc RegisterSpaceApiHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SpaceApiClient) error {\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_ListDirectories_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ListDirectories_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ListDirectories_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_ListDirectory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ListDirectory_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ListDirectory_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GenerateKeyPair_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GenerateKeyPair_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GenerateKeyPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetStoredMnemonic_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetStoredMnemonic_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetStoredMnemonic_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_RestoreKeyPairViaMnemonic_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_RestoreKeyPairViaMnemonic_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RestoreKeyPairViaMnemonic_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_DeleteKeyPair_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_DeleteKeyPair_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_DeleteKeyPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GenerateKeyPairWithForce_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GenerateKeyPairWithForce_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GenerateKeyPairWithForce_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GetPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetPublicKey_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_Subscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_Subscribe_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_Subscribe_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_TxlSubscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_TxlSubscribe_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_TxlSubscribe_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_OpenFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_OpenFile_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_OpenFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"DELETE\", pattern_SpaceApi_RemoveDirOrFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_RemoveDirOrFile_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RemoveDirOrFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GeneratePublicFileLink_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GeneratePublicFileLink_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GeneratePublicFileLink_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetSharedWithMeFiles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetSharedWithMeFiles_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetSharedWithMeFiles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetSharedByMeFiles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetSharedByMeFiles_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetSharedByMeFiles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_OpenPublicFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_OpenPublicFile_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_OpenPublicFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_AddItems_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_AddItems_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_AddItems_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_CreateFolder_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_CreateFolder_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_CreateFolder_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ToggleFuseDrive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ToggleFuseDrive_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ToggleFuseDrive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetFuseDriveStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetFuseDriveStatus_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetFuseDriveStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_CreateBucket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_CreateBucket_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_CreateBucket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_BackupKeysByPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_BackupKeysByPassphrase_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_BackupKeysByPassphrase_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_RecoverKeysByPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_RecoverKeysByPassphrase_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RecoverKeysByPassphrase_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_TestKeysPassphrase_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_TestKeysPassphrase_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_TestKeysPassphrase_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_CreateLocalKeysBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_CreateLocalKeysBackup_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_CreateLocalKeysBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_RecoverKeysByLocalBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_RecoverKeysByLocalBackup_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_RecoverKeysByLocalBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ShareBucket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ShareBucket_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ShareBucket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_JoinBucket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_JoinBucket_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_JoinBucket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ShareFilesViaPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ShareFilesViaPublicKey_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ShareFilesViaPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_UnshareFilesViaPublicKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_UnshareFilesViaPublicKey_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_UnshareFilesViaPublicKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_HandleFilesInvitation_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_HandleFilesInvitation_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_HandleFilesInvitation_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_NotificationSubscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_NotificationSubscribe_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_NotificationSubscribe_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_ListBuckets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ListBuckets_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ListBuckets_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetNotifications_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetNotifications_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetNotifications_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ReadNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ReadNotification_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ReadNotification_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_DeleteAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_DeleteAccount_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_DeleteAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_ToggleBucketBackup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_ToggleBucketBackup_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_ToggleBucketBackup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_BucketBackupRestore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_BucketBackupRestore_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_BucketBackupRestore_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetUsageInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetUsageInfo_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetUsageInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetAPISessionTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetAPISessionTokens_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetAPISessionTokens_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_GetRecentlySharedWith_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GetRecentlySharedWith_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GetRecentlySharedWith_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_SetNotificationsLastSeenAt_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_SetNotificationsLastSeenAt_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_SetNotificationsLastSeenAt_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_SpaceApi_SearchFiles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_SearchFiles_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_SearchFiles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_InitializeMasterAppToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_InitializeMasterAppToken_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_InitializeMasterAppToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"POST\", pattern_SpaceApi_GenerateAppToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_SpaceApi_GenerateAppToken_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_SpaceApi_GenerateAppToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\treturn nil\n}\n\nvar (\n\tpattern_SpaceApi_ListDirectories_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"directories\", \"all\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ListDirectory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"directories\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GenerateKeyPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"keypairs\", \"generate\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetStoredMnemonic_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"keypairs\", \"mnemonic\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_RestoreKeyPairViaMnemonic_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"keypairs\", \"restoreWithMnemonic\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_DeleteKeyPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"keypairs\", \"delete\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GenerateKeyPairWithForce_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"keypairs\", \"forceGenerate\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetPublicKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"publicKey\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_Subscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"subscriptions\", \"file\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_TxlSubscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"subscriptions\", \"textile\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_OpenFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"files\", \"open\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_RemoveDirOrFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"files\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GeneratePublicFileLink_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{\"v1\", \"buckets\", \"bucket\", \"generatePublicFileLink\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetSharedWithMeFiles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"files\", \"sharedWithMe\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetSharedByMeFiles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"files\", \"sharedByMe\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_OpenPublicFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"files\", \"openPublic\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_AddItems_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"files\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_CreateFolder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"directories\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ToggleFuseDrive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"toggleFuse\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetFuseDriveStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"fuse\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_CreateBucket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"buckets\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_BackupKeysByPassphrase_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"passphrases\", \"backup\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_RecoverKeysByPassphrase_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"passphrases\", \"recover\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_TestKeysPassphrase_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"passphrases\", \"test\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_CreateLocalKeysBackup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"localBackups\", \"backup\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_RecoverKeysByLocalBackup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"localBackups\", \"recover\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ShareBucket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{\"v1\", \"buckets\", \"bucket\", \"share\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_JoinBucket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{\"v1\", \"buckets\", \"bucket\", \"join\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ShareFilesViaPublicKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"shareFilesViaPublicKey\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_UnshareFilesViaPublicKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"unshareFilesViaPublicKey\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_HandleFilesInvitation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{\"v1\", \"filesinvitation\", \"invitationID\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_NotificationSubscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"subscriptions\", \"notification\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ListBuckets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"buckets\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetNotifications_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"notifications\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ReadNotification_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{\"v1\", \"notifications\", \"ID\", \"read\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_DeleteAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"deleteAccount\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_ToggleBucketBackup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"backup\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_BucketBackupRestore_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"backup\", \"restore\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetUsageInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"usage\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetAPISessionTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"apiSessionTokens\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GetRecentlySharedWith_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"sharedWithList\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_SetNotificationsLastSeenAt_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"notifications\", \"lastSeenAt\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_SearchFiles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"search\", \"files\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_InitializeMasterAppToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{\"v1\", \"appTokens\", \"master\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_SpaceApi_GenerateAppToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"appTokens\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n)\n\nvar (\n\tforward_SpaceApi_ListDirectories_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_ListDirectory_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GenerateKeyPair_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetStoredMnemonic_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_RestoreKeyPairViaMnemonic_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_DeleteKeyPair_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GenerateKeyPairWithForce_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetPublicKey_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_Subscribe_0 = runtime.ForwardResponseStream\n\n\tforward_SpaceApi_TxlSubscribe_0 = runtime.ForwardResponseStream\n\n\tforward_SpaceApi_OpenFile_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_RemoveDirOrFile_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GeneratePublicFileLink_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetSharedWithMeFiles_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetSharedByMeFiles_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_OpenPublicFile_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_AddItems_0 = runtime.ForwardResponseStream\n\n\tforward_SpaceApi_CreateFolder_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_ToggleFuseDrive_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetFuseDriveStatus_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_CreateBucket_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_BackupKeysByPassphrase_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_RecoverKeysByPassphrase_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_TestKeysPassphrase_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_CreateLocalKeysBackup_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_RecoverKeysByLocalBackup_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_ShareBucket_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_JoinBucket_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_ShareFilesViaPublicKey_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_UnshareFilesViaPublicKey_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_HandleFilesInvitation_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_NotificationSubscribe_0 = runtime.ForwardResponseStream\n\n\tforward_SpaceApi_ListBuckets_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetNotifications_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_ReadNotification_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_DeleteAccount_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_ToggleBucketBackup_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_BucketBackupRestore_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetUsageInfo_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetAPISessionTokens_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GetRecentlySharedWith_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_SetNotificationsLastSeenAt_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_SearchFiles_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_InitializeMasterAppToken_0 = runtime.ForwardResponseMessage\n\n\tforward_SpaceApi_GenerateAppToken_0 = runtime.ForwardResponseMessage\n)\n"
  },
  {
    "path": "grpc/proto/space.proto",
    "content": "syntax = \"proto3\";\n\n\nimport \"google/protobuf/empty.proto\";\nimport \"google/api/annotations.proto\";\n\npackage space;\n\noption go_package = \".;pb\";\n\n//See here for more info about the google.api.http spec: https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L46\n\n// SpaceApi service\nservice SpaceApi {\n  // Get all folder or files in the default bucket. It fetches all subdirectories too.\n  rpc ListDirectories(ListDirectoriesRequest) returns (ListDirectoriesResponse) {\n    option (google.api.http) = {\n      get: \"/v1/directories/all\"\n    };\n  }\n\n  // Get the folder or files in the path directory.\n  // Unlike ListDirectories, this only returns immediate children at path.\n  rpc ListDirectory(ListDirectoryRequest) returns (ListDirectoryResponse) {\n    option (google.api.http) = {\n      get: \"/v1/directories\"\n    };\n  }\n\n  // Generate Key Pair for current account.\n  // This will return error if daemon account already has keypairs\n  rpc GenerateKeyPair(GenerateKeyPairRequest) returns (GenerateKeyPairResponse) {\n    option (google.api.http) = {\n      post: \"/v1/keypairs/generate\"\n      body: \"*\"\n    };\n  }\n\n  rpc GetStoredMnemonic(GetStoredMnemonicRequest) returns (GetStoredMnemonicResponse) {\n    option (google.api.http) = {\n      get: \"/v1/keypairs/mnemonic\"\n    };\n  }\n\n  // Restores a keypair given a mnemonic.\n  // This will override any existing key pair\n  rpc RestoreKeyPairViaMnemonic(RestoreKeyPairViaMnemonicRequest) returns (RestoreKeyPairViaMnemonicResponse) {\n    option (google.api.http) = {\n      post: \"/v1/keypairs/restoreWithMnemonic\"\n      body: \"*\"\n    };\n  }\n\n  rpc DeleteKeyPair(DeleteKeyPairRequest) returns (DeleteKeyPairResponse) {\n    option (google.api.http) = {\n      post: \"/v1/keypairs/delete\"\n      body: \"*\"\n    };\n  }\n\n  // Force Generation of KeyPair. This will override existing keys stored in daemon.\n  rpc GenerateKeyPairWithForce(GenerateKeyPairRequest) returns (GenerateKeyPairResponse) {\n    option (google.api.http) = {\n      post: \"/v1/keypairs/forceGenerate\"\n      body: \"*\"\n    };\n  }\n\n  rpc GetPublicKey(GetPublicKeyRequest) returns (GetPublicKeyResponse) {\n    option (google.api.http) = {\n      post: \"/v1/publicKey\"\n      body: \"*\"\n    };\n  }\n\n  // Subscribe to file events. This streams responses to the caller\n  rpc Subscribe(google.protobuf.Empty) returns (stream FileEventResponse) {\n    option (google.api.http) = {\n      get: \"/v1/subscriptions/file\"\n    };\n  }\n\n  // Subscribe to textile events. This streams responses to the caller\n  rpc TxlSubscribe(google.protobuf.Empty) returns (stream TextileEventResponse) {\n    option (google.api.http) = {\n      get: \"/v1/subscriptions/textile\"\n    };\n  }\n\n  // Open a file in the daemon.\n  // Daemon keeps track of all open files and closes them if no activity is noticed after a while\n  rpc OpenFile(OpenFileRequest) returns (OpenFileResponse) {\n    option (google.api.http) = {\n      post: \"/v1/files/open\"\n      body: \"*\"\n    };\n  }\n\n  // Removes a file or dir from a bucket\n  rpc RemoveDirOrFile(RemoveDirOrFileRequest) returns (RemoveDirOrFileResponse) {\n    option (google.api.http) = {\n      delete: \"/v1/files\"\n    };\n  }\n\n  // Generates a copy of the file that's accessible through IPFS gateways\n  rpc GeneratePublicFileLink(GeneratePublicFileLinkRequest) returns (GeneratePublicFileLinkResponse) {\n    option (google.api.http) = {\n      post: \"/v1/buckets/{bucket}/generatePublicFileLink\"\n      body: \"*\"\n    };\n  }\n\n  // Gets the files that are shared with this recipient\n  rpc GetSharedWithMeFiles(GetSharedWithMeFilesRequest) returns (GetSharedWithMeFilesResponse) {\n    option (google.api.http) = {\n      get: \"/v1/files/sharedWithMe\"\n    };\n  }\n\n  // Gets the files that are shared by the sender\n  rpc GetSharedByMeFiles(GetSharedByMeFilesRequest) returns (GetSharedByMeFilesResponse) {\n    option (google.api.http) = {\n      get: \"/v1/files/sharedByMe\"\n    };\n  }\n\n  // Open an encrypted public shared file in the daemon.\n  // This requires the decryption key and file hash/cid to work\n  rpc OpenPublicFile(OpenPublicFileRequest) returns (OpenPublicFileResponse) {\n    option (google.api.http) = {\n      get: \"/v1/files/openPublic\"\n    };\n  }\n\n  // Adds items (files/folders) to be uploaded to the bucket.\n  rpc AddItems(AddItemsRequest) returns (stream AddItemsResponse) {\n    option (google.api.http) = {\n      post: \"/v1/files\"\n      body: \"*\"\n    };\n  }\n\n  // Creates a folder/directory at the specified path\n  rpc CreateFolder(CreateFolderRequest) returns (CreateFolderResponse) {\n    option (google.api.http) = {\n      post: \"/v1/directories\"\n      body: \"*\"\n    };\n  }\n\n  // Toggle FUSE drive to be mounted or unmounted\n  rpc ToggleFuseDrive(ToggleFuseRequest) returns (FuseDriveResponse) {\n    option (google.api.http) = {\n      post: \"/v1/toggleFuse\"\n      body: \"*\"\n    };\n  }\n\n  // Get status of FUSE drive. If mounted or unmounted\n  rpc GetFuseDriveStatus(google.protobuf.Empty) returns (FuseDriveResponse) {\n    option (google.api.http) = {\n      get: \"/v1/fuse\"\n    };\n  }\n\n  // Create a new bucket owned by current user (aka keypair)\n  rpc CreateBucket(CreateBucketRequest) returns (CreateBucketResponse) {\n    option (google.api.http) = {\n      post: \"/v1/buckets\"\n      body: \"*\"\n    };\n  }\n\n  // Backup Key by Passphrase\n  rpc BackupKeysByPassphrase(BackupKeysByPassphraseRequest) returns (BackupKeysByPassphraseResponse) {\n    option (google.api.http) = {\n      post: \"/v1/passphrases/backup\"\n      body: \"*\"\n    };\n  }\n\n  // Recover Keys by Passphrase\n  rpc RecoverKeysByPassphrase(RecoverKeysByPassphraseRequest) returns (RecoverKeysByPassphraseResponse) {\n    option (google.api.http) = {\n      post: \"/v1/passphrases/recover\"\n      body: \"*\"\n    };\n  }\n\n  // Tests a passphrase to see if it matches the one previously used\n  rpc TestKeysPassphrase(TestKeysPassphraseRequest) returns (TestKeysPassphraseResponse) {\n    option (google.api.http) = {\n      post: \"/v1/passphrases/test\"\n      body: \"*\"\n    };\n  }\n\n  rpc CreateLocalKeysBackup(CreateLocalKeysBackupRequest) returns (CreateLocalKeysBackupResponse) {\n    option (google.api.http) = {\n      post: \"/v1/localBackups/backup\"\n      body: \"*\"\n    };\n  }\n\n  rpc RecoverKeysByLocalBackup(RecoverKeysByLocalBackupRequest) returns (RecoverKeysByLocalBackupResponse) {\n    option (google.api.http) = {\n      post: \"/v1/localBackups/recover\"\n      body: \"*\"\n    };\n  }\n\n  // Share bucket\n  rpc ShareBucket(ShareBucketRequest) returns (ShareBucketResponse) {\n    option (google.api.http) = {\n      post: \"/v1/buckets/{bucket}/share\"\n      body: \"*\"\n    };\n  }\n\n  // Join bucket\n  rpc JoinBucket(JoinBucketRequest) returns (JoinBucketResponse) {\n    option (google.api.http) = {\n      post: \"/v1/buckets/{bucket}/join\"\n      body: \"*\"\n    };\n  }\n\n  // Share bucket via public key using Textile Hub inboxing\n  rpc ShareFilesViaPublicKey(ShareFilesViaPublicKeyRequest) returns (ShareFilesViaPublicKeyResponse) {\n    option (google.api.http) = {\n      post: \"/v1/shareFilesViaPublicKey\"\n      body: \"*\"\n    };\n  }\n\n  // Remove public keys for shared files in buckets\n  rpc UnshareFilesViaPublicKey(UnshareFilesViaPublicKeyRequest) returns (UnshareFilesViaPublicKeyResponse) {\n    option (google.api.http) = {\n      post: \"/v1/unshareFilesViaPublicKey\"\n      body: \"*\"\n    };\n  }\n\n  rpc HandleFilesInvitation(HandleFilesInvitationRequest) returns (HandleFilesInvitationResponse) {\n    option (google.api.http) = {\n      post: \"/v1/filesinvitation/{invitationID}\"\n      body: \"*\"\n    };\n  }\n\n  rpc NotificationSubscribe(google.protobuf.Empty) returns (stream NotificationEventResponse) {\n    option (google.api.http) = {\n      get: \"/v1/subscriptions/notification\"\n    };\n  }\n\n  rpc ListBuckets(ListBucketsRequest) returns (ListBucketsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/buckets\"\n    };\n  }\n\n  rpc GetNotifications(GetNotificationsRequest) returns (GetNotificationsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/notifications\"\n    };\n  }\n\n\n  rpc ReadNotification(ReadNotificationRequest) returns (ReadNotificationResponse) {\n    option (google.api.http) = {\n      post: \"/v1/notifications/{ID}/read\"\n      body: \"*\"\n    };\n  }\n\n  rpc DeleteAccount(DeleteAccountRequest) returns (DeleteAccountResponse) {\n    option (google.api.http) = {\n      post: \"/v1/deleteAccount\"\n      body: \"*\"\n    };\n  }\n\n  rpc ToggleBucketBackup(ToggleBucketBackupRequest) returns (ToggleBucketBackupResponse) {\n    option (google.api.http) = {\n      post: \"/v1/backup\"\n      body: \"*\"\n    };\n  }\n\n  rpc BucketBackupRestore(BucketBackupRestoreRequest) returns (BucketBackupRestoreResponse) {\n    option (google.api.http) = {\n      post: \"/v1/backup/restore\"\n      body: \"*\"\n    };\n  }\n\n  rpc GetUsageInfo(GetUsageInfoRequest) returns (GetUsageInfoResponse) {\n    option (google.api.http) = {\n      get: \"/v1/usage\"\n    };\n  }\n\n  rpc GetAPISessionTokens(GetAPISessionTokensRequest) returns (GetAPISessionTokensResponse) {\n    option (google.api.http) = {\n      get: \"/v1/apiSessionTokens\"\n    };\n  }\n\n  // Returns a list of addresses / public keys of clients to which files where shared or received, ordered by date\n  rpc GetRecentlySharedWith(GetRecentlySharedWithRequest) returns (GetRecentlySharedWithResponse) {\n    option (google.api.http) = {\n      get: \"/v1/sharedWithList\"\n    };\n  }\n\n  // This will set the last read timestamp for the user so that the client\n  // can check if newer notifications are present for UX\n  rpc SetNotificationsLastSeenAt(SetNotificationsLastSeenAtRequest) returns (SetNotificationsLastSeenAtResponse) {\n    option (google.api.http) = {\n      post: \"/v1/notifications/lastSeenAt\"\n      body: \"*\"\n    };\n  }\n\n  // Search for files across all users bucket\n  rpc SearchFiles(SearchFilesRequest) returns (SearchFilesResponse) {\n    option (google.api.http) = {\n      get: \"/v1/search/files\"\n    };\n  }\n\n  // Initialize master app token\n  // App tokens are used to authorize scoped access to a range of methods\n  // Master token can only be generated once and has access to all methods\n  rpc InitializeMasterAppToken(InitializeMasterAppTokenRequest) returns (InitializeMasterAppTokenResponse) {\n    option (google.api.http) = {\n      post: \"/v1/appTokens/master\"\n      body: \"*\"\n    };\n  }\n\n  // Generates an app token with scoped access.\n  rpc GenerateAppToken(GenerateAppTokenRequest) returns (GenerateAppTokenResponse) {\n    option (google.api.http) = {\n      post: \"/v1/appTokens\"\n      body: \"*\"\n    };\n  }\n}\n\nmessage SearchFilesRequest {\n  string query = 1;\n}\n\nmessage SearchFilesResponse {\n  repeated SearchFilesDirectoryEntry entries = 1;\n  string query = 2;\n}\n\nmessage SearchFilesDirectoryEntry {\n  ListDirectoryEntry entry = 1;\n  string dbId = 2;\n  string bucket = 3;\n}\n\nmessage SetNotificationsLastSeenAtRequest {\n  int64 timestamp = 1;\n}\n\nmessage SetNotificationsLastSeenAtResponse {}\n\nmessage GetSharedWithMeFilesRequest {\n  string seek = 1;\n  int64 limit = 2;\n}\n\nmessage GetSharedWithMeFilesResponse {\n  repeated SharedListDirectoryEntry items = 1;\n  string nextOffset = 2;\n}\n\nmessage GetSharedByMeFilesRequest {\n  string seek = 1;\n  int64 limit = 2;\n}\n\nmessage GetSharedByMeFilesResponse {\n  repeated SharedListDirectoryEntry items = 1;\n  string nextOffset = 2;\n}\n\nmessage GetUsageInfoRequest {}\n\nmessage GetUsageInfoResponse {\n  uint64 localStarogeUsed = 1;\n  uint64 localBandwidthUsed = 2;\n  uint64 spaceStorageUsed = 3;\n  uint64 spaceBandwidthUsed = 4;\n  uint64 usageQuota = 5;\n}\n\nmessage ToggleBucketBackupRequest {\n  string bucket = 1;\n  bool backup = 2;\n}\n\nmessage ToggleBucketBackupResponse {}\n\nmessage BucketBackupRestoreRequest {\n  string bucket = 1;\n}\n\nmessage BucketBackupRestoreResponse {}\n\nmessage ListDirectoriesRequest {\n  string bucket = 1;\n  bool omitMembers = 2;\n}\n\nmessage FileMember {\n  string publicKey = 1;\n  string address = 2;\n}\n\nmessage ListDirectoryEntry {\n  string path = 1;\n  bool isDir = 2;\n  string name = 3;\n  string sizeInBytes = 4;\n  string created = 5;\n  string updated = 6;\n  string fileExtension = 7;\n  string ipfsHash = 8;\n  bool isLocallyAvailable = 9;\n  int64 backupCount = 10;\n  repeated FileMember members = 11;\n  bool isBackupInProgress = 12;\n  bool isRestoreInProgress = 13;\n}\n\nmessage SharedListDirectoryEntry {\n  ListDirectoryEntry entry = 1;\n  string dbId = 2;\n  string bucket = 3;\n  bool isPublicLink = 4;\n  string sharedBy = 5;\n}\n\nmessage ListDirectoriesResponse {\n  repeated ListDirectoryEntry entries = 1;\n}\n\nmessage ListDirectoryRequest {\n  string path = 1;\n  string bucket = 2;\n  bool omitMembers = 3;\n}\n\nmessage ListDirectoryResponse {\n  repeated ListDirectoryEntry entries = 1;\n}\n\nmessage CreateBucketRequest {\n  string slug = 1;\n}\n\nmessage BucketMember {\n  string address = 1;\n  string publicKey = 2;\n  bool isOwner = 3;\n  bool hasJoined = 4;\n}\n\nmessage Bucket {\n  string key = 1;\n  string name = 2;\n  string path = 3;\n  int64 createdAt = 4;\n  int64 updatedAt = 5;\n  repeated BucketMember members = 6;\n  bool isPersonalBucket = 7;\n  bool isBackupEnabled = 8;\n  int32 itemsCount = 9;\n}\n\nmessage CreateBucketResponse {\n  Bucket bucket = 1;\n}\n\nmessage GenerateKeyPairRequest {}\n\nmessage GenerateKeyPairResponse {\n  string mnemonic = 1;\n}\n\nmessage GetStoredMnemonicRequest {}\n\nmessage GetStoredMnemonicResponse {\n  string mnemonic = 1;\n}\n\nmessage RestoreKeyPairViaMnemonicRequest {\n  string mnemonic = 1;\n}\n\nmessage RestoreKeyPairViaMnemonicResponse {}\n\nenum EventType {\n  ENTRY_ADDED = 0;\n  ENTRY_DELETED = 1;\n  ENTRY_UPDATED = 2;\n  ENTRY_BACKUP_IN_PROGRESS = 3;\n  ENTRY_BACKUP_READY = 4;\n  ENTRY_RESTORE_IN_PROGRESS = 5;\n  ENTRY_RESTORE_READY = 6;\n  FOLDER_ADDED = 7;\n  FOLDER_DELETED = 8;\n  FOLDER_UPDATED = 9;\n}\n\nmessage FileEventResponse {\n  EventType type = 1;\n  ListDirectoryEntry entry = 2;\n  string bucket = 3;\n  string dbId = 4;\n}\n\nmessage TextileEventResponse {\n  string bucket = 1;\n}\n\nmessage OpenFileRequest {\n  string path = 1;\n  string bucket = 2;\n  string dbId = 3; // optional field to specify shared with me file\n}\n\nmessage OpenFileResponse {\n  string location = 1;\n}\n\nmessage OpenPublicFileRequest {\n  string fileCid = 1;\n  string password = 2;\n  string filename = 3;\n}\n\nmessage OpenPublicFileResponse {\n  string location = 1;\n}\n\nmessage AddItemsRequest {\n  // full paths to file or Folder on FS. Needs to be a location available to the daemon\n  repeated string sourcePaths = 1;\n  // target path in bucket.\n  string targetPath = 2;\n  // The bucket in which to save the item\n  string bucket = 3;\n}\n\nmessage AddItemResult {\n  string sourcePath= 1;\n  string bucketPath = 2;\n  string error = 3;\n}\n\nmessage AddItemsResponse {\n  AddItemResult result = 1;\n  int64 totalFiles = 2;\n  int64 totalBytes = 3;\n  int64 completedFiles = 4;\n  int64 completedBytes = 5;\n}\n\nmessage CreateFolderRequest {\n  // target path in bucket to add new empty folder\n  string path = 1;\n  // The bucket in which to add the folder\n  string bucket = 2;\n}\n// not sure we need to return anything other than an error if we failed\nmessage CreateFolderResponse {\n}\n\nenum KeyBackupType {\n  PASSWORD = 0;\n  GOOGLE = 1;\n  TWITTER = 2;\n  EMAIL = 3;\n}\n\nmessage BackupKeysByPassphraseRequest {\n  string uuid = 1;\n  string passphrase = 2;\n  KeyBackupType type = 3;\n}\n\nmessage BackupKeysByPassphraseResponse {}\n\nmessage RecoverKeysByPassphraseRequest {\n  string uuid = 1;\n  string passphrase = 2;\n  KeyBackupType type = 3;\n}\n\nmessage RecoverKeysByPassphraseResponse {}\n\nmessage TestKeysPassphraseRequest {\n  string uuid = 1;\n  string passphrase = 2;\n}\n\nmessage TestKeysPassphraseResponse {}\n\nmessage ThreadInfo {\n  repeated string addresses = 1;\n  string key = 2;\n}\n\nmessage ShareBucketRequest {\n  string bucket = 1;\n}\n\nmessage ShareBucketResponse {\n  ThreadInfo threadinfo = 1;\n}\n\nmessage JoinBucketRequest {\n  ThreadInfo threadinfo = 1;\n  string bucket = 2;\n}\n\nmessage JoinBucketResponse {\n  bool result = 1;\n}\n\n\nmessage ShareFilesViaPublicKeyRequest {\n  repeated string publicKeys = 1;\n  repeated FullPath paths = 2;\n}\n\nmessage FullPath {\n  string dbId = 1; // optional field to specify shared with me file\n  string bucket = 2;\n  string path = 3;\n}\n\nmessage ShareFilesViaPublicKeyResponse {}\n\nmessage UnshareFilesViaPublicKeyRequest {\n  repeated string publicKeys = 1;\n  repeated FullPath paths = 2;\n}\n\nmessage UnshareFilesViaPublicKeyResponse {}\n\nmessage GeneratePublicFileLinkRequest {\n  string bucket = 1;\n  repeated string itemPaths = 2;\n  string password = 3;\n  // optional field to specify db id\n  // for shared with me files\n  string dbId = 4;\n}\n\nmessage GeneratePublicFileLinkResponse {\n  string link = 1;\n  string fileCid = 2;\n}\n\nmessage ToggleFuseRequest {\n  bool mountDrive = 1;\n}\n\nenum FuseState {\n  UNSUPPORTED = 0;\n  NOT_INSTALLED = 1;\n  UNMOUNTED = 2;\n  MOUNTED = 3;\n}\n\nmessage FuseDriveResponse {\n  FuseState state = 1;\n  string mountPath = 2;\n}\n\nmessage ListBucketsRequest {}\n\nmessage ListBucketsResponse {\n  repeated Bucket buckets = 1;\n}\n\nenum NotificationType {\n  UNKNOWN = 0;\n  INVITATION = 1;\n  USAGEALERT = 2;\n  INVITATION_REPLY = 3;\n  REVOKED_INVITATION = 4;\n}\n\nenum InvitationStatus {\n  PENDING = 0;\n  ACCEPTED = 1;\n  REJECTED = 2;\n}\n\nmessage Invitation {\n  string inviterPublicKey = 1;\n  string invitationID = 2;\n  InvitationStatus status = 4;\n  repeated FullPath itemPaths = 5;\n}\n\nmessage UsageAlert {\n  int64 used = 1;\n  int64 limit = 2;\n  string message = 3;\n}\n\nmessage InvitationAccept {\n  string invitationID = 2;\n}\n\nmessage RevokedInvitation {\n  string inviterPublicKey = 1;\n  repeated FullPath itemPaths = 5;\n}\n\nmessage Notification {\n  string ID = 1; // underlying message id from textile\n  string subject = 2;\n  string body = 3;\n  oneof relatedObject {\n    Invitation invitationValue = 4;\n    UsageAlert usageAlert = 5;\n    InvitationAccept invitationAccept = 6;\n    RevokedInvitation revokedInvitation = 7;\n  }\n  NotificationType type = 8;\n  int64 createdAt = 9;\n  int64 readAt = 10;\n}\n\nmessage HandleFilesInvitationRequest {\n  string invitationID = 1;\n  bool accept = 2;\n}\n\nmessage HandleFilesInvitationResponse {}\n\nmessage NotificationEventResponse {\n  Notification notification = 1;\n}\n\nmessage GetNotificationsRequest {\n  string seek = 1;\n  int64 limit = 2;\n}\n\nmessage GetNotificationsResponse {\n  repeated Notification notifications= 1;\n  string nextOffset = 2;\n  int64 lastSeenAt = 3;\n}\nmessage ReadNotificationRequest {\n  string ID = 1;\n}\n\nmessage ReadNotificationResponse {\n}\n\nmessage GetPublicKeyRequest {}\n\nmessage GetPublicKeyResponse {\n  // Public key encoded in hex\n  string publicKey = 1;\n}\n\nmessage RecoverKeysByLocalBackupRequest {\n  string pathToKeyBackup = 1;\n}\n\nmessage RecoverKeysByLocalBackupResponse {}\n\nmessage CreateLocalKeysBackupRequest {\n  // The path in which to save the backup\n  string pathToKeyBackup = 1;\n}\n\nmessage CreateLocalKeysBackupResponse {}\n\nmessage DeleteAccountRequest {}\n\nmessage DeleteAccountResponse {}\n\nmessage DeleteKeyPairRequest {}\n\nmessage DeleteKeyPairResponse {}\n\nmessage GetAPISessionTokensRequest {}\n\nmessage GetAPISessionTokensResponse {\n  string hubToken = 1;\n  string servicesToken = 2;\n}\n\nmessage GetRecentlySharedWithRequest {}\n\nmessage GetRecentlySharedWithResponse {\n repeated FileMember members = 1;\n}\n\nmessage InitializeMasterAppTokenRequest {}\n\nmessage InitializeMasterAppTokenResponse {\n  string appToken = 1;\n}\n\nmessage AllowedMethod {\n  string methodName = 1;\n}\n\nmessage GenerateAppTokenRequest {\n  repeated AllowedMethod allowedMethods = 1;\n}\n\nmessage GenerateAppTokenResponse {\n  string appToken = 1;\n}\n\nmessage RemoveDirOrFileRequest {\n  string path = 1;\n  string bucket = 2;\n}\n\nmessage RemoveDirOrFileResponse {}"
  },
  {
    "path": "integration_tests/README.md",
    "content": "### Integration Testing Guide\n\n#### Fixtures\nFixtures module contains test fixtures to setup and teardown tests and perform some actions\n\n#### Helpers\nHelpers modules contains helper function for performing actions and also some assertions. \nCustom assertions should be created to make tests more readable and also prevent duplication of assertion logic. "
  },
  {
    "path": "integration_tests/fixtures/app.go",
    "content": "package fixtures\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n\n\t\"github.com/FleekHQ/space-daemon/core/keychain\"\n\n\t\"github.com/99designs/keyring\"\n\n\t\"github.com/FleekHQ/space-daemon/app\"\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t. \"github.com/onsi/gomega\"\n)\n\ntype RunAppCtx struct {\n\tApp            *app.App\n\tcfg            config.Config\n\tclient         pb.SpaceApiClient\n\tClientAppToken string\n\tClientMnemonic string\n}\n\nfunc RunApp() *RunAppCtx {\n\t_, cfg, env := GetTestConfig()\n\tspaceApp := app.New(cfg, env)\n\terr := spaceApp.Start()\n\n\tExpectWithOffset(1, err).NotTo(HaveOccurred(), \"space app failed to start\")\n\tExpectWithOffset(1, spaceApp.IsRunning).To(Equal(true), \"spaceApp.IsRunning should be true\")\n\n\treturn &RunAppCtx{\n\t\tApp:    spaceApp,\n\t\tcfg:    cfg,\n\t\tclient: nil,\n\t}\n}\n\n// RunAppWithClientAppToken creates an instance of RunAppCtx for test but with the\n// ClientAppToken already set\nfunc RunAppWithClientAppToken(appToken string) *RunAppCtx {\n\tnewApp := RunApp()\n\tnewApp.ClientAppToken = appToken\n\treturn newApp\n}\n\nfunc (a *RunAppCtx) Shutdown() {\n\tif a.App != nil {\n\t\t// shutdown app\n\t\terr := a.App.Shutdown()\n\t\tif err != nil {\n\t\t\tlog.Error(\"Failed to shutdown app in test\", err)\n\t\t}\n\n\t\tspaceStorePath := a.cfg.GetString(config.SpaceStorePath, \"\")\n\t\tbuckdPath := a.cfg.GetString(config.BuckdPath, \"\")\n\n\t\t// delete app dir\n\t\t_ = os.RemoveAll(spaceStorePath)\n\t\t_ = os.RemoveAll(buckdPath)\n\t}\n}\n\nfunc (a *RunAppCtx) ClearMasterAppToken() {\n\tspaceStorePath := a.cfg.GetString(config.SpaceStorePath, \"\")\n\n\t// clear master token from keystore\n\tucd, _ := os.UserConfigDir()\n\tring, err := keyring.Open(keyring.Config{\n\t\tServiceName:                    \"space\",\n\t\tKeychainTrustApplication:       true,\n\t\tKeychainAccessibleWhenUnlocked: true,\n\t\tKWalletAppID:                   \"space\",\n\t\tKWalletFolder:                  \"space\",\n\t\tWinCredPrefix:                  \"space\",\n\t\tLibSecretCollectionName:        \"space\",\n\t\tPassPrefix:                     \"space\",\n\t\tPassDir:                        spaceStorePath + \"/kcpw\",\n\t\tFileDir:                        path.Join(ucd, \"space\", \"keyring\"),\n\t})\n\tif err == nil {\n\t\t_ = ring.Remove(keychain.AppTokenStoreKey + \"_\" + keychain.MasterAppTokenStoreKey)\n\t\tif a.ClientAppToken != \"\" {\n\t\t\tparts := strings.Split(a.ClientAppToken, \".\")\n\t\t\t_ = ring.Remove(keychain.AppTokenStoreKey + \"_\" + parts[0])\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "integration_tests/fixtures/client.go",
    "content": "package fixtures\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"google.golang.org/grpc/metadata\"\n\n\t. \"github.com/onsi/gomega\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"google.golang.org/grpc\"\n)\n\nvar DefaultBucket = \"personal\"\nvar MirrorBucket = \"personal_mirror\"\n\nfunc (a *RunAppCtx) Client() pb.SpaceApiClient {\n\tif a.client != nil {\n\t\treturn a.client\n\t}\n\n\tconn, err := DialGrpcClient(fmt.Sprintf(\":%d\", a.cfg.GetInt(config.SpaceServerPort, 9999)), a)\n\tExpect(err).NotTo(HaveOccurred())\n\ta.client = pb.NewSpaceApiClient(conn)\n\n\treturn a.client\n}\n\nfunc DialGrpcClient(targetAddr string, a *RunAppCtx) (*grpc.ClientConn, error) {\n\treturn grpc.Dial(\n\t\ttargetAddr,\n\t\tgrpc.WithInsecure(),\n\t\tgrpc.WithBlock(),\n\t\tgrpc.WithUnaryInterceptor(func(\n\t\t\tctx context.Context,\n\t\t\tmethod string,\n\t\t\treq, reply interface{},\n\t\t\tcc *grpc.ClientConn,\n\t\t\tinvoker grpc.UnaryInvoker,\n\t\t\topts ...grpc.CallOption,\n\t\t) error {\n\t\t\tif a.ClientAppToken != \"\" {\n\t\t\t\tmd := metadata.New(map[string]string{\"authorization\": \"AppToken \" + a.ClientAppToken})\n\t\t\t\tctx = metadata.NewOutgoingContext(ctx, md)\n\t\t\t}\n\n\t\t\treturn invoker(ctx, method, req, reply, cc, opts...)\n\t\t}),\n\t\tgrpc.WithStreamInterceptor(func(\n\t\t\tctx context.Context,\n\t\t\tdesc *grpc.StreamDesc,\n\t\t\tcc *grpc.ClientConn,\n\t\t\tmethod string,\n\t\t\tstreamer grpc.Streamer,\n\t\t\topts ...grpc.CallOption,\n\t\t) (grpc.ClientStream, error) {\n\t\t\tif a.ClientAppToken != \"\" {\n\t\t\t\tmd := metadata.New(map[string]string{\"authorization\": \"AppToken \" + a.ClientAppToken})\n\t\t\t\tctx = metadata.NewOutgoingContext(ctx, md)\n\t\t\t}\n\n\t\t\treturn streamer(ctx, desc, cc, method, opts...)\n\t\t}),\n\t)\n}\n"
  },
  {
    "path": "integration_tests/fixtures/configs.go",
    "content": "package fixtures\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\t. \"github.com/onsi/gomega\"\n\t\"github.com/phayes/freeport\"\n)\n\n// GetTestConfig returns a ConfigMap instance instantiated using the env variables\nfunc GetTestConfig() (*config.Flags, config.Config, env.SpaceEnv) {\n\thomeDir, err := os.UserHomeDir()\n\tExpect(err).NotTo(HaveOccurred())\n\n\tfreePorts, err := freeport.GetFreePorts(8)\n\tExpect(err).NotTo(HaveOccurred())\n\n\tflags := config.Flags{\n\t\tIpfsaddr:               \"/ip4/127.0.0.1/tcp/5001\",\n\t\tIpfsnode:               false, // use external ipfs node\n\t\tIpfsnodeaddr:           \"/ip4/127.0.0.1/tcp/5001\",\n\t\tIpfsnodepath:           filepath.Join(homeDir, \".fleek-space-ipfs-node-test\"),\n\t\tDevMode:                false,\n\t\tServicesAPIURL:         os.Getenv(\"SERVICES_API_URL\"),\n\t\tSpaceStorageSiteUrl:    os.Getenv(\"SPACE_STORAGE_SITE_URL\"),\n\t\tVaultAPIURL:            os.Getenv(\"VAULT_API_URL\"),\n\t\tVaultSaltSecret:        os.Getenv(\"VAULT_SALT_SECRET\"),\n\t\tServicesHubAuthURL:     os.Getenv(\"SERVICES_HUB_AUTH_URL\"),\n\t\tTextileHubTarget:       os.Getenv(\"TXL_HUB_TARGET\"),\n\t\tTextileHubMa:           os.Getenv(\"TXL_HUB_MA\"),\n\t\tTextileThreadsTarget:   os.Getenv(\"TXL_THREADS_TARGET\"),\n\t\tTextileHubGatewayUrl:   os.Getenv(\"TXL_HUB_GATEWAY_URL\"),\n\t\tTextileUserKey:         os.Getenv(\"TXL_USER_KEY\"),\n\t\tTextileUserSecret:      os.Getenv(\"TXL_USER_SECRET\"),\n\t\tSpaceStorePath:         filepath.Join(homeDir, \".fleek-space-\"+RandomPathName()),\n\t\tRpcServerPort:          freePorts[1],\n\t\tRpcProxyServerPort:     freePorts[2],\n\t\tRestProxyServerPort:    freePorts[3],\n\t\tBuckdPath:              filepath.Join(homeDir, \".fleek-space-buckd-\"+RandomPathName()),\n\t\tBuckdApiMaAddr:         fmt.Sprintf(\"/ip4/127.0.0.1/tcp/%d\", freePorts[4]),\n\t\tBuckdApiProxyMaAddr:    fmt.Sprintf(\"/ip4/127.0.0.1/tcp/%d\", freePorts[5]),\n\t\tBuckdThreadsHostMaAddr: fmt.Sprintf(\"/ip4/0.0.0.0/tcp/%d\", freePorts[6]),\n\t\tBuckdGatewayPort:       freePorts[7],\n\t\tLogLevel:               \"info\",\n\t}\n\n\t// env\n\tspaceEnv := env.New()\n\n\t// load configs\n\treturn &flags, config.NewMap(&flags), spaceEnv\n}\n"
  },
  {
    "path": "integration_tests/fixtures/directories.go",
    "content": "package fixtures\n\nimport \"math/rand\"\n\nconst letterBytes = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \"\n\n// RandomPathName create a valid path segment name. Usually 10 characters in length\nfunc RandomPathName() string {\n\tb := make([]byte, 10)\n\tfor i := range b {\n\t\tb[i] = letterBytes[rand.Intn(len(letterBytes))]\n\t}\n\treturn string(b)\n}\n"
  },
  {
    "path": "integration_tests/helpers/assertions.go",
    "content": "package helpers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\n\t\"github.com/FleekHQ/space-daemon/integration_tests/fixtures\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc ExpectFileExists(ctx context.Context, client pb.SpaceApiClient, remotePath string, remoteFileName string) *pb.ListDirectoryEntry {\n\tres, err := client.ListDirectory(ctx, &pb.ListDirectoryRequest{\n\t\tPath:   remotePath,\n\t\tBucket: fixtures.DefaultBucket,\n\t})\n\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\tExpectWithOffset(1, res.Entries).NotTo(BeEmpty(), \"file at remote path not found\")\n\n\tfor _, item := range res.Entries {\n\t\tif item.Name == remoteFileName {\n\t\t\treturn item\n\t\t}\n\t}\n\t// Not Found\n\tExpectWithOffset(1, errors.New(\"file at remote path not found\")).NotTo(HaveOccurred())\n\treturn nil\n}\n\nfunc ExpectFileContentEquals(filePath string, expectedContent []byte) {\n\tactualContent, err := ioutil.ReadFile(filePath)\n\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\tExpectWithOffset(1, actualContent).To(Equal(expectedContent))\n}\n\nfunc ExpectFileToBeSharedWithMe(\n\tctx context.Context,\n\tclient pb.SpaceApiClient,\n\tfileName, bucket, dbId string,\n\tisPublicShared bool,\n) *pb.SharedListDirectoryEntry {\n\t// assert file is visible in recently shared list\n\tsharedWithMeRes, err := client.GetSharedWithMeFiles(ctx, &pb.GetSharedWithMeFilesRequest{Limit: 10})\n\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\tExpectWithOffset(1, sharedWithMeRes.Items).NotTo(BeEmpty())\n\tfor _, item := range sharedWithMeRes.Items {\n\t\tif item.Entry.Name == fileName {\n\t\t\tExpectWithOffset(1, item.IsPublicLink).To(Equal(isPublicShared), \"shared files is publicly shared not expected value\")\n\t\t\tExpectWithOffset(1, item.Bucket).To(Equal(bucket), \"shared files bucket slug not expected value\")\n\t\t\tif dbId != \"<ignore>\" { // conditionally skip this for some checks\n\t\t\t\tExpectWithOffset(1, item.DbId).To(Equal(dbId), \"shared files dbId not expected value\")\n\t\t\t}\n\t\t\treturn item\n\t\t}\n\t}\n\t// Not Found\n\tExpectWithOffset(1, errors.New(fmt.Sprintf(\"shared with me file not found. filename=%s, isPublicShared=%v\", fileName, isPublicShared)))\n\treturn nil\n}\n"
  },
  {
    "path": "integration_tests/helpers/directories.go",
    "content": "package helpers\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/onsi/ginkgo\"\n\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\n\t\"github.com/FleekHQ/space-daemon/integration_tests/fixtures\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc CreateEmptyFolder(ctx context.Context, client pb.SpaceApiClient, path string) {\n\t_, err := client.CreateFolder(ctx, &pb.CreateFolderRequest{\n\t\tPath:   path,\n\t\tBucket: fixtures.DefaultBucket,\n\t})\n\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\t<-time.After(4 * time.Second) // required currently for textile to perform sync properly. TODO: Fix this\n}\n\nfunc CreateLocalStringFile(strContent string) *os.File {\n\tcontent := []byte(strContent)\n\ttmpfile, err := ioutil.TempFile(\"\", \"*-localStringFile.txt\")\n\tExpectWithOffset(1, err).NotTo(HaveOccurred(), \"Failed to create local string file\")\n\tif err != nil {\n\t\tdefer tmpfile.Close()\n\t}\n\n\t_, err = tmpfile.Write(content)\n\tExpectWithOffset(1, err).NotTo(HaveOccurred(), \"Failed to write string content\")\n\n\treturn tmpfile\n}\n\nfunc UploadFilesToTargetPath(\n\tctx context.Context,\n\tclient pb.SpaceApiClient,\n\ttargetPath string,\n\tsourcePaths []string,\n) {\n\tstreamResponse, err := client.AddItems(ctx, &pb.AddItemsRequest{\n\t\tSourcePaths: sourcePaths,\n\t\tTargetPath:  targetPath,\n\t\tBucket:      fixtures.DefaultBucket,\n\t})\n\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\t_, err = streamResponse.Recv()\n\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\t<-time.After(4 * time.Second) // required currently for textile to perform sync properly. TODO: Fix this\n}\n\n// StartWatchingForRemoteUploads kicks off a goroutine that subscribes to Subscribe rpc for the client\n// and watches for the specified files and buckets to be uploaded\n// The first channels returns returns a true when all files have been found or false after a 5 minutes timeout of not finding them all\n// the second function returned must always be called at the end of a test to ensure the goroutine is stopped.\nfunc StartWatchingForRemoteBackup(\n\tctx context.Context,\n\tclient pb.SpaceApiClient,\n\tfilePathsToWatch []string,\n) (<-chan bool, func()) {\n\tExpectWithOffset(1, filePathsToWatch).NotTo(BeEmpty())\n\n\tstreamCtx, cancelStreamCtx := context.WithCancel(context.Background())\n\tstreamResponse, err := client.Subscribe(streamCtx, &empty.Empty{})\n\tExpectWithOffset(1, err).NotTo(HaveOccurred(), \"Subscribe failed to connect\")\n\tfoundFiles := make(map[string]bool)\n\ttotalFound := 0\n\tfoundAllChan := make(chan bool, 1)\n\tcloseAChan := make(chan bool, 1)\n\titemsChan := make(chan *pb.FileEventResponse)\n\n\tgo func() {\n\t\tdefer ginkgo.GinkgoRecover()\n\n\t\ttimeoutChan := time.After(5 * time.Minute)\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-closeAChan:\n\t\t\t\treturn\n\t\t\tcase <-timeoutChan:\n\t\t\t\tfoundAllChan <- totalFound == len(filePathsToWatch)\n\t\t\t\treturn\n\t\t\tcase item := <-itemsChan:\n\t\t\t\tif !foundFiles[item.Entry.Path] && item.Bucket == fixtures.DefaultBucket && item.Type == pb.EventType_ENTRY_BACKUP_READY {\n\t\t\t\t\tfor _, path := range filePathsToWatch {\n\t\t\t\t\t\tif path == item.Entry.Path {\n\t\t\t\t\t\t\tfoundFiles[item.Entry.Path] = true\n\t\t\t\t\t\t\ttotalFound++\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif totalFound == len(filePathsToWatch) {\n\t\t\t\t\t// wait for completion\n\t\t\t\t\tfoundAllChan <- true // all file have been found\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tdefer ginkgo.GinkgoRecover()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tdefault:\n\t\t\t\titem, err := streamResponse.Recv()\n\t\t\t\tif err == io.EOF { // stream closed\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tExpectWithOffset(2, err).NotTo(HaveOccurred(), \"failed while receiving data from stream\")\n\t\t\t\tif err == nil {\n\t\t\t\t\titemsChan <- item\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn foundAllChan, func() {\n\t\tcloseAChan <- true\n\t\tcancelStreamCtx()\n\t}\n}\n\n// i need to be receiving and in parallel\n"
  },
  {
    "path": "integration_tests/helpers/initialize.go",
    "content": "package helpers\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/FleekHQ/space-daemon/integration_tests/fixtures\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc InitializeApp(app *fixtures.RunAppCtx) {\n\tif app.ClientAppToken == \"\" {\n\t\tres, err := app.Client().InitializeMasterAppToken(\n\t\t\tcontext.Background(),\n\t\t\t&pb.InitializeMasterAppTokenRequest{},\n\t\t)\n\n\t\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\t\tExpectWithOffset(1, res.AppToken).NotTo(BeEmpty())\n\t\tapp.ClientAppToken = res.AppToken\n\t}\n\n\tif app.ClientMnemonic == \"\" {\n\t\tkpRes, err := app.Client().GenerateKeyPair(context.Background(), &pb.GenerateKeyPairRequest{})\n\t\tExpectWithOffset(1, err).NotTo(HaveOccurred())\n\t\tapp.ClientMnemonic = kpRes.Mnemonic\n\t}\n}\n"
  },
  {
    "path": "integration_tests/integration_tests_suite_test.go",
    "content": "package integration_tests\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/config\"\n\n\tipfs \"github.com/FleekHQ/space-daemon/core/ipfs/node\"\n\n\t. \"github.com/FleekHQ/space-daemon/integration_tests/helpers\"\n\n\t\"github.com/FleekHQ/space-daemon/integration_tests/fixtures\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar (\n\tapp      *fixtures.RunAppCtx\n\tipfsNode *ipfs.IpfsNode\n\tipfsCfg  config.Config\n)\n\n// TestIntegrationTests registers the integration test suite with ginkgo.\nfunc TestIntegrationTests(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"IntegrationTests Suite\")\n}\n\nvar _ = BeforeSuite(func() {\n\t// start ipfs node\n\t_, ipfsCfg, _ = fixtures.GetTestConfig()\n\tipfsNode = ipfs.NewIpsNode(ipfsCfg)\n\tipfsErrChan := make(chan error)\n\tgo func() {\n\t\tipfsErrChan <- ipfsNode.Start(context.TODO())\n\t}()\n\n\tselect {\n\tcase err := <-ipfsErrChan:\n\t\tExpect(err).NotTo(HaveOccurred(), \"Error starting ipfs node for integration tests\")\n\tcase <-ipfsNode.WaitForReady():\n\t\t// ipfs node ready\n\t}\n\n\tapp = fixtures.RunApp()\n\tInitializeApp(app)\n})\n\nvar _ = AfterSuite(func() {\n\tapp.Shutdown()\n\tapp.ClearMasterAppToken()\n\n\t// shutdown ipfs\n\t_ = ipfsNode.Shutdown()\n\t_ = os.RemoveAll(ipfsCfg.GetString(config.Ipfsnodepath, \"\"))\n})\n"
  },
  {
    "path": "integration_tests/sharing_test.go",
    "content": "package integration_tests\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\t\"github.com/FleekHQ/space-daemon/integration_tests/fixtures\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t. \"github.com/FleekHQ/space-daemon/integration_tests/helpers\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"Sharing Files\", func() {\n\tContext(\"when sharing publicly\", func() {\n\t\tIt(\"should work\", func() {\n\t\t\tctx := context.Background()\n\t\t\tpassword := \"random-strong-password\"\n\t\t\tsharedFileContent := \"Perhaps really long text\"\n\t\t\tfile := CreateLocalStringFile(sharedFileContent)\n\t\t\tfileName := filepath.Base(file.Name())\n\n\t\t\t// share file\n\t\t\tUploadFilesToTargetPath(ctx, app.Client(), \"\", []string{file.Name()})\n\t\t\tpublicLinkRes, err := app.Client().GeneratePublicFileLink(ctx, &pb.GeneratePublicFileLinkRequest{\n\t\t\t\tBucket:    fixtures.DefaultBucket,\n\t\t\t\tItemPaths: []string{fileName},\n\t\t\t\tPassword:  password,\n\t\t\t})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\n\t\t\t// fetch shared file\n\t\t\topenLinkRes, err := app.Client().OpenPublicFile(ctx, &pb.OpenPublicFileRequest{\n\t\t\t\tFileCid:  publicLinkRes.FileCid,\n\t\t\t\tPassword: password,\n\t\t\t\tFilename: fileName,\n\t\t\t})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\t\t\tExpectFileContentEquals(openLinkRes.Location, []byte(sharedFileContent))\n\n\t\t\t// assert file is visible in recently shared list\n\t\t\tExpectFileToBeSharedWithMe(ctx, app.Client(), fileName, \"\", \"\", true)\n\t\t})\n\t})\n\n\tContext(\"when sharing privately\", func() {\n\t\tvar app2 *fixtures.RunAppCtx\n\n\t\tBeforeEach(func() {\n\t\t\tapp2 = fixtures.RunAppWithClientAppToken(app.ClientAppToken)\n\t\t\tInitializeApp(app2)\n\t\t})\n\n\t\tAfterEach(func() {\n\t\t\tapp2.Shutdown()\n\t\t})\n\n\t\tIt(\"should work\", func() {\n\t\t\tctx := context.Background()\n\t\t\tsharedFileContent := \"A really really really long text or possibly binary data\"\n\t\t\tfile := CreateLocalStringFile(sharedFileContent)\n\t\t\tfileName := filepath.Base(file.Name())\n\t\t\tpk1Res, err := app.Client().GetPublicKey(ctx, &pb.GetPublicKeyRequest{})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\n\t\t\t// upload file to second users directory\n\t\t\tremoteBackupWait, cleanupWait := StartWatchingForRemoteBackup(ctx, app2.Client(), []string{fileName})\n\t\t\tdefer cleanupWait()\n\t\t\tUploadFilesToTargetPath(ctx, app2.Client(), \"\", []string{file.Name()})\n\n\t\t\t// Wait for file to be replicated to the hub\n\t\t\tbackupSuccess := <-remoteBackupWait\n\t\t\tExpect(backupSuccess).To(BeTrue(), \"failed to complete remote backup of watched files\")\n\n\t\t\t// share file with the first user\n\t\t\t_, err = app2.Client().ShareFilesViaPublicKey(ctx, &pb.ShareFilesViaPublicKeyRequest{\n\t\t\t\tPublicKeys: []string{pk1Res.PublicKey},\n\t\t\t\tPaths: []*pb.FullPath{{\n\t\t\t\t\tBucket: fixtures.DefaultBucket,\n\t\t\t\t\tPath:   fileName,\n\t\t\t\t}},\n\t\t\t})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\n\t\t\t// Fetch and verify invite notification.\n\t\t\tnotifRes, err := app.Client().GetNotifications(ctx, &pb.GetNotificationsRequest{Limit: 10})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\t\t\tExpect(notifRes.Notifications).NotTo(BeEmpty(), \"no invite notification provided\")\n\t\t\tExpect(notifRes.Notifications[0].Type).To(Equal(pb.NotificationType_INVITATION))\n\n\t\t\t// Accept invite\n\t\t\t_, err = app.Client().HandleFilesInvitation(ctx, &pb.HandleFilesInvitationRequest{\n\t\t\t\tInvitationID: notifRes.Notifications[0].ID,\n\t\t\t\tAccept:       true,\n\t\t\t})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\n\t\t\t// verify file is in shared with first user\n\t\t\tsharedItem := ExpectFileToBeSharedWithMe(ctx, app.Client(), fileName, fixtures.MirrorBucket, \"<ignore>\", false)\n\n\t\t\t// confirm first user can see file\n\t\t\topenFileResult, err := app.Client().OpenFile(ctx, &pb.OpenFileRequest{\n\t\t\t\tPath:   sharedItem.Entry.Path,\n\t\t\t\tBucket: sharedItem.Bucket,\n\t\t\t\tDbId:   sharedItem.DbId,\n\t\t\t})\n\t\t\tExpect(err).NotTo(HaveOccurred())\n\t\t\tExpectFileContentEquals(openFileResult.Location, []byte(sharedFileContent))\n\t\t})\n\t})\n})\n"
  },
  {
    "path": "integration_tests/uploads_test.go",
    "content": "package integration_tests\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\t\"github.com/FleekHQ/space-daemon/integration_tests/fixtures\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t. \"github.com/FleekHQ/space-daemon/integration_tests/helpers\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"App Uploads\", func() {\n\tIt(\"should create empty folder successfully\", func() {\n\t\tctx := context.Background()\n\t\tfolderName := fixtures.RandomPathName()\n\n\t\tCreateEmptyFolder(ctx, app.Client(), folderName)\n\t\t_, err := app.Client().ListDirectory(ctx, &pb.ListDirectoryRequest{\n\t\t\tPath:   \"\",\n\t\t\tBucket: fixtures.DefaultBucket,\n\t\t})\n\t\tExpect(err).NotTo(HaveOccurred())\n\t\tExpectFileExists(ctx, app.Client(), \"\", folderName)\n\t})\n\n\tIt(\"should upload and download files successfully\", func() {\n\t\tctx := context.Background()\n\t\tfile := CreateLocalStringFile(\"random file content\")\n\t\tfileName := filepath.Base(file.Name())\n\n\t\tUploadFilesToTargetPath(ctx, app.Client(), \"\", []string{file.Name()})\n\t\tExpectFileExists(ctx, app.Client(), \"\", fileName)\n\n\t\t// try uploading to a folder\n\t\ttopFolderPath := fixtures.RandomPathName()\n\t\tCreateEmptyFolder(ctx, app.Client(), topFolderPath)\n\t\tUploadFilesToTargetPath(ctx, app.Client(), topFolderPath, []string{file.Name()})\n\t\tExpectFileExists(ctx, app.Client(), topFolderPath, fileName)\n\t})\n})\n"
  },
  {
    "path": "log/logger.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/FleekHQ/space-daemon/core/env\"\n\t\"github.com/sirupsen/logrus\"\n)\n\nvar (\n\tlog *logger\n)\n\ntype logger struct {\n\tlog *logrus.Logger\n}\n\nfunc init() {\n\tlog = new(\"\")\n}\n\nfunc New(env env.SpaceEnv) *logger {\n\t// TODO: check for log level in config and pass it to new\n\treturn new(\"\")\n}\n\nfunc new(logLevel string) *logger {\n\tlogLevelConf := \"Debug\"\n\tlevel, err := logrus.ParseLevel(logLevelConf)\n\tif err != nil {\n\t\tlevel = logrus.DebugLevel\n\t}\n\tlog = &logger{\n\t\tlog: &logrus.Logger{\n\t\t\tLevel:     level,\n\t\t\tOut:       os.Stdout,\n\t\t\tFormatter: &logrus.TextFormatter{},\n\t\t}}\n\n\treturn log\n}\n\n// METHODS\n\nfunc (l *logger) Info(msg string, tags ...string) {\n\tif l.log.Level < logrus.InfoLevel {\n\t\treturn\n\t}\n\n\tl.log.WithFields(parseFields(tags...)).Info(msg)\n}\n\nfunc (l *logger) Printf(msg string, args ...interface{}) {\n\tif l.log.Level < logrus.InfoLevel {\n\t\treturn\n\t}\n\n\tl.log.Printf(msg, args...)\n}\n\nfunc (l *logger) Debug(msg string, tags ...string) {\n\tif l.log.Level < logrus.DebugLevel {\n\t\treturn\n\t}\n\n\tl.log.WithFields(parseFields(tags...)).Debug(msg)\n}\n\nfunc (l *logger) Warn(msg string, tags ...string) {\n\tif l.log.Level < logrus.WarnLevel {\n\t\treturn\n\t}\n\n\tl.log.WithFields(parseFields(tags...)).Warn(msg)\n}\n\nfunc (l *logger) Error(msg string, err error, tags ...string) {\n\tif l.log.Level < logrus.ErrorLevel {\n\t\treturn\n\t}\n\tmsg = fmt.Sprintf(\"%s -- ERROR -- %v\", msg, err)\n\t// l.log.WithFields(parseFields(tags...)).Error(msg)\n\tl.log.Error(msg, tags)\n}\n\nfunc (l *logger) Fatal(err error) {\n\tl.Error(err.Error(), err)\n\tl.log.Exit(1)\n}\n\n// Functions\n\nfunc Info(msg string, tags ...string) {\n\tlog.Info(msg, tags...)\n}\n\nfunc Printf(msg string, args ...interface{}) {\n\tlog.Printf(msg, args...)\n}\n\nfunc Warn(msg string, tags ...string) {\n\tlog.Warn(msg, tags...)\n}\n\nfunc Debug(msg string, tags ...string) {\n\tlog.Debug(msg, tags...)\n}\n\nfunc Error(msg string, err error, tags ...string) {\n\tlog.Error(msg, err, tags...)\n}\n\nfunc Fatal(err error) {\n\tlog.Fatal(err)\n}\n\nfunc SetLogLevel(logLevel string) {\n\tlevel, err := logrus.ParseLevel(logLevel)\n\tif err != nil {\n\t\tlevel = logrus.DebugLevel\n\t}\n\tlog.log.SetLevel(level)\n}\n\nfunc parseFields(tags ...string) logrus.Fields {\n\tresult := make(logrus.Fields, len(tags))\n\n\tfor _, tag := range tags {\n\t\tels := strings.Split(tag, \":\")\n\t\tif len(els) > 1 {\n\t\t\tresult[strings.TrimSpace(els[0])] = strings.TrimSpace(els[1])\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "mocks/Bucket.go",
    "content": "// Code generated by mockery v2.3.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tcontext \"context\"\n\n\tbucket \"github.com/FleekHQ/space-daemon/core/textile/bucket\"\n\n\tio \"io\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tpath \"github.com/ipfs/interface-go-ipfs-core/path\"\n\n\tthread \"github.com/textileio/go-threads/core/thread\"\n)\n\n// Bucket is an autogenerated mock type for the Bucket type\ntype Bucket struct {\n\tmock.Mock\n}\n\n// CreateDirectory provides a mock function with given fields: ctx, _a1\nfunc (_m *Bucket) CreateDirectory(ctx context.Context, _a1 string) (path.Resolved, path.Path, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 path.Resolved\n\tif rf, ok := ret.Get(0).(func(context.Context, string) path.Resolved); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(path.Resolved)\n\t\t}\n\t}\n\n\tvar r1 path.Path\n\tif rf, ok := ret.Get(1).(func(context.Context, string) path.Path); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).(path.Path)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context, string) error); ok {\n\t\tr2 = rf(ctx, _a1)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// DeleteDirOrFile provides a mock function with given fields: ctx, _a1\nfunc (_m *Bucket) DeleteDirOrFile(ctx context.Context, _a1 string) (path.Resolved, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 path.Resolved\n\tif rf, ok := ret.Get(0).(func(context.Context, string) path.Resolved); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(path.Resolved)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// DirExists provides a mock function with given fields: ctx, _a1\nfunc (_m *Bucket) DirExists(ctx context.Context, _a1 string) (bool, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// DownloadFile provides a mock function with given fields: ctx, _a1, reader\nfunc (_m *Bucket) DownloadFile(ctx context.Context, _a1 string, reader io.Reader) (path.Resolved, path.Path, error) {\n\tret := _m.Called(ctx, _a1, reader)\n\n\tvar r0 path.Resolved\n\tif rf, ok := ret.Get(0).(func(context.Context, string, io.Reader) path.Resolved); ok {\n\t\tr0 = rf(ctx, _a1, reader)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(path.Resolved)\n\t\t}\n\t}\n\n\tvar r1 path.Path\n\tif rf, ok := ret.Get(1).(func(context.Context, string, io.Reader) path.Path); ok {\n\t\tr1 = rf(ctx, _a1, reader)\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).(path.Path)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context, string, io.Reader) error); ok {\n\t\tr2 = rf(ctx, _a1, reader)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// Each provides a mock function with given fields: ctx, _a1, iterator, withRecursive\nfunc (_m *Bucket) Each(ctx context.Context, _a1 string, iterator func(context.Context, *bucket.Bucket, string) error, withRecursive bool) (int, error) {\n\tret := _m.Called(ctx, _a1, iterator, withRecursive)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, string, func(context.Context, *bucket.Bucket, string) error, bool) int); ok {\n\t\tr0 = rf(ctx, _a1, iterator, withRecursive)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, func(context.Context, *bucket.Bucket, string) error, bool) error); ok {\n\t\tr1 = rf(ctx, _a1, iterator, withRecursive)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FileExists provides a mock function with given fields: ctx, _a1\nfunc (_m *Bucket) FileExists(ctx context.Context, _a1 string) (bool, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetClient provides a mock function with given fields:\nfunc (_m *Bucket) GetClient() bucket.BucketsClient {\n\tret := _m.Called()\n\n\tvar r0 bucket.BucketsClient\n\tif rf, ok := ret.Get(0).(func() bucket.BucketsClient); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(bucket.BucketsClient)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// GetContext provides a mock function with given fields: ctx\nfunc (_m *Bucket) GetContext(ctx context.Context) (context.Context, *thread.ID, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 context.Context\n\tif rf, ok := ret.Get(0).(func(context.Context) context.Context); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(context.Context)\n\t\t}\n\t}\n\n\tvar r1 *thread.ID\n\tif rf, ok := ret.Get(1).(func(context.Context) *thread.ID); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).(*thread.ID)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context) error); ok {\n\t\tr2 = rf(ctx)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GetData provides a mock function with given fields:\nfunc (_m *Bucket) GetData() bucket.BucketData {\n\tret := _m.Called()\n\n\tvar r0 bucket.BucketData\n\tif rf, ok := ret.Get(0).(func() bucket.BucketData); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(bucket.BucketData)\n\t}\n\n\treturn r0\n}\n\n// GetFile provides a mock function with given fields: ctx, _a1, w\nfunc (_m *Bucket) GetFile(ctx context.Context, _a1 string, w io.Writer) error {\n\tret := _m.Called(ctx, _a1, w)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, string, io.Writer) error); ok {\n\t\tr0 = rf(ctx, _a1, w)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// GetThreadID provides a mock function with given fields: ctx\nfunc (_m *Bucket) GetThreadID(ctx context.Context) (*thread.ID, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 *thread.ID\n\tif rf, ok := ret.Get(0).(func(context.Context) *thread.ID); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*thread.ID)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ItemsCount provides a mock function with given fields: ctx, _a1, withRecursive\nfunc (_m *Bucket) ItemsCount(ctx context.Context, _a1 string, withRecursive bool) (int32, error) {\n\tret := _m.Called(ctx, _a1, withRecursive)\n\n\tvar r0 int32\n\tif rf, ok := ret.Get(0).(func(context.Context, string, bool) int32); ok {\n\t\tr0 = rf(ctx, _a1, withRecursive)\n\t} else {\n\t\tr0 = ret.Get(0).(int32)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {\n\t\tr1 = rf(ctx, _a1, withRecursive)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Key provides a mock function with given fields:\nfunc (_m *Bucket) Key() string {\n\tret := _m.Called()\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func() string); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\treturn r0\n}\n\n// ListDirectory provides a mock function with given fields: ctx, _a1\nfunc (_m *Bucket) ListDirectory(ctx context.Context, _a1 string) (*bucket.DirEntries, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 *bucket.DirEntries\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *bucket.DirEntries); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*bucket.DirEntries)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Slug provides a mock function with given fields:\nfunc (_m *Bucket) Slug() string {\n\tret := _m.Called()\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func() string); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\treturn r0\n}\n\n// UpdatedAt provides a mock function with given fields: ctx, _a1\nfunc (_m *Bucket) UpdatedAt(ctx context.Context, _a1 string) (int64, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 int64\n\tif rf, ok := ret.Get(0).(func(context.Context, string) int64); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tr0 = ret.Get(0).(int64)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// UploadFile provides a mock function with given fields: ctx, _a1, reader\nfunc (_m *Bucket) UploadFile(ctx context.Context, _a1 string, reader io.Reader) (path.Resolved, path.Path, error) {\n\tret := _m.Called(ctx, _a1, reader)\n\n\tvar r0 path.Resolved\n\tif rf, ok := ret.Get(0).(func(context.Context, string, io.Reader) path.Resolved); ok {\n\t\tr0 = rf(ctx, _a1, reader)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(path.Resolved)\n\t\t}\n\t}\n\n\tvar r1 path.Path\n\tif rf, ok := ret.Get(1).(func(context.Context, string, io.Reader) path.Path); ok {\n\t\tr1 = rf(ctx, _a1, reader)\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).(path.Path)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context, string, io.Reader) error); ok {\n\t\tr2 = rf(ctx, _a1, reader)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n"
  },
  {
    "path": "mocks/Client.go",
    "content": "// Code generated by mockery v2.4.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tconfig \"github.com/FleekHQ/space-daemon/config\"\n\tcid \"github.com/ipfs/go-cid\"\n\tclient \"github.com/textileio/go-threads/api/client\"\n\n\tcontext \"context\"\n\n\tcrypto \"github.com/libp2p/go-libp2p-core/crypto\"\n\n\tdb \"github.com/textileio/go-threads/db\"\n\n\tdomain \"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n\tio \"io\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tmodel \"github.com/FleekHQ/space-daemon/core/textile/model\"\n\n\tsync \"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\n\ttextile \"github.com/FleekHQ/space-daemon/core/textile\"\n\n\tusersdclient \"github.com/textileio/textile/v2/api/usersd/client\"\n)\n\n// Client is an autogenerated mock type for the Client type\ntype Client struct {\n\tmock.Mock\n}\n\n// AcceptSharedFileLink provides a mock function with given fields: ctx, cidHash, password, filename, fileSize\nfunc (_m *Client) AcceptSharedFileLink(ctx context.Context, cidHash string, password string, filename string, fileSize string) (*domain.SharedDirEntry, error) {\n\tret := _m.Called(ctx, cidHash, password, filename, fileSize)\n\n\tvar r0 *domain.SharedDirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) *domain.SharedDirEntry); ok {\n\t\tr0 = rf(ctx, cidHash, password, filename, fileSize)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*domain.SharedDirEntry)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) error); ok {\n\t\tr1 = rf(ctx, cidHash, password, filename, fileSize)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// AcceptSharedFilesInvitation provides a mock function with given fields: ctx, invitation\nfunc (_m *Client) AcceptSharedFilesInvitation(ctx context.Context, invitation domain.Invitation) (domain.Invitation, error) {\n\tret := _m.Called(ctx, invitation)\n\n\tvar r0 domain.Invitation\n\tif rf, ok := ret.Get(0).(func(context.Context, domain.Invitation) domain.Invitation); ok {\n\t\tr0 = rf(ctx, invitation)\n\t} else {\n\t\tr0 = ret.Get(0).(domain.Invitation)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, domain.Invitation) error); ok {\n\t\tr1 = rf(ctx, invitation)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// AttachMailboxNotifier provides a mock function with given fields: notif\nfunc (_m *Client) AttachMailboxNotifier(notif textile.GrpcMailboxNotifier) {\n\t_m.Called(notif)\n}\n\n// AttachSynchronizerNotifier provides a mock function with given fields: notif\nfunc (_m *Client) AttachSynchronizerNotifier(notif sync.EventNotifier) {\n\t_m.Called(notif)\n}\n\n// BucketBackupRestore provides a mock function with given fields: ctx, bucketSlug\nfunc (_m *Client) BucketBackupRestore(ctx context.Context, bucketSlug string) error {\n\tret := _m.Called(ctx, bucketSlug)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, string) error); ok {\n\t\tr0 = rf(ctx, bucketSlug)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// CreateBucket provides a mock function with given fields: ctx, bucketSlug\nfunc (_m *Client) CreateBucket(ctx context.Context, bucketSlug string) (textile.Bucket, error) {\n\tret := _m.Called(ctx, bucketSlug)\n\n\tvar r0 textile.Bucket\n\tif rf, ok := ret.Get(0).(func(context.Context, string) textile.Bucket); ok {\n\t\tr0 = rf(ctx, bucketSlug)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(textile.Bucket)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, bucketSlug)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// DeleteAccount provides a mock function with given fields: ctx\nfunc (_m *Client) DeleteAccount(ctx context.Context) error {\n\tret := _m.Called(ctx)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context) error); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// DisableSync provides a mock function with given fields:\nfunc (_m *Client) DisableSync() {\n\t_m.Called()\n}\n\n// DownloadPublicItem provides a mock function with given fields: ctx, _a1\nfunc (_m *Client) DownloadPublicItem(ctx context.Context, _a1 cid.Cid) (io.ReadCloser, error) {\n\tret := _m.Called(ctx, _a1)\n\n\tvar r0 io.ReadCloser\n\tif rf, ok := ret.Get(0).(func(context.Context, cid.Cid) io.ReadCloser); ok {\n\t\tr0 = rf(ctx, _a1)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(io.ReadCloser)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, cid.Cid) error); ok {\n\t\tr1 = rf(ctx, _a1)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetBucket provides a mock function with given fields: ctx, slug, remoteFile\nfunc (_m *Client) GetBucket(ctx context.Context, slug string, remoteFile *textile.GetBucketForRemoteFileInput) (textile.Bucket, error) {\n\tret := _m.Called(ctx, slug, remoteFile)\n\n\tvar r0 textile.Bucket\n\tif rf, ok := ret.Get(0).(func(context.Context, string, *textile.GetBucketForRemoteFileInput) textile.Bucket); ok {\n\t\tr0 = rf(ctx, slug, remoteFile)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(textile.Bucket)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, *textile.GetBucketForRemoteFileInput) error); ok {\n\t\tr1 = rf(ctx, slug, remoteFile)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetDefaultBucket provides a mock function with given fields: ctx\nfunc (_m *Client) GetDefaultBucket(ctx context.Context) (textile.Bucket, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 textile.Bucket\n\tif rf, ok := ret.Get(0).(func(context.Context) textile.Bucket); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(textile.Bucket)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetFailedHealthchecks provides a mock function with given fields:\nfunc (_m *Client) GetFailedHealthchecks() int {\n\tret := _m.Called()\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func() int); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\treturn r0\n}\n\n// GetMailAsNotifications provides a mock function with given fields: ctx, seek, limit\nfunc (_m *Client) GetMailAsNotifications(ctx context.Context, seek string, limit int) ([]*domain.Notification, error) {\n\tret := _m.Called(ctx, seek, limit)\n\n\tvar r0 []*domain.Notification\n\tif rf, ok := ret.Get(0).(func(context.Context, string, int) []*domain.Notification); ok {\n\t\tr0 = rf(ctx, seek, limit)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*domain.Notification)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, int) error); ok {\n\t\tr1 = rf(ctx, seek, limit)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetModel provides a mock function with given fields:\nfunc (_m *Client) GetModel() model.Model {\n\tret := _m.Called()\n\n\tvar r0 model.Model\n\tif rf, ok := ret.Get(0).(func() model.Model); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(model.Model)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// GetPathAccessRoles provides a mock function with given fields: ctx, b, path\nfunc (_m *Client) GetPathAccessRoles(ctx context.Context, b textile.Bucket, path string) ([]domain.Member, error) {\n\tret := _m.Called(ctx, b, path)\n\n\tvar r0 []domain.Member\n\tif rf, ok := ret.Get(0).(func(context.Context, textile.Bucket, string) []domain.Member); ok {\n\t\tr0 = rf(ctx, b, path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]domain.Member)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, textile.Bucket, string) error); ok {\n\t\tr1 = rf(ctx, b, path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetPublicReceivedFile provides a mock function with given fields: ctx, cidHash, accepted\nfunc (_m *Client) GetPublicReceivedFile(ctx context.Context, cidHash string, accepted bool) (*domain.SharedDirEntry, string, error) {\n\tret := _m.Called(ctx, cidHash, accepted)\n\n\tvar r0 *domain.SharedDirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, string, bool) *domain.SharedDirEntry); ok {\n\t\tr0 = rf(ctx, cidHash, accepted)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*domain.SharedDirEntry)\n\t\t}\n\t}\n\n\tvar r1 string\n\tif rf, ok := ret.Get(1).(func(context.Context, string, bool) string); ok {\n\t\tr1 = rf(ctx, cidHash, accepted)\n\t} else {\n\t\tr1 = ret.Get(1).(string)\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context, string, bool) error); ok {\n\t\tr2 = rf(ctx, cidHash, accepted)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GetPublicShareBucket provides a mock function with given fields: ctx\nfunc (_m *Client) GetPublicShareBucket(ctx context.Context) (textile.Bucket, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 textile.Bucket\n\tif rf, ok := ret.Get(0).(func(context.Context) textile.Bucket); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(textile.Bucket)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetReceivedFiles provides a mock function with given fields: ctx, accepted, seek, limit\nfunc (_m *Client) GetReceivedFiles(ctx context.Context, accepted bool, seek string, limit int) ([]*domain.SharedDirEntry, string, error) {\n\tret := _m.Called(ctx, accepted, seek, limit)\n\n\tvar r0 []*domain.SharedDirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, bool, string, int) []*domain.SharedDirEntry); ok {\n\t\tr0 = rf(ctx, accepted, seek, limit)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*domain.SharedDirEntry)\n\t\t}\n\t}\n\n\tvar r1 string\n\tif rf, ok := ret.Get(1).(func(context.Context, bool, string, int) string); ok {\n\t\tr1 = rf(ctx, accepted, seek, limit)\n\t} else {\n\t\tr1 = ret.Get(1).(string)\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context, bool, string, int) error); ok {\n\t\tr2 = rf(ctx, accepted, seek, limit)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GetSentFiles provides a mock function with given fields: ctx, seek, limit\nfunc (_m *Client) GetSentFiles(ctx context.Context, seek string, limit int) ([]*domain.SharedDirEntry, string, error) {\n\tret := _m.Called(ctx, seek, limit)\n\n\tvar r0 []*domain.SharedDirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, string, int) []*domain.SharedDirEntry); ok {\n\t\tr0 = rf(ctx, seek, limit)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*domain.SharedDirEntry)\n\t\t}\n\t}\n\n\tvar r1 string\n\tif rf, ok := ret.Get(1).(func(context.Context, string, int) string); ok {\n\t\tr1 = rf(ctx, seek, limit)\n\t} else {\n\t\tr1 = ret.Get(1).(string)\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func(context.Context, string, int) error); ok {\n\t\tr2 = rf(ctx, seek, limit)\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GetThreadsConnection provides a mock function with given fields:\nfunc (_m *Client) GetThreadsConnection() (*client.Client, error) {\n\tret := _m.Called()\n\n\tvar r0 *client.Client\n\tif rf, ok := ret.Get(0).(func() *client.Client); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*client.Client)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// IsHealthy provides a mock function with given fields:\nfunc (_m *Client) IsHealthy() bool {\n\tret := _m.Called()\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func() bool); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\treturn r0\n}\n\n// IsInitialized provides a mock function with given fields:\nfunc (_m *Client) IsInitialized() bool {\n\tret := _m.Called()\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func() bool); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\treturn r0\n}\n\n// IsRunning provides a mock function with given fields:\nfunc (_m *Client) IsRunning() bool {\n\tret := _m.Called()\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func() bool); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\treturn r0\n}\n\n// JoinBucket provides a mock function with given fields: ctx, slug, ti\nfunc (_m *Client) JoinBucket(ctx context.Context, slug string, ti *domain.ThreadInfo) (bool, error) {\n\tret := _m.Called(ctx, slug, ti)\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func(context.Context, string, *domain.ThreadInfo) bool); ok {\n\t\tr0 = rf(ctx, slug, ti)\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, *domain.ThreadInfo) error); ok {\n\t\tr1 = rf(ctx, slug, ti)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ListBuckets provides a mock function with given fields: ctx\nfunc (_m *Client) ListBuckets(ctx context.Context) ([]textile.Bucket, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []textile.Bucket\n\tif rf, ok := ret.Get(0).(func(context.Context) []textile.Bucket); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]textile.Bucket)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Listen provides a mock function with given fields: ctx, dbID, threadName\nfunc (_m *Client) Listen(ctx context.Context, dbID string, threadName string) (<-chan client.ListenEvent, error) {\n\tret := _m.Called(ctx, dbID, threadName)\n\n\tvar r0 <-chan client.ListenEvent\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string) <-chan client.ListenEvent); ok {\n\t\tr0 = rf(ctx, dbID, threadName)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(<-chan client.ListenEvent)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {\n\t\tr1 = rf(ctx, dbID, threadName)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ManageShareFilesViaPublicKey provides a mock function with given fields: ctx, paths, pubkeys, keys, role\nfunc (_m *Client) ManageShareFilesViaPublicKey(ctx context.Context, paths []domain.FullPath, pubkeys []crypto.PubKey, keys [][]byte, role domain.SharedFilesRoleAction) error {\n\tret := _m.Called(ctx, paths, pubkeys, keys, role)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, []domain.FullPath, []crypto.PubKey, [][]byte, domain.SharedFilesRoleAction) error); ok {\n\t\tr0 = rf(ctx, paths, pubkeys, keys, role)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// RejectSharedFilesInvitation provides a mock function with given fields: ctx, invitation\nfunc (_m *Client) RejectSharedFilesInvitation(ctx context.Context, invitation domain.Invitation) (domain.Invitation, error) {\n\tret := _m.Called(ctx, invitation)\n\n\tvar r0 domain.Invitation\n\tif rf, ok := ret.Get(0).(func(context.Context, domain.Invitation) domain.Invitation); ok {\n\t\tr0 = rf(ctx, invitation)\n\t} else {\n\t\tr0 = ret.Get(0).(domain.Invitation)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, domain.Invitation) error); ok {\n\t\tr1 = rf(ctx, invitation)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// RemoveKeys provides a mock function with given fields: ctx\nfunc (_m *Client) RemoveKeys(ctx context.Context) error {\n\tret := _m.Called(ctx)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context) error); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// RestoreDB provides a mock function with given fields: ctx\nfunc (_m *Client) RestoreDB(ctx context.Context) error {\n\tret := _m.Called(ctx)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context) error); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// SendMessage provides a mock function with given fields: ctx, recipient, body\nfunc (_m *Client) SendMessage(ctx context.Context, recipient crypto.PubKey, body []byte) (*usersdclient.Message, error) {\n\tret := _m.Called(ctx, recipient, body)\n\n\tvar r0 *usersdclient.Message\n\tif rf, ok := ret.Get(0).(func(context.Context, crypto.PubKey, []byte) *usersdclient.Message); ok {\n\t\tr0 = rf(ctx, recipient, body)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*usersdclient.Message)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, crypto.PubKey, []byte) error); ok {\n\t\tr1 = rf(ctx, recipient, body)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ShareBucket provides a mock function with given fields: ctx, bucketSlug\nfunc (_m *Client) ShareBucket(ctx context.Context, bucketSlug string) (*db.Info, error) {\n\tret := _m.Called(ctx, bucketSlug)\n\n\tvar r0 *db.Info\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *db.Info); ok {\n\t\tr0 = rf(ctx, bucketSlug)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*db.Info)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, bucketSlug)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Shutdown provides a mock function with given fields:\nfunc (_m *Client) Shutdown() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Start provides a mock function with given fields: ctx, cfg\nfunc (_m *Client) Start(ctx context.Context, cfg config.Config) error {\n\tret := _m.Called(ctx, cfg)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, config.Config) error); ok {\n\t\tr0 = rf(ctx, cfg)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// ToggleBucketBackup provides a mock function with given fields: ctx, bucketSlug, bucketBackup\nfunc (_m *Client) ToggleBucketBackup(ctx context.Context, bucketSlug string, bucketBackup bool) (bool, error) {\n\tret := _m.Called(ctx, bucketSlug, bucketBackup)\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func(context.Context, string, bool) bool); ok {\n\t\tr0 = rf(ctx, bucketSlug, bucketBackup)\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {\n\t\tr1 = rf(ctx, bucketSlug, bucketBackup)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// WaitForHealthy provides a mock function with given fields:\nfunc (_m *Client) WaitForHealthy() chan error {\n\tret := _m.Called()\n\n\tvar r0 chan error\n\tif rf, ok := ret.Get(0).(func() chan error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(chan error)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// WaitForInitialized provides a mock function with given fields:\nfunc (_m *Client) WaitForInitialized() chan bool {\n\tret := _m.Called()\n\n\tvar r0 chan bool\n\tif rf, ok := ret.Get(0).(func() chan bool); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(chan bool)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// WaitForReady provides a mock function with given fields:\nfunc (_m *Client) WaitForReady() chan bool {\n\tret := _m.Called()\n\n\tvar r0 chan bool\n\tif rf, ok := ret.Get(0).(func() chan bool); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(chan bool)\n\t\t}\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/FilesSearchEngine.go",
    "content": "// Code generated by mockery v2.0.3. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tcontext \"context\"\n\n\tsearch \"github.com/FleekHQ/space-daemon/core/search\"\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// FilesSearchEngine is an autogenerated mock type for the FilesSearchEngine type\ntype FilesSearchEngine struct {\n\tmock.Mock\n}\n\n// DeleteFileData provides a mock function with given fields: ctx, data\nfunc (_m *FilesSearchEngine) DeleteFileData(ctx context.Context, data *search.DeleteIndexRecord) error {\n\tret := _m.Called(ctx, data)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, *search.DeleteIndexRecord) error); ok {\n\t\tr0 = rf(ctx, data)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// InsertFileData provides a mock function with given fields: ctx, data\nfunc (_m *FilesSearchEngine) InsertFileData(ctx context.Context, data *search.InsertIndexRecord) (*search.IndexRecord, error) {\n\tret := _m.Called(ctx, data)\n\n\tvar r0 *search.IndexRecord\n\tif rf, ok := ret.Get(0).(func(context.Context, *search.InsertIndexRecord) *search.IndexRecord); ok {\n\t\tr0 = rf(ctx, data)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*search.IndexRecord)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *search.InsertIndexRecord) error); ok {\n\t\tr1 = rf(ctx, data)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// QueryFileData provides a mock function with given fields: ctx, query, limit\nfunc (_m *FilesSearchEngine) QueryFileData(ctx context.Context, query string, limit int) ([]*search.IndexRecord, error) {\n\tret := _m.Called(ctx, query, limit)\n\n\tvar r0 []*search.IndexRecord\n\tif rf, ok := ret.Get(0).(func(context.Context, string, int) []*search.IndexRecord); ok {\n\t\tr0 = rf(ctx, query, limit)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*search.IndexRecord)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, int) error); ok {\n\t\tr1 = rf(ctx, query, limit)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Start provides a mock function with given fields:\nfunc (_m *FilesSearchEngine) Start() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/HubAuth.go",
    "content": "// Code generated by mockery v2.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tcontext \"context\"\n\n\thub \"github.com/FleekHQ/space-daemon/core/textile/hub\"\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// HubAuth is an autogenerated mock type for the HubAuth type\ntype HubAuth struct {\n\tmock.Mock\n}\n\n// ClearCache provides a mock function with given fields:\nfunc (_m *HubAuth) ClearCache() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// GetHubContext provides a mock function with given fields: ctx\nfunc (_m *HubAuth) GetHubContext(ctx context.Context) (context.Context, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 context.Context\n\tif rf, ok := ret.Get(0).(func(context.Context) context.Context); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(context.Context)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetTokensWithCache provides a mock function with given fields: ctx\nfunc (_m *HubAuth) GetTokensWithCache(ctx context.Context) (*hub.AuthTokens, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 *hub.AuthTokens\n\tif rf, ok := ret.Get(0).(func(context.Context) *hub.AuthTokens); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*hub.AuthTokens)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "mocks/Keychain.go",
    "content": "// Code generated by mockery v2.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tkeychain \"github.com/FleekHQ/space-daemon/core/keychain\"\n\tcrypto \"github.com/libp2p/go-libp2p-core/crypto\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tpermissions \"github.com/FleekHQ/space-daemon/core/permissions\"\n\n\tthread \"github.com/textileio/go-threads/core/thread\"\n)\n\n// Keychain is an autogenerated mock type for the Keychain type\ntype Keychain struct {\n\tmock.Mock\n}\n\n// DeleteKeypair provides a mock function with given fields:\nfunc (_m *Keychain) DeleteKeypair() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// GenerateKeyFromMnemonic provides a mock function with given fields: _a0\nfunc (_m *Keychain) GenerateKeyFromMnemonic(_a0 ...keychain.GenerateKeyFromMnemonicOpts) (string, error) {\n\t_va := make([]interface{}, len(_a0))\n\tfor _i := range _a0 {\n\t\t_va[_i] = _a0[_i]\n\t}\n\tvar _ca []interface{}\n\t_ca = append(_ca, _va...)\n\tret := _m.Called(_ca...)\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func(...keychain.GenerateKeyFromMnemonicOpts) string); ok {\n\t\tr0 = rf(_a0...)\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(...keychain.GenerateKeyFromMnemonicOpts) error); ok {\n\t\tr1 = rf(_a0...)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GenerateKeyPair provides a mock function with given fields:\nfunc (_m *Keychain) GenerateKeyPair() ([]byte, []byte, error) {\n\tret := _m.Called()\n\n\tvar r0 []byte\n\tif rf, ok := ret.Get(0).(func() []byte); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]byte)\n\t\t}\n\t}\n\n\tvar r1 []byte\n\tif rf, ok := ret.Get(1).(func() []byte); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).([]byte)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func() error); ok {\n\t\tr2 = rf()\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GenerateKeyPairWithForce provides a mock function with given fields:\nfunc (_m *Keychain) GenerateKeyPairWithForce() ([]byte, []byte, error) {\n\tret := _m.Called()\n\n\tvar r0 []byte\n\tif rf, ok := ret.Get(0).(func() []byte); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]byte)\n\t\t}\n\t}\n\n\tvar r1 []byte\n\tif rf, ok := ret.Get(1).(func() []byte); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).([]byte)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func() error); ok {\n\t\tr2 = rf()\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GetAppToken provides a mock function with given fields: key\nfunc (_m *Keychain) GetAppToken(key string) (*permissions.AppToken, error) {\n\tret := _m.Called(key)\n\n\tvar r0 *permissions.AppToken\n\tif rf, ok := ret.Get(0).(func(string) *permissions.AppToken); ok {\n\t\tr0 = rf(key)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*permissions.AppToken)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(key)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetManagedThreadKey provides a mock function with given fields: threadKeyName\nfunc (_m *Keychain) GetManagedThreadKey(threadKeyName string) (thread.Key, error) {\n\tret := _m.Called(threadKeyName)\n\n\tvar r0 thread.Key\n\tif rf, ok := ret.Get(0).(func(string) thread.Key); ok {\n\t\tr0 = rf(threadKeyName)\n\t} else {\n\t\tr0 = ret.Get(0).(thread.Key)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(threadKeyName)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetStoredKeyPairInLibP2PFormat provides a mock function with given fields:\nfunc (_m *Keychain) GetStoredKeyPairInLibP2PFormat() (crypto.PrivKey, crypto.PubKey, error) {\n\tret := _m.Called()\n\n\tvar r0 crypto.PrivKey\n\tif rf, ok := ret.Get(0).(func() crypto.PrivKey); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(crypto.PrivKey)\n\t\t}\n\t}\n\n\tvar r1 crypto.PubKey\n\tif rf, ok := ret.Get(1).(func() crypto.PubKey); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tif ret.Get(1) != nil {\n\t\t\tr1 = ret.Get(1).(crypto.PubKey)\n\t\t}\n\t}\n\n\tvar r2 error\n\tif rf, ok := ret.Get(2).(func() error); ok {\n\t\tr2 = rf()\n\t} else {\n\t\tr2 = ret.Error(2)\n\t}\n\n\treturn r0, r1, r2\n}\n\n// GetStoredMnemonic provides a mock function with given fields:\nfunc (_m *Keychain) GetStoredMnemonic() (string, error) {\n\tret := _m.Called()\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func() string); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetStoredPublicKey provides a mock function with given fields:\nfunc (_m *Keychain) GetStoredPublicKey() (crypto.PubKey, error) {\n\tret := _m.Called()\n\n\tvar r0 crypto.PubKey\n\tif rf, ok := ret.Get(0).(func() crypto.PubKey); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(crypto.PubKey)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ImportExistingKeyPair provides a mock function with given fields: priv, mnemonic\nfunc (_m *Keychain) ImportExistingKeyPair(priv crypto.PrivKey, mnemonic string) error {\n\tret := _m.Called(priv, mnemonic)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(crypto.PrivKey, string) error); ok {\n\t\tr0 = rf(priv, mnemonic)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Sign provides a mock function with given fields: _a0\nfunc (_m *Keychain) Sign(_a0 []byte) ([]byte, error) {\n\tret := _m.Called(_a0)\n\n\tvar r0 []byte\n\tif rf, ok := ret.Get(0).(func([]byte) []byte); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]byte)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func([]byte) error); ok {\n\t\tr1 = rf(_a0)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// StoreAppToken provides a mock function with given fields: tok\nfunc (_m *Keychain) StoreAppToken(tok *permissions.AppToken) error {\n\tret := _m.Called(tok)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(*permissions.AppToken) error); ok {\n\t\tr0 = rf(tok)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/Keyring.go",
    "content": "// Code generated by mockery v2.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tkeyring \"github.com/99designs/keyring\"\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// Keyring is an autogenerated mock type for the Keyring type\ntype Keyring struct {\n\tmock.Mock\n}\n\n// Get provides a mock function with given fields: _a0\nfunc (_m *Keyring) Get(_a0 string) (keyring.Item, error) {\n\tret := _m.Called(_a0)\n\n\tvar r0 keyring.Item\n\tif rf, ok := ret.Get(0).(func(string) keyring.Item); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tr0 = ret.Get(0).(keyring.Item)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(_a0)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetMetadata provides a mock function with given fields: _a0\nfunc (_m *Keyring) GetMetadata(_a0 string) (keyring.Metadata, error) {\n\tret := _m.Called(_a0)\n\n\tvar r0 keyring.Metadata\n\tif rf, ok := ret.Get(0).(func(string) keyring.Metadata); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tr0 = ret.Get(0).(keyring.Metadata)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(_a0)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Remove provides a mock function with given fields: _a0\nfunc (_m *Keyring) Remove(_a0 string) error {\n\tret := _m.Called(_a0)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(string) error); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Set provides a mock function with given fields: _a0\nfunc (_m *Keyring) Set(_a0 keyring.Item) error {\n\tret := _m.Called(_a0)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(keyring.Item) error); ok {\n\t\tr0 = rf(_a0)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/Mailbox.go",
    "content": "// Code generated by mockery v1.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tclient \"github.com/textileio/textile/v2/api/usersd/client\"\n\tcmd \"github.com/textileio/textile/v2/cmd\"\n\n\tcontext \"context\"\n\n\tlocal \"github.com/textileio/textile/v2/mail/local\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tthread \"github.com/textileio/go-threads/core/thread\"\n)\n\n// Mailbox is an autogenerated mock type for the Mailbox type\ntype Mailbox struct {\n\tmock.Mock\n}\n\n// Identity provides a mock function with given fields:\nfunc (_m *Mailbox) Identity() thread.Identity {\n\tret := _m.Called()\n\n\tvar r0 thread.Identity\n\tif rf, ok := ret.Get(0).(func() thread.Identity); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(thread.Identity)\n\t\t}\n\t}\n\n\treturn r0\n}\n\n// ListInboxMessages provides a mock function with given fields: ctx, opts\nfunc (_m *Mailbox) ListInboxMessages(ctx context.Context, opts ...client.ListOption) ([]client.Message, error) {\n\t_va := make([]interface{}, len(opts))\n\tfor _i := range opts {\n\t\t_va[_i] = opts[_i]\n\t}\n\tvar _ca []interface{}\n\t_ca = append(_ca, ctx)\n\t_ca = append(_ca, _va...)\n\tret := _m.Called(_ca...)\n\n\tvar r0 []client.Message\n\tif rf, ok := ret.Get(0).(func(context.Context, ...client.ListOption) []client.Message); ok {\n\t\tr0 = rf(ctx, opts...)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]client.Message)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, ...client.ListOption) error); ok {\n\t\tr1 = rf(ctx, opts...)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// SendMessage provides a mock function with given fields: ctx, to, body\nfunc (_m *Mailbox) SendMessage(ctx context.Context, to thread.PubKey, body []byte) (client.Message, error) {\n\tret := _m.Called(ctx, to, body)\n\n\tvar r0 client.Message\n\tif rf, ok := ret.Get(0).(func(context.Context, thread.PubKey, []byte) client.Message); ok {\n\t\tr0 = rf(ctx, to, body)\n\t} else {\n\t\tr0 = ret.Get(0).(client.Message)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, thread.PubKey, []byte) error); ok {\n\t\tr1 = rf(ctx, to, body)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// WatchInbox provides a mock function with given fields: ctx, mevents, offline\nfunc (_m *Mailbox) WatchInbox(ctx context.Context, mevents chan<- local.MailboxEvent, offline bool) (<-chan cmd.WatchState, error) {\n\tret := _m.Called(ctx, mevents, offline)\n\n\tvar r0 <-chan cmd.WatchState\n\tif rf, ok := ret.Get(0).(func(context.Context, chan<- local.MailboxEvent, bool) <-chan cmd.WatchState); ok {\n\t\tr0 = rf(ctx, mevents, offline)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(<-chan cmd.WatchState)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, chan<- local.MailboxEvent, bool) error); ok {\n\t\tr1 = rf(ctx, mevents, offline)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "mocks/Model.go",
    "content": "// Code generated by mockery v1.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tcontext \"context\"\n\n\tdomain \"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tmodel \"github.com/FleekHQ/space-daemon/core/textile/model\"\n)\n\n// Model is an autogenerated mock type for the Model type\ntype Model struct {\n\tmock.Mock\n}\n\n// BucketBackupToggle provides a mock function with given fields: ctx, bucketSlug, backup\nfunc (_m *Model) BucketBackupToggle(ctx context.Context, bucketSlug string, backup bool) (*model.BucketSchema, error) {\n\tret := _m.Called(ctx, bucketSlug, backup)\n\n\tvar r0 *model.BucketSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, bool) *model.BucketSchema); ok {\n\t\tr0 = rf(ctx, bucketSlug, backup)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.BucketSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {\n\t\tr1 = rf(ctx, bucketSlug, backup)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateBucket provides a mock function with given fields: ctx, bucketSlug, dbID\nfunc (_m *Model) CreateBucket(ctx context.Context, bucketSlug string, dbID string) (*model.BucketSchema, error) {\n\tret := _m.Called(ctx, bucketSlug, dbID)\n\n\tvar r0 *model.BucketSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string) *model.BucketSchema); ok {\n\t\tr0 = rf(ctx, bucketSlug, dbID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.BucketSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {\n\t\tr1 = rf(ctx, bucketSlug, dbID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateMirrorBucket provides a mock function with given fields: ctx, bucketSlug, mirrorBucket\nfunc (_m *Model) CreateMirrorBucket(ctx context.Context, bucketSlug string, mirrorBucket *model.MirrorBucketSchema) (*model.BucketSchema, error) {\n\tret := _m.Called(ctx, bucketSlug, mirrorBucket)\n\n\tvar r0 *model.BucketSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, *model.MirrorBucketSchema) *model.BucketSchema); ok {\n\t\tr0 = rf(ctx, bucketSlug, mirrorBucket)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.BucketSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, *model.MirrorBucketSchema) error); ok {\n\t\tr1 = rf(ctx, bucketSlug, mirrorBucket)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateMirrorFile provides a mock function with given fields: ctx, mirrorFile\nfunc (_m *Model) CreateMirrorFile(ctx context.Context, mirrorFile *domain.MirrorFile) (*model.MirrorFileSchema, error) {\n\tret := _m.Called(ctx, mirrorFile)\n\n\tvar r0 *model.MirrorFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, *domain.MirrorFile) *model.MirrorFileSchema); ok {\n\t\tr0 = rf(ctx, mirrorFile)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.MirrorFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *domain.MirrorFile) error); ok {\n\t\tr1 = rf(ctx, mirrorFile)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateReceivedFileViaInvitation provides a mock function with given fields: ctx, file, invitationId, accepted, key, sharedBy\nfunc (_m *Model) CreateReceivedFileViaInvitation(ctx context.Context, file domain.FullPath, invitationId string, accepted bool, key []byte, sharedBy string) (*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, file, invitationId, accepted, key, sharedBy)\n\n\tvar r0 *model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, domain.FullPath, string, bool, []byte, string) *model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, file, invitationId, accepted, key, sharedBy)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, domain.FullPath, string, bool, []byte, string) error); ok {\n\t\tr1 = rf(ctx, file, invitationId, accepted, key, sharedBy)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateReceivedFileViaPublicLink provides a mock function with given fields: ctx, ipfsHash, password, filename, filesize, accepted\nfunc (_m *Model) CreateReceivedFileViaPublicLink(ctx context.Context, ipfsHash string, password string, filename string, filesize string, accepted bool) (*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, ipfsHash, password, filename, filesize, accepted)\n\n\tvar r0 *model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, bool) *model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, ipfsHash, password, filename, filesize, accepted)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, bool) error); ok {\n\t\tr1 = rf(ctx, ipfsHash, password, filename, filesize, accepted)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateSentFileViaInvitation provides a mock function with given fields: ctx, file, invitationId, key\nfunc (_m *Model) CreateSentFileViaInvitation(ctx context.Context, file domain.FullPath, invitationId string, key []byte) (*model.SentFileSchema, error) {\n\tret := _m.Called(ctx, file, invitationId, key)\n\n\tvar r0 *model.SentFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, domain.FullPath, string, []byte) *model.SentFileSchema); ok {\n\t\tr0 = rf(ctx, file, invitationId, key)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.SentFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, domain.FullPath, string, []byte) error); ok {\n\t\tr1 = rf(ctx, file, invitationId, key)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// CreateSharedPublicKey provides a mock function with given fields: ctx, pubKey\nfunc (_m *Model) CreateSharedPublicKey(ctx context.Context, pubKey string) (*model.SharedPublicKeySchema, error) {\n\tret := _m.Called(ctx, pubKey)\n\n\tvar r0 *model.SharedPublicKeySchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *model.SharedPublicKeySchema); ok {\n\t\tr0 = rf(ctx, pubKey)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.SharedPublicKeySchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, pubKey)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// DeleteReceivedFiles provides a mock function with given fields: ctx, paths, keys\nfunc (_m *Model) DeleteReceivedFiles(ctx context.Context, paths []domain.FullPath, keys [][]byte) error {\n\tret := _m.Called(ctx, paths, keys)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, []domain.FullPath, [][]byte) error); ok {\n\t\tr0 = rf(ctx, paths, keys)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// DeleteSearchIndexRecord provides a mock function with given fields: ctx, name, path, bucketSlug, dbId\nfunc (_m *Model) DeleteSearchIndexRecord(ctx context.Context, name string, path string, bucketSlug string, dbId string) error {\n\tret := _m.Called(ctx, name, path, bucketSlug, dbId)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok {\n\t\tr0 = rf(ctx, name, path, bucketSlug, dbId)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// FindBucket provides a mock function with given fields: ctx, bucketSlug\nfunc (_m *Model) FindBucket(ctx context.Context, bucketSlug string) (*model.BucketSchema, error) {\n\tret := _m.Called(ctx, bucketSlug)\n\n\tvar r0 *model.BucketSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *model.BucketSchema); ok {\n\t\tr0 = rf(ctx, bucketSlug)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.BucketSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, bucketSlug)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FindMirrorFileByPathAndBucketSlug provides a mock function with given fields: ctx, path, bucketSlug\nfunc (_m *Model) FindMirrorFileByPathAndBucketSlug(ctx context.Context, path string, bucketSlug string) (*model.MirrorFileSchema, error) {\n\tret := _m.Called(ctx, path, bucketSlug)\n\n\tvar r0 *model.MirrorFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string) *model.MirrorFileSchema); ok {\n\t\tr0 = rf(ctx, path, bucketSlug)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.MirrorFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {\n\t\tr1 = rf(ctx, path, bucketSlug)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FindMirrorFileByPaths provides a mock function with given fields: ctx, paths\nfunc (_m *Model) FindMirrorFileByPaths(ctx context.Context, paths []string) (map[string]*model.MirrorFileSchema, error) {\n\tret := _m.Called(ctx, paths)\n\n\tvar r0 map[string]*model.MirrorFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, []string) map[string]*model.MirrorFileSchema); ok {\n\t\tr0 = rf(ctx, paths)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(map[string]*model.MirrorFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, []string) error); ok {\n\t\tr1 = rf(ctx, paths)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FindPublicLinkReceivedFile provides a mock function with given fields: ctx, ipfsHash\nfunc (_m *Model) FindPublicLinkReceivedFile(ctx context.Context, ipfsHash string) (*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, ipfsHash)\n\n\tvar r0 *model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, ipfsHash)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, ipfsHash)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FindReceivedFile provides a mock function with given fields: ctx, remoteDbID, bucket, path\nfunc (_m *Model) FindReceivedFile(ctx context.Context, remoteDbID string, bucket string, path string) (*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, remoteDbID, bucket, path)\n\n\tvar r0 *model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string, string) *model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, remoteDbID, bucket, path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {\n\t\tr1 = rf(ctx, remoteDbID, bucket, path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FindReceivedFilesByIds provides a mock function with given fields: ctx, ids\nfunc (_m *Model) FindReceivedFilesByIds(ctx context.Context, ids []string) ([]*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, ids)\n\n\tvar r0 []*model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, []string) []*model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, ids)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, []string) error); ok {\n\t\tr1 = rf(ctx, ids)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// FindSentFile provides a mock function with given fields: ctx, remoteDbID, bucket, path\nfunc (_m *Model) FindSentFile(ctx context.Context, remoteDbID string, bucket string, path string) (*model.SentFileSchema, error) {\n\tret := _m.Called(ctx, remoteDbID, bucket, path)\n\n\tvar r0 *model.SentFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string, string) *model.SentFileSchema); ok {\n\t\tr0 = rf(ctx, remoteDbID, bucket, path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.SentFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {\n\t\tr1 = rf(ctx, remoteDbID, bucket, path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// InitSearchIndexCollection provides a mock function with given fields: ctx\nfunc (_m *Model) InitSearchIndexCollection(ctx context.Context) error {\n\tret := _m.Called(ctx)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context) error); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// ListBuckets provides a mock function with given fields: ctx\nfunc (_m *Model) ListBuckets(ctx context.Context) ([]*model.BucketSchema, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []*model.BucketSchema\n\tif rf, ok := ret.Get(0).(func(context.Context) []*model.BucketSchema); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.BucketSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ListReceivedFiles provides a mock function with given fields: ctx, accepted, seek, limit\nfunc (_m *Model) ListReceivedFiles(ctx context.Context, accepted bool, seek string, limit int) ([]*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, accepted, seek, limit)\n\n\tvar r0 []*model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, bool, string, int) []*model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, accepted, seek, limit)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, bool, string, int) error); ok {\n\t\tr1 = rf(ctx, accepted, seek, limit)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ListReceivedPublicFiles provides a mock function with given fields: ctx, cidHash, accepted\nfunc (_m *Model) ListReceivedPublicFiles(ctx context.Context, cidHash string, accepted bool) ([]*model.ReceivedFileSchema, error) {\n\tret := _m.Called(ctx, cidHash, accepted)\n\n\tvar r0 []*model.ReceivedFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, bool) []*model.ReceivedFileSchema); ok {\n\t\tr0 = rf(ctx, cidHash, accepted)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.ReceivedFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {\n\t\tr1 = rf(ctx, cidHash, accepted)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ListSentFiles provides a mock function with given fields: ctx, seek, limit\nfunc (_m *Model) ListSentFiles(ctx context.Context, seek string, limit int) ([]*model.SentFileSchema, error) {\n\tret := _m.Called(ctx, seek, limit)\n\n\tvar r0 []*model.SentFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, int) []*model.SentFileSchema); ok {\n\t\tr0 = rf(ctx, seek, limit)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.SentFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, int) error); ok {\n\t\tr1 = rf(ctx, seek, limit)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// ListSharedPublicKeys provides a mock function with given fields: ctx\nfunc (_m *Model) ListSharedPublicKeys(ctx context.Context) ([]*model.SharedPublicKeySchema, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []*model.SharedPublicKeySchema\n\tif rf, ok := ret.Get(0).(func(context.Context) []*model.SharedPublicKeySchema); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.SharedPublicKeySchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// QuerySearchIndex provides a mock function with given fields: ctx, query\nfunc (_m *Model) QuerySearchIndex(ctx context.Context, query string) ([]*model.SearchIndexRecord, error) {\n\tret := _m.Called(ctx, query)\n\n\tvar r0 []*model.SearchIndexRecord\n\tif rf, ok := ret.Get(0).(func(context.Context, string) []*model.SearchIndexRecord); ok {\n\t\tr0 = rf(ctx, query)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*model.SearchIndexRecord)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, query)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// UpdateMirrorFile provides a mock function with given fields: ctx, mirrorFile\nfunc (_m *Model) UpdateMirrorFile(ctx context.Context, mirrorFile *model.MirrorFileSchema) (*model.MirrorFileSchema, error) {\n\tret := _m.Called(ctx, mirrorFile)\n\n\tvar r0 *model.MirrorFileSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, *model.MirrorFileSchema) *model.MirrorFileSchema); ok {\n\t\tr0 = rf(ctx, mirrorFile)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.MirrorFileSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *model.MirrorFileSchema) error); ok {\n\t\tr1 = rf(ctx, mirrorFile)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// UpdateSearchIndexRecord provides a mock function with given fields: ctx, name, path, itemType, bucketSlug, dbId\nfunc (_m *Model) UpdateSearchIndexRecord(ctx context.Context, name string, path string, itemType model.SearchItemType, bucketSlug string, dbId string) (*model.SearchIndexRecord, error) {\n\tret := _m.Called(ctx, name, path, itemType, bucketSlug, dbId)\n\n\tvar r0 *model.SearchIndexRecord\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string, model.SearchItemType, string, string) *model.SearchIndexRecord); ok {\n\t\tr0 = rf(ctx, name, path, itemType, bucketSlug, dbId)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.SearchIndexRecord)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string, model.SearchItemType, string, string) error); ok {\n\t\tr1 = rf(ctx, name, path, itemType, bucketSlug, dbId)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// UpsertBucket provides a mock function with given fields: ctx, bucketSlug, dbID\nfunc (_m *Model) UpsertBucket(ctx context.Context, bucketSlug string, dbID string) (*model.BucketSchema, error) {\n\tret := _m.Called(ctx, bucketSlug, dbID)\n\n\tvar r0 *model.BucketSchema\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string) *model.BucketSchema); ok {\n\t\tr0 = rf(ctx, bucketSlug, dbID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*model.BucketSchema)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {\n\t\tr1 = rf(ctx, bucketSlug, dbID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "mocks/Store.go",
    "content": "// Code generated by mockery v2.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport mock \"github.com/stretchr/testify/mock\"\n\n// Store is an autogenerated mock type for the Store type\ntype Store struct {\n\tmock.Mock\n}\n\n// Close provides a mock function with given fields:\nfunc (_m *Store) Close() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// DropAll provides a mock function with given fields:\nfunc (_m *Store) DropAll() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Get provides a mock function with given fields: key\nfunc (_m *Store) Get(key []byte) ([]byte, error) {\n\tret := _m.Called(key)\n\n\tvar r0 []byte\n\tif rf, ok := ret.Get(0).(func([]byte) []byte); ok {\n\t\tr0 = rf(key)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]byte)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func([]byte) error); ok {\n\t\tr1 = rf(key)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// IsOpen provides a mock function with given fields:\nfunc (_m *Store) IsOpen() bool {\n\tret := _m.Called()\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func() bool); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\treturn r0\n}\n\n// KeysWithPrefix provides a mock function with given fields: prefix\nfunc (_m *Store) KeysWithPrefix(prefix string) ([]string, error) {\n\tret := _m.Called(prefix)\n\n\tvar r0 []string\n\tif rf, ok := ret.Get(0).(func(string) []string); ok {\n\t\tr0 = rf(prefix)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]string)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string) error); ok {\n\t\tr1 = rf(prefix)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Open provides a mock function with given fields:\nfunc (_m *Store) Open() error {\n\tret := _m.Called()\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func() error); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Remove provides a mock function with given fields: key\nfunc (_m *Store) Remove(key []byte) error {\n\tret := _m.Called(key)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func([]byte) error); ok {\n\t\tr0 = rf(key)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Set provides a mock function with given fields: key, value\nfunc (_m *Store) Set(key []byte, value []byte) error {\n\tret := _m.Called(key, value)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {\n\t\tr0 = rf(key, value)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// SetString provides a mock function with given fields: key, value\nfunc (_m *Store) SetString(key string, value string) error {\n\tret := _m.Called(key, value)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(string, string) error); ok {\n\t\tr0 = rf(key, value)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/Syncer.go",
    "content": "// Code generated by mockery v2.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tdomain \"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// Syncer is an autogenerated mock type for the Syncer type\ntype Syncer struct {\n\tmock.Mock\n}\n\n// AddFileWatch provides a mock function with given fields: addFileInfo\nfunc (_m *Syncer) AddFileWatch(addFileInfo domain.AddWatchFile) error {\n\tret := _m.Called(addFileInfo)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(domain.AddWatchFile) error); ok {\n\t\tr0 = rf(addFileInfo)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// GetOpenFilePath provides a mock function with given fields: bucketSlug, bucketPath, dbID, cid\nfunc (_m *Syncer) GetOpenFilePath(bucketSlug string, bucketPath string, dbID string, cid string) (string, bool) {\n\tret := _m.Called(bucketSlug, bucketPath, dbID, cid)\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func(string, string, string, string) string); ok {\n\t\tr0 = rf(bucketSlug, bucketPath, dbID, cid)\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\tvar r1 bool\n\tif rf, ok := ret.Get(1).(func(string, string, string, string) bool); ok {\n\t\tr1 = rf(bucketSlug, bucketPath, dbID, cid)\n\t} else {\n\t\tr1 = ret.Get(1).(bool)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "mocks/Vault.go",
    "content": "// Code generated by mockery v1.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tdomain \"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tvault \"github.com/FleekHQ/space-daemon/core/vault\"\n)\n\n// Vault is an autogenerated mock type for the Vault type\ntype Vault struct {\n\tmock.Mock\n}\n\n// Retrieve provides a mock function with given fields: uuid, passphrase, backupType\nfunc (_m *Vault) Retrieve(uuid string, passphrase string, backupType domain.KeyBackupType) ([]vault.VaultItem, error) {\n\tret := _m.Called(uuid, passphrase, backupType)\n\n\tvar r0 []vault.VaultItem\n\tif rf, ok := ret.Get(0).(func(string, string, domain.KeyBackupType) []vault.VaultItem); ok {\n\t\tr0 = rf(uuid, passphrase, backupType)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]vault.VaultItem)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string, string, domain.KeyBackupType) error); ok {\n\t\tr1 = rf(uuid, passphrase, backupType)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Store provides a mock function with given fields: uuid, passphrase, backupType, apiToken, items\nfunc (_m *Vault) Store(uuid string, passphrase string, backupType domain.KeyBackupType, apiToken string, items []vault.VaultItem) (*vault.StoredVault, error) {\n\tret := _m.Called(uuid, passphrase, backupType, apiToken, items)\n\n\tvar r0 *vault.StoredVault\n\tif rf, ok := ret.Get(0).(func(string, string, domain.KeyBackupType, string, []vault.VaultItem) *vault.StoredVault); ok {\n\t\tr0 = rf(uuid, passphrase, backupType, apiToken, items)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*vault.StoredVault)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(string, string, domain.KeyBackupType, string, []vault.VaultItem) error); ok {\n\t\tr1 = rf(uuid, passphrase, backupType, apiToken, items)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "mocks/fuse/FSDataSource.go",
    "content": "// Code generated by mockery v2.0.3. DO NOT EDIT.\n\npackage fuse\n\nimport (\n\tcontext \"context\"\n\n\tfsds \"github.com/FleekHQ/space-daemon/core/fsds\"\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tos \"os\"\n)\n\n// FSDataSource is an autogenerated mock type for the FSDataSource type\ntype FSDataSource struct {\n\tmock.Mock\n}\n\n// CreateEntry provides a mock function with given fields: ctx, path, mode\nfunc (_m *FSDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*fsds.DirEntry, error) {\n\tret := _m.Called(ctx, path, mode)\n\n\tvar r0 *fsds.DirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, string, os.FileMode) *fsds.DirEntry); ok {\n\t\tr0 = rf(ctx, path, mode)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*fsds.DirEntry)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string, os.FileMode) error); ok {\n\t\tr1 = rf(ctx, path, mode)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// DeleteEntry provides a mock function with given fields: ctx, path\nfunc (_m *FSDataSource) DeleteEntry(ctx context.Context, path string) error {\n\tret := _m.Called(ctx, path)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, string) error); ok {\n\t\tr0 = rf(ctx, path)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// Get provides a mock function with given fields: ctx, path\nfunc (_m *FSDataSource) Get(ctx context.Context, path string) (*fsds.DirEntry, error) {\n\tret := _m.Called(ctx, path)\n\n\tvar r0 *fsds.DirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *fsds.DirEntry); ok {\n\t\tr0 = rf(ctx, path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*fsds.DirEntry)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// GetChildren provides a mock function with given fields: ctx, path\nfunc (_m *FSDataSource) GetChildren(ctx context.Context, path string) ([]*fsds.DirEntry, error) {\n\tret := _m.Called(ctx, path)\n\n\tvar r0 []*fsds.DirEntry\n\tif rf, ok := ret.Get(0).(func(context.Context, string) []*fsds.DirEntry); ok {\n\t\tr0 = rf(ctx, path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*fsds.DirEntry)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// Open provides a mock function with given fields: ctx, path\nfunc (_m *FSDataSource) Open(ctx context.Context, path string) (fsds.FileReadWriterCloser, error) {\n\tret := _m.Called(ctx, path)\n\n\tvar r0 fsds.FileReadWriterCloser\n\tif rf, ok := ret.Get(0).(func(context.Context, string) fsds.FileReadWriterCloser); ok {\n\t\tr0 = rf(ctx, path)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(fsds.FileReadWriterCloser)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, path)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// RenameEntry provides a mock function with given fields: ctx, oldPath, newPath\nfunc (_m *FSDataSource) RenameEntry(ctx context.Context, oldPath string, newPath string) error {\n\tret := _m.Called(ctx, oldPath, newPath)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {\n\t\tr0 = rf(ctx, oldPath, newPath)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/fuse/FuseInstaller.go",
    "content": "// Code generated by mockery v2.0.3. DO NOT EDIT.\n\npackage fuse\n\nimport (\n\tcontext \"context\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// FuseInstaller is an autogenerated mock type for the FuseInstaller type\ntype FuseInstaller struct {\n\tmock.Mock\n}\n\n// Install provides a mock function with given fields: ctx, args\nfunc (_m *FuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {\n\tret := _m.Called(ctx, args)\n\n\tvar r0 error\n\tif rf, ok := ret.Get(0).(func(context.Context, map[string]interface{}) error); ok {\n\t\tr0 = rf(ctx, args)\n\t} else {\n\t\tr0 = ret.Error(0)\n\t}\n\n\treturn r0\n}\n\n// IsInstalled provides a mock function with given fields: ctx\nfunc (_m *FuseInstaller) IsInstalled(ctx context.Context) (bool, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func(context.Context) bool); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "mocks/mock.go",
    "content": "package mocks\n\nimport \"github.com/stretchr/testify/mock\"\n\n// Common utils and helpers can go here\n\n// NOTE: mocks generated using https://github.com/vektra/mockery\n\n\ntype Path struct {\n\tmock.Mock\n}\n\nfunc (m Path) String() string {\n\targs := m.Called()\n\treturn args.String(0)\n}\n\nfunc (m Path) Namespace() string {\n\tpanic(\"implement me\")\n}\n\nfunc (m Path) Mutable() bool {\n\tpanic(\"implement me\")\n}\n\nfunc (m Path) IsValid() error {\n\tpanic(\"implement me\")\n}\n\n\n"
  },
  {
    "path": "mocks/mock_config.go",
    "content": "// Code generated by mockery v2.2.1. DO NOT EDIT.\n\npackage mocks\n\nimport mock \"github.com/stretchr/testify/mock\"\n\n// Config is an autogenerated mock type for the Config type\ntype Config struct {\n\tmock.Mock\n}\n\n// GetBool provides a mock function with given fields: key, defaultValue\nfunc (_m *Config) GetBool(key string, defaultValue interface{}) bool {\n\tret := _m.Called(key, defaultValue)\n\n\tvar r0 bool\n\tif rf, ok := ret.Get(0).(func(string, interface{}) bool); ok {\n\t\tr0 = rf(key, defaultValue)\n\t} else {\n\t\tr0 = ret.Get(0).(bool)\n\t}\n\n\treturn r0\n}\n\n// GetInt provides a mock function with given fields: key, defaultValue\nfunc (_m *Config) GetInt(key string, defaultValue interface{}) int {\n\tret := _m.Called(key, defaultValue)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(string, interface{}) int); ok {\n\t\tr0 = rf(key, defaultValue)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\treturn r0\n}\n\n// GetString provides a mock function with given fields: key, defaultValue\nfunc (_m *Config) GetString(key string, defaultValue interface{}) string {\n\tret := _m.Called(key, defaultValue)\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func(string, interface{}) string); ok {\n\t\tr0 = rf(key, defaultValue)\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/mock_env.go",
    "content": "// Code generated by mockery v2.0.0-alpha.2. DO NOT EDIT.\n\npackage mocks\n\nimport mock \"github.com/stretchr/testify/mock\"\n\n// SpaceEnv is an autogenerated mock type for the SpaceEnv type\ntype SpaceEnv struct {\n\tmock.Mock\n}\n\n// CurrentFolder provides a mock function with given fields:\nfunc (_m *SpaceEnv) CurrentFolder() (string, error) {\n\tret := _m.Called()\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func() string); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// LogLevel provides a mock function with given fields:\nfunc (_m *SpaceEnv) LogLevel() string {\n\tret := _m.Called()\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func() string); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\treturn r0\n}\n\n// WorkingFolder provides a mock function with given fields:\nfunc (_m *SpaceEnv) WorkingFolder() string {\n\tret := _m.Called()\n\n\tvar r0 string\n\tif rf, ok := ret.Get(0).(func() string); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(string)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "mocks/mock_textile_handler.go",
    "content": "// Code generated by mockery v1.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tevents \"github.com/FleekHQ/space-daemon/core/events\"\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\n// TextileNotifier is an autogenerated mock type for the TextileNotifier type\ntype TextileNotifier struct {\n\tmock.Mock\n}\n\n// SendTextileEvent provides a mock function with given fields: event\nfunc (_m *TextileNotifier) SendTextileEvent(event events.TextileEvent) {\n\t_m.Called(event)\n}\n"
  },
  {
    "path": "mocks/mock_textile_users_client.go",
    "content": "// Code generated by mockery v1.0.0. DO NOT EDIT.\n\npackage mocks\n\nimport (\n\tcontext \"context\"\n\n\tclient \"github.com/textileio/textile/v2/api/usersd/client\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n\n\tthread \"github.com/textileio/go-threads/core/thread\"\n)\n\n// UsersClient is an autogenerated mock type for the UsersClient type\ntype UsersClient struct {\n\tmock.Mock\n}\n\n// ListInboxMessages provides a mock function with given fields: ctx, opts\nfunc (_m *UsersClient) ListInboxMessages(ctx context.Context, opts ...client.ListOption) ([]client.Message, error) {\n\t_va := make([]interface{}, len(opts))\n\tfor _i := range opts {\n\t\t_va[_i] = opts[_i]\n\t}\n\tvar _ca []interface{}\n\t_ca = append(_ca, ctx)\n\t_ca = append(_ca, _va...)\n\tret := _m.Called(_ca...)\n\n\tvar r0 []client.Message\n\tif rf, ok := ret.Get(0).(func(context.Context, ...client.ListOption) []client.Message); ok {\n\t\tr0 = rf(ctx, opts...)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]client.Message)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, ...client.ListOption) error); ok {\n\t\tr1 = rf(ctx, opts...)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// SendMessage provides a mock function with given fields: ctx, from, to, body\nfunc (_m *UsersClient) SendMessage(ctx context.Context, from thread.Identity, to thread.PubKey, body []byte) (client.Message, error) {\n\tret := _m.Called(ctx, from, to, body)\n\n\tvar r0 client.Message\n\tif rf, ok := ret.Get(0).(func(context.Context, thread.Identity, thread.PubKey, []byte) client.Message); ok {\n\t\tr0 = rf(ctx, from, to, body)\n\t} else {\n\t\tr0 = ret.Get(0).(client.Message)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, thread.Identity, thread.PubKey, []byte) error); ok {\n\t\tr1 = rf(ctx, from, to, body)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n\n// SetupMailbox provides a mock function with given fields: ctx\nfunc (_m *UsersClient) SetupMailbox(ctx context.Context) (thread.ID, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 thread.ID\n\tif rf, ok := ret.Get(0).(func(context.Context) thread.ID); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tr0 = ret.Get(0).(thread.ID)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "scripts/windows.bat",
    "content": "@ECHO off\n\nREM Delete credentials associated with space daemon\nFOR /F \"tokens=2\" %%c IN ('@CMDKEY /list ^| @FINDSTR space:space') DO (@CMDKEY /delete:%%c)\n\nREM Delete folders created by space daemon\n@RD /S /Q \"C:\\\\Users\\\\%USERNAME%\\\\.fleek-ipfs\"\n@RD /S /Q \"C:\\\\Users\\\\%USERNAME%\\\\.fleek-space\"\n@RD /S /Q \"C:\\\\Users\\\\%USERNAME%\\\\.buckd\"\n\n@ECHO Removed credentials and deleted space daemon associated folders successfully."
  },
  {
    "path": "swagger/ui/space.swagger.json",
    "content": "{\n  \"swagger\": \"2.0\",\n  \"info\": {\n    \"title\": \"space.proto\",\n    \"version\": \"version not set\"\n  },\n  \"consumes\": [\n    \"application/json\"\n  ],\n  \"produces\": [\n    \"application/json\"\n  ],\n  \"paths\": {\n    \"/v1/apiSessionTokens\": {\n      \"get\": {\n        \"operationId\": \"SpaceApi_GetAPISessionTokens\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetAPISessionTokensResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/appTokens\": {\n      \"post\": {\n        \"summary\": \"Generates an app token with scoped access.\",\n        \"operationId\": \"SpaceApi_GenerateAppToken\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGenerateAppTokenResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGenerateAppTokenRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/appTokens/master\": {\n      \"post\": {\n        \"summary\": \"Initialize master app token\\nApp tokens are used to authorize scoped access to a range of methods\\nMaster token can only be generated once and has access to all methods\",\n        \"operationId\": \"SpaceApi_InitializeMasterAppToken\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceInitializeMasterAppTokenResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceInitializeMasterAppTokenRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/backup\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_ToggleBucketBackup\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceToggleBucketBackupResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceToggleBucketBackupRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/backup/restore\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_BucketBackupRestore\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceBucketBackupRestoreResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceBucketBackupRestoreRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/buckets\": {\n      \"get\": {\n        \"operationId\": \"SpaceApi_ListBuckets\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceListBucketsResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      },\n      \"post\": {\n        \"summary\": \"Create a new bucket owned by current user (aka keypair)\",\n        \"operationId\": \"SpaceApi_CreateBucket\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceCreateBucketResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceCreateBucketRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/buckets/{bucket}/generatePublicFileLink\": {\n      \"post\": {\n        \"summary\": \"Generates a copy of the file that's accessible through IPFS gateways\",\n        \"operationId\": \"SpaceApi_GeneratePublicFileLink\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGeneratePublicFileLinkResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"bucket\",\n            \"in\": \"path\",\n            \"required\": true,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGeneratePublicFileLinkRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/buckets/{bucket}/join\": {\n      \"post\": {\n        \"summary\": \"Join bucket\",\n        \"operationId\": \"SpaceApi_JoinBucket\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceJoinBucketResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"bucket\",\n            \"in\": \"path\",\n            \"required\": true,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceJoinBucketRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/buckets/{bucket}/share\": {\n      \"post\": {\n        \"summary\": \"Share bucket\",\n        \"operationId\": \"SpaceApi_ShareBucket\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceShareBucketResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"bucket\",\n            \"in\": \"path\",\n            \"required\": true,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceShareBucketRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/deleteAccount\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_DeleteAccount\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceDeleteAccountResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceDeleteAccountRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/directories\": {\n      \"get\": {\n        \"summary\": \"Get the folder or files in the path directory.\\nUnlike ListDirectories, this only returns immediate children at path.\",\n        \"operationId\": \"SpaceApi_ListDirectory\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceListDirectoryResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"path\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"bucket\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"omitMembers\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"boolean\",\n            \"format\": \"boolean\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      },\n      \"post\": {\n        \"summary\": \"Creates a folder/directory at the specified path\",\n        \"operationId\": \"SpaceApi_CreateFolder\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceCreateFolderResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceCreateFolderRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/directories/all\": {\n      \"get\": {\n        \"summary\": \"Get all folder or files in the default bucket. It fetches all subdirectories too.\",\n        \"operationId\": \"SpaceApi_ListDirectories\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceListDirectoriesResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"bucket\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"omitMembers\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"boolean\",\n            \"format\": \"boolean\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/files\": {\n      \"delete\": {\n        \"summary\": \"Removes a file or dir from a bucket\",\n        \"operationId\": \"SpaceApi_RemoveDirOrFile\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRemoveDirOrFileResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"path\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"bucket\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      },\n      \"post\": {\n        \"summary\": \"Adds items (files/folders) to be uploaded to the bucket.\",\n        \"operationId\": \"SpaceApi_AddItems\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.(streaming responses)\",\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"result\": {\n                  \"$ref\": \"#/definitions/spaceAddItemsResponse\"\n                },\n                \"error\": {\n                  \"$ref\": \"#/definitions/runtimeStreamError\"\n                }\n              },\n              \"title\": \"Stream result of spaceAddItemsResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceAddItemsRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/files/open\": {\n      \"post\": {\n        \"summary\": \"Open a file in the daemon.\\nDaemon keeps track of all open files and closes them if no activity is noticed after a while\",\n        \"operationId\": \"SpaceApi_OpenFile\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceOpenFileResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceOpenFileRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/files/openPublic\": {\n      \"get\": {\n        \"summary\": \"Open an encrypted public shared file in the daemon.\\nThis requires the decryption key and file hash/cid to work\",\n        \"operationId\": \"SpaceApi_OpenPublicFile\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceOpenPublicFileResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"fileCid\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"password\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"filename\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/files/sharedByMe\": {\n      \"get\": {\n        \"summary\": \"Gets the files that are shared by the sender\",\n        \"operationId\": \"SpaceApi_GetSharedByMeFiles\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetSharedByMeFilesResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"seek\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"limit\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\",\n            \"format\": \"int64\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/files/sharedWithMe\": {\n      \"get\": {\n        \"summary\": \"Gets the files that are shared with this recipient\",\n        \"operationId\": \"SpaceApi_GetSharedWithMeFiles\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetSharedWithMeFilesResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"seek\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"limit\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\",\n            \"format\": \"int64\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/filesinvitation/{invitationID}\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_HandleFilesInvitation\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceHandleFilesInvitationResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"invitationID\",\n            \"in\": \"path\",\n            \"required\": true,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceHandleFilesInvitationRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/fuse\": {\n      \"get\": {\n        \"summary\": \"Get status of FUSE drive. If mounted or unmounted\",\n        \"operationId\": \"SpaceApi_GetFuseDriveStatus\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceFuseDriveResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/keypairs/delete\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_DeleteKeyPair\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceDeleteKeyPairResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceDeleteKeyPairRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/keypairs/forceGenerate\": {\n      \"post\": {\n        \"summary\": \"Force Generation of KeyPair. This will override existing keys stored in daemon.\",\n        \"operationId\": \"SpaceApi_GenerateKeyPairWithForce\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGenerateKeyPairResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGenerateKeyPairRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/keypairs/generate\": {\n      \"post\": {\n        \"summary\": \"Generate Key Pair for current account.\\nThis will return error if daemon account already has keypairs\",\n        \"operationId\": \"SpaceApi_GenerateKeyPair\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGenerateKeyPairResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGenerateKeyPairRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/keypairs/mnemonic\": {\n      \"get\": {\n        \"operationId\": \"SpaceApi_GetStoredMnemonic\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetStoredMnemonicResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/keypairs/restoreWithMnemonic\": {\n      \"post\": {\n        \"summary\": \"Restores a keypair given a mnemonic.\\nThis will override any existing key pair\",\n        \"operationId\": \"SpaceApi_RestoreKeyPairViaMnemonic\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRestoreKeyPairViaMnemonicResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRestoreKeyPairViaMnemonicRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/localBackups/backup\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_CreateLocalKeysBackup\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceCreateLocalKeysBackupResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceCreateLocalKeysBackupRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/localBackups/recover\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_RecoverKeysByLocalBackup\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRecoverKeysByLocalBackupResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRecoverKeysByLocalBackupRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/notifications\": {\n      \"get\": {\n        \"operationId\": \"SpaceApi_GetNotifications\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetNotificationsResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"seek\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"limit\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\",\n            \"format\": \"int64\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/notifications/lastSeenAt\": {\n      \"post\": {\n        \"summary\": \"This will set the last read timestamp for the user so that the client\\ncan check if newer notifications are present for UX\",\n        \"operationId\": \"SpaceApi_SetNotificationsLastSeenAt\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceSetNotificationsLastSeenAtResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceSetNotificationsLastSeenAtRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/notifications/{ID}/read\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_ReadNotification\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceReadNotificationResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"ID\",\n            \"in\": \"path\",\n            \"required\": true,\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceReadNotificationRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/passphrases/backup\": {\n      \"post\": {\n        \"summary\": \"Backup Key by Passphrase\",\n        \"operationId\": \"SpaceApi_BackupKeysByPassphrase\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceBackupKeysByPassphraseResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceBackupKeysByPassphraseRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/passphrases/recover\": {\n      \"post\": {\n        \"summary\": \"Recover Keys by Passphrase\",\n        \"operationId\": \"SpaceApi_RecoverKeysByPassphrase\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRecoverKeysByPassphraseResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceRecoverKeysByPassphraseRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/passphrases/test\": {\n      \"post\": {\n        \"summary\": \"Tests a passphrase to see if it matches the one previously used\",\n        \"operationId\": \"SpaceApi_TestKeysPassphrase\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceTestKeysPassphraseResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceTestKeysPassphraseRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/publicKey\": {\n      \"post\": {\n        \"operationId\": \"SpaceApi_GetPublicKey\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetPublicKeyResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetPublicKeyRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/search/files\": {\n      \"get\": {\n        \"summary\": \"Search for files across all users bucket\",\n        \"operationId\": \"SpaceApi_SearchFiles\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceSearchFilesResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"query\",\n            \"in\": \"query\",\n            \"required\": false,\n            \"type\": \"string\"\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/shareFilesViaPublicKey\": {\n      \"post\": {\n        \"summary\": \"Share bucket via public key using Textile Hub inboxing\",\n        \"operationId\": \"SpaceApi_ShareFilesViaPublicKey\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceShareFilesViaPublicKeyResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceShareFilesViaPublicKeyRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/sharedWithList\": {\n      \"get\": {\n        \"summary\": \"Returns a list of addresses / public keys of clients to which files where shared or received, ordered by date\",\n        \"operationId\": \"SpaceApi_GetRecentlySharedWith\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetRecentlySharedWithResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/subscriptions/file\": {\n      \"get\": {\n        \"summary\": \"Subscribe to file events. This streams responses to the caller\",\n        \"operationId\": \"SpaceApi_Subscribe\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.(streaming responses)\",\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"result\": {\n                  \"$ref\": \"#/definitions/spaceFileEventResponse\"\n                },\n                \"error\": {\n                  \"$ref\": \"#/definitions/runtimeStreamError\"\n                }\n              },\n              \"title\": \"Stream result of spaceFileEventResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/subscriptions/notification\": {\n      \"get\": {\n        \"operationId\": \"SpaceApi_NotificationSubscribe\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.(streaming responses)\",\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"result\": {\n                  \"$ref\": \"#/definitions/spaceNotificationEventResponse\"\n                },\n                \"error\": {\n                  \"$ref\": \"#/definitions/runtimeStreamError\"\n                }\n              },\n              \"title\": \"Stream result of spaceNotificationEventResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/subscriptions/textile\": {\n      \"get\": {\n        \"summary\": \"Subscribe to textile events. This streams responses to the caller\",\n        \"operationId\": \"SpaceApi_TxlSubscribe\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.(streaming responses)\",\n            \"schema\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"result\": {\n                  \"$ref\": \"#/definitions/spaceTextileEventResponse\"\n                },\n                \"error\": {\n                  \"$ref\": \"#/definitions/runtimeStreamError\"\n                }\n              },\n              \"title\": \"Stream result of spaceTextileEventResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/toggleFuse\": {\n      \"post\": {\n        \"summary\": \"Toggle FUSE drive to be mounted or unmounted\",\n        \"operationId\": \"SpaceApi_ToggleFuseDrive\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceFuseDriveResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"parameters\": [\n          {\n            \"name\": \"body\",\n            \"in\": \"body\",\n            \"required\": true,\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceToggleFuseRequest\"\n            }\n          }\n        ],\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    },\n    \"/v1/usage\": {\n      \"get\": {\n        \"operationId\": \"SpaceApi_GetUsageInfo\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"A successful response.\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/spaceGetUsageInfoResponse\"\n            }\n          },\n          \"default\": {\n            \"description\": \"An unexpected error response\",\n            \"schema\": {\n              \"$ref\": \"#/definitions/runtimeError\"\n            }\n          }\n        },\n        \"tags\": [\n          \"SpaceApi\"\n        ]\n      }\n    }\n  },\n  \"definitions\": {\n    \"protobufAny\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type_url\": {\n          \"type\": \"string\"\n        },\n        \"value\": {\n          \"type\": \"string\",\n          \"format\": \"byte\"\n        }\n      }\n    },\n    \"runtimeError\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"error\": {\n          \"type\": \"string\"\n        },\n        \"code\": {\n          \"type\": \"integer\",\n          \"format\": \"int32\"\n        },\n        \"message\": {\n          \"type\": \"string\"\n        },\n        \"details\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/protobufAny\"\n          }\n        }\n      }\n    },\n    \"runtimeStreamError\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"grpc_code\": {\n          \"type\": \"integer\",\n          \"format\": \"int32\"\n        },\n        \"http_code\": {\n          \"type\": \"integer\",\n          \"format\": \"int32\"\n        },\n        \"message\": {\n          \"type\": \"string\"\n        },\n        \"http_status\": {\n          \"type\": \"string\"\n        },\n        \"details\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/protobufAny\"\n          }\n        }\n      }\n    },\n    \"spaceAddItemResult\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"sourcePath\": {\n          \"type\": \"string\"\n        },\n        \"bucketPath\": {\n          \"type\": \"string\"\n        },\n        \"error\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceAddItemsRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"sourcePaths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"title\": \"full paths to file or Folder on FS. Needs to be a location available to the daemon\"\n        },\n        \"targetPath\": {\n          \"type\": \"string\",\n          \"description\": \"target path in bucket.\"\n        },\n        \"bucket\": {\n          \"type\": \"string\",\n          \"title\": \"The bucket in which to save the item\"\n        }\n      }\n    },\n    \"spaceAddItemsResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"result\": {\n          \"$ref\": \"#/definitions/spaceAddItemResult\"\n        },\n        \"totalFiles\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"totalBytes\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"completedFiles\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"completedBytes\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        }\n      }\n    },\n    \"spaceAllowedMethod\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"methodName\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceBackupKeysByPassphraseRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"uuid\": {\n          \"type\": \"string\"\n        },\n        \"passphrase\": {\n          \"type\": \"string\"\n        },\n        \"type\": {\n          \"$ref\": \"#/definitions/spaceKeyBackupType\"\n        }\n      }\n    },\n    \"spaceBackupKeysByPassphraseResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceBucket\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"key\": {\n          \"type\": \"string\"\n        },\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"path\": {\n          \"type\": \"string\"\n        },\n        \"createdAt\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"updatedAt\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"members\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceBucketMember\"\n          }\n        },\n        \"isPersonalBucket\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        },\n        \"isBackupEnabled\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        },\n        \"itemsCount\": {\n          \"type\": \"integer\",\n          \"format\": \"int32\"\n        }\n      }\n    },\n    \"spaceBucketBackupRestoreRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"bucket\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceBucketBackupRestoreResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceBucketMember\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"address\": {\n          \"type\": \"string\"\n        },\n        \"publicKey\": {\n          \"type\": \"string\"\n        },\n        \"isOwner\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        },\n        \"hasJoined\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceCreateBucketRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"slug\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceCreateBucketResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"bucket\": {\n          \"$ref\": \"#/definitions/spaceBucket\"\n        }\n      }\n    },\n    \"spaceCreateFolderRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"path\": {\n          \"type\": \"string\",\n          \"title\": \"target path in bucket to add new empty folder\"\n        },\n        \"bucket\": {\n          \"type\": \"string\",\n          \"title\": \"The bucket in which to add the folder\"\n        }\n      }\n    },\n    \"spaceCreateFolderResponse\": {\n      \"type\": \"object\",\n      \"title\": \"not sure we need to return anything other than an error if we failed\"\n    },\n    \"spaceCreateLocalKeysBackupRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"pathToKeyBackup\": {\n          \"type\": \"string\",\n          \"title\": \"The path in which to save the backup\"\n        }\n      }\n    },\n    \"spaceCreateLocalKeysBackupResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceDeleteAccountRequest\": {\n      \"type\": \"object\"\n    },\n    \"spaceDeleteAccountResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceDeleteKeyPairRequest\": {\n      \"type\": \"object\"\n    },\n    \"spaceDeleteKeyPairResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceEventType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"ENTRY_ADDED\",\n        \"ENTRY_DELETED\",\n        \"ENTRY_UPDATED\",\n        \"ENTRY_BACKUP_IN_PROGRESS\",\n        \"ENTRY_BACKUP_READY\",\n        \"ENTRY_RESTORE_IN_PROGRESS\",\n        \"ENTRY_RESTORE_READY\",\n        \"FOLDER_ADDED\",\n        \"FOLDER_DELETED\",\n        \"FOLDER_UPDATED\"\n      ],\n      \"default\": \"ENTRY_ADDED\"\n    },\n    \"spaceFileEventResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"$ref\": \"#/definitions/spaceEventType\"\n        },\n        \"entry\": {\n          \"$ref\": \"#/definitions/spaceListDirectoryEntry\"\n        },\n        \"bucket\": {\n          \"type\": \"string\"\n        },\n        \"dbId\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceFileMember\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"publicKey\": {\n          \"type\": \"string\"\n        },\n        \"address\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceFullPath\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"dbId\": {\n          \"type\": \"string\"\n        },\n        \"bucket\": {\n          \"type\": \"string\"\n        },\n        \"path\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceFuseDriveResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"state\": {\n          \"$ref\": \"#/definitions/spaceFuseState\"\n        }\n      }\n    },\n    \"spaceFuseState\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"UNSUPPORTED\",\n        \"NOT_INSTALLED\",\n        \"UNMOUNTED\",\n        \"MOUNTED\"\n      ],\n      \"default\": \"UNSUPPORTED\"\n    },\n    \"spaceGenerateAppTokenRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"allowedMethods\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceAllowedMethod\"\n          }\n        }\n      }\n    },\n    \"spaceGenerateAppTokenResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"appToken\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGenerateKeyPairRequest\": {\n      \"type\": \"object\"\n    },\n    \"spaceGenerateKeyPairResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"mnemonic\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGeneratePublicFileLinkRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"bucket\": {\n          \"type\": \"string\"\n        },\n        \"itemPaths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"password\": {\n          \"type\": \"string\"\n        },\n        \"dbId\": {\n          \"type\": \"string\",\n          \"title\": \"optional field to specify db id\\nfor shared with me files\"\n        }\n      }\n    },\n    \"spaceGeneratePublicFileLinkResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"link\": {\n          \"type\": \"string\"\n        },\n        \"fileCid\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGetAPISessionTokensResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"hubToken\": {\n          \"type\": \"string\"\n        },\n        \"servicesToken\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGetNotificationsResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"notifications\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceNotification\"\n          }\n        },\n        \"nextOffset\": {\n          \"type\": \"string\"\n        },\n        \"lastSeenAt\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        }\n      }\n    },\n    \"spaceGetPublicKeyRequest\": {\n      \"type\": \"object\"\n    },\n    \"spaceGetPublicKeyResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"publicKey\": {\n          \"type\": \"string\",\n          \"title\": \"Public key encoded in hex\"\n        }\n      }\n    },\n    \"spaceGetRecentlySharedWithResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"members\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceFileMember\"\n          }\n        }\n      }\n    },\n    \"spaceGetSharedByMeFilesResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"items\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceSharedListDirectoryEntry\"\n          }\n        },\n        \"nextOffset\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGetSharedWithMeFilesResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"items\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceSharedListDirectoryEntry\"\n          }\n        },\n        \"nextOffset\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGetStoredMnemonicResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"mnemonic\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceGetUsageInfoResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"localStarogeUsed\": {\n          \"type\": \"string\",\n          \"format\": \"uint64\"\n        },\n        \"localBandwidthUsed\": {\n          \"type\": \"string\",\n          \"format\": \"uint64\"\n        },\n        \"spaceStorageUsed\": {\n          \"type\": \"string\",\n          \"format\": \"uint64\"\n        },\n        \"spaceBandwidthUsed\": {\n          \"type\": \"string\",\n          \"format\": \"uint64\"\n        },\n        \"usageQuota\": {\n          \"type\": \"string\",\n          \"format\": \"uint64\"\n        }\n      }\n    },\n    \"spaceHandleFilesInvitationRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"invitationID\": {\n          \"type\": \"string\"\n        },\n        \"accept\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceHandleFilesInvitationResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceInitializeMasterAppTokenRequest\": {\n      \"type\": \"object\"\n    },\n    \"spaceInitializeMasterAppTokenResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"appToken\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceInvitation\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"inviterPublicKey\": {\n          \"type\": \"string\"\n        },\n        \"invitationID\": {\n          \"type\": \"string\"\n        },\n        \"status\": {\n          \"$ref\": \"#/definitions/spaceInvitationStatus\"\n        },\n        \"itemPaths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceFullPath\"\n          }\n        }\n      }\n    },\n    \"spaceInvitationAccept\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"invitationID\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceInvitationStatus\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"PENDING\",\n        \"ACCEPTED\",\n        \"REJECTED\"\n      ],\n      \"default\": \"PENDING\"\n    },\n    \"spaceJoinBucketRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"threadinfo\": {\n          \"$ref\": \"#/definitions/spaceThreadInfo\"\n        },\n        \"bucket\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceJoinBucketResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"result\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceKeyBackupType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"PASSWORD\",\n        \"ETH\"\n      ],\n      \"default\": \"PASSWORD\"\n    },\n    \"spaceListBucketsResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"buckets\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceBucket\"\n          }\n        }\n      }\n    },\n    \"spaceListDirectoriesResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"entries\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceListDirectoryEntry\"\n          }\n        }\n      }\n    },\n    \"spaceListDirectoryEntry\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"path\": {\n          \"type\": \"string\"\n        },\n        \"isDir\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        },\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"sizeInBytes\": {\n          \"type\": \"string\"\n        },\n        \"created\": {\n          \"type\": \"string\"\n        },\n        \"updated\": {\n          \"type\": \"string\"\n        },\n        \"fileExtension\": {\n          \"type\": \"string\"\n        },\n        \"ipfsHash\": {\n          \"type\": \"string\"\n        },\n        \"isLocallyAvailable\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        },\n        \"backupCount\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"members\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceFileMember\"\n          }\n        },\n        \"isBackupInProgress\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        },\n        \"isRestoreInProgress\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceListDirectoryResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"entries\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceListDirectoryEntry\"\n          }\n        }\n      }\n    },\n    \"spaceNotification\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"ID\": {\n          \"type\": \"string\"\n        },\n        \"subject\": {\n          \"type\": \"string\"\n        },\n        \"body\": {\n          \"type\": \"string\"\n        },\n        \"invitationValue\": {\n          \"$ref\": \"#/definitions/spaceInvitation\"\n        },\n        \"usageAlert\": {\n          \"$ref\": \"#/definitions/spaceUsageAlert\"\n        },\n        \"invitationAccept\": {\n          \"$ref\": \"#/definitions/spaceInvitationAccept\"\n        },\n        \"type\": {\n          \"$ref\": \"#/definitions/spaceNotificationType\"\n        },\n        \"createdAt\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"readAt\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        }\n      }\n    },\n    \"spaceNotificationEventResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"notification\": {\n          \"$ref\": \"#/definitions/spaceNotification\"\n        }\n      }\n    },\n    \"spaceNotificationType\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"UNKNOWN\",\n        \"INVITATION\",\n        \"USAGEALERT\",\n        \"INVITATION_REPLY\"\n      ],\n      \"default\": \"UNKNOWN\"\n    },\n    \"spaceOpenFileRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"path\": {\n          \"type\": \"string\"\n        },\n        \"bucket\": {\n          \"type\": \"string\"\n        },\n        \"dbId\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceOpenFileResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"location\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceOpenPublicFileResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"location\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceReadNotificationRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"ID\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceReadNotificationResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceRecoverKeysByLocalBackupRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"pathToKeyBackup\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceRecoverKeysByLocalBackupResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceRecoverKeysByPassphraseRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"uuid\": {\n          \"type\": \"string\"\n        },\n        \"passphrase\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceRecoverKeysByPassphraseResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceRemoveDirOrFileResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceRestoreKeyPairViaMnemonicRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"mnemonic\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceRestoreKeyPairViaMnemonicResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceSearchFilesDirectoryEntry\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"entry\": {\n          \"$ref\": \"#/definitions/spaceListDirectoryEntry\"\n        },\n        \"dbId\": {\n          \"type\": \"string\"\n        },\n        \"bucket\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceSearchFilesResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"entries\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceSearchFilesDirectoryEntry\"\n          }\n        },\n        \"query\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceSetNotificationsLastSeenAtRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"timestamp\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        }\n      }\n    },\n    \"spaceSetNotificationsLastSeenAtResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceShareBucketRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"bucket\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceShareBucketResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"threadinfo\": {\n          \"$ref\": \"#/definitions/spaceThreadInfo\"\n        }\n      }\n    },\n    \"spaceShareFilesViaPublicKeyRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"publicKeys\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"paths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/definitions/spaceFullPath\"\n          }\n        }\n      }\n    },\n    \"spaceShareFilesViaPublicKeyResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceSharedListDirectoryEntry\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"entry\": {\n          \"$ref\": \"#/definitions/spaceListDirectoryEntry\"\n        },\n        \"dbId\": {\n          \"type\": \"string\"\n        },\n        \"bucket\": {\n          \"type\": \"string\"\n        },\n        \"isPublicLink\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceTestKeysPassphraseRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"uuid\": {\n          \"type\": \"string\"\n        },\n        \"passphrase\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceTestKeysPassphraseResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceTextileEventResponse\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"bucket\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceThreadInfo\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"addresses\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"key\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"spaceToggleBucketBackupRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"bucket\": {\n          \"type\": \"string\"\n        },\n        \"backup\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceToggleBucketBackupResponse\": {\n      \"type\": \"object\"\n    },\n    \"spaceToggleFuseRequest\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"mountDrive\": {\n          \"type\": \"boolean\",\n          \"format\": \"boolean\"\n        }\n      }\n    },\n    \"spaceUsageAlert\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"used\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"limit\": {\n          \"type\": \"string\",\n          \"format\": \"int64\"\n        },\n        \"message\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "tracing/tracing.go",
    "content": "package tracing\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/uber/jaeger-client-go/config\"\n\n\t\"github.com/opentracing/opentracing-go\"\n)\n\n// Initializes a tracer configuring the servicename as the app name\nfunc MustInit(appName string) (opentracing.Tracer, io.Closer) {\n\tcfg := &config.Configuration{\n\t\tServiceName: appName,\n\t\tSampler: &config.SamplerConfig{\n\t\t\tType:  \"const\",\n\t\t\tParam: 1,\n\t\t},\n\t\tReporter: &config.ReporterConfig{\n\t\t\tLogSpans: true,\n\t\t},\n\t}\n\ttracer, closer, err := cfg.NewTracer()\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"ERROR: cannot init Jaeger: %v\\n\", err))\n\t}\n\treturn tracer, closer\n}\n"
  }
]