Full Code of FleekHQ/space-daemon for AI

master 646538d0b2db cached
224 files
1.5 MB
535.6k tokens
2505 symbols
1 requests
Download .txt
Showing preview only (1,599K chars total). Download the full file or copy to clipboard to get everything.
Repository: FleekHQ/space-daemon
Branch: master
Commit: 646538d0b2db
Files: 224
Total size: 1.5 MB

Directory structure:
gitextract_hiosi7jg/

├── .github/
│   └── workflows/
│       ├── release.yml
│       └── test.yml
├── .gitignore
├── .goreleaser.yml
├── .vscode/
│   └── launch.json
├── LICENSE
├── Makefile
├── README.md
├── app/
│   └── app.go
├── ci/
│   ├── add-osx-cert.sh
│   └── gon.hcl
├── cmd/
│   └── space-daemon/
│       └── main.go
├── config/
│   ├── config.go
│   ├── json_config.go
│   └── map_config.go
├── core/
│   ├── backup/
│   │   └── backup.go
│   ├── component.go
│   ├── env/
│   │   ├── env.go
│   │   └── file_env.go
│   ├── events/
│   │   └── events.go
│   ├── fsds/
│   │   ├── config.go
│   │   ├── data_source.go
│   │   ├── dir_entry.go
│   │   ├── files_ds.go
│   │   ├── read_write_wrapper.go
│   │   ├── shared_with_me_ds.go
│   │   ├── spacefs.go
│   │   └── utils.go
│   ├── ipfs/
│   │   ├── dag.go
│   │   ├── ipfs.go
│   │   ├── node/
│   │   │   └── node.go
│   │   ├── utils.go
│   │   └── utils_test.go
│   ├── keychain/
│   │   ├── app_token.go
│   │   ├── keychain.go
│   │   ├── keyring/
│   │   │   └── keyring.go
│   │   ├── mnemonic.go
│   │   └── test/
│   │       └── keychain_test.go
│   ├── libfuse/
│   │   ├── block_size.go
│   │   ├── directory.go
│   │   ├── files.go
│   │   └── vfs.go
│   ├── permissions/
│   │   ├── app_token.go
│   │   └── app_token_test.go
│   ├── search/
│   │   ├── bleve/
│   │   │   ├── analyzer.go
│   │   │   ├── bleve.go
│   │   │   ├── bleve_test.go
│   │   │   └── options.go
│   │   ├── engines.go
│   │   ├── model.go
│   │   └── sqlite/
│   │       ├── model.go
│   │       ├── options.go
│   │       ├── sqlite.go
│   │       └── sqlite_test.go
│   ├── space/
│   │   ├── domain/
│   │   │   └── domain.go
│   │   ├── fuse/
│   │   │   ├── controller.go
│   │   │   ├── fs.go
│   │   │   ├── installer/
│   │   │   │   ├── installer_darwin.go
│   │   │   │   ├── installer_darwin_test.go
│   │   │   │   ├── installer_linux.go
│   │   │   │   ├── installer_windows.go
│   │   │   │   └── interface.go
│   │   │   ├── mount.go
│   │   │   ├── mount_windows.go
│   │   │   ├── state.go
│   │   │   └── state_test.go
│   │   ├── services/
│   │   │   ├── fs_utils.go
│   │   │   ├── services.go
│   │   │   ├── services_app_token.go
│   │   │   ├── services_central_server.go
│   │   │   ├── services_fs.go
│   │   │   ├── services_identity.go
│   │   │   ├── services_keypair.go
│   │   │   ├── services_notifs.go
│   │   │   ├── services_search.go
│   │   │   ├── services_sharing.go
│   │   │   ├── services_vault.go
│   │   │   └── sharing_utils.go
│   │   ├── space.go
│   │   └── space_test.go
│   ├── spacefs/
│   │   ├── fs.go
│   │   ├── fs_test.go
│   │   └── interfaces.go
│   ├── store/
│   │   └── store.go
│   ├── sync/
│   │   ├── fs.go
│   │   ├── notifier_default.go
│   │   ├── sync.go
│   │   ├── textile.go
│   │   └── textile_test.go
│   ├── textile/
│   │   ├── README.md
│   │   ├── account.go
│   │   ├── buckd.go
│   │   ├── bucket/
│   │   │   ├── bucket.go
│   │   │   ├── bucket_dir.go
│   │   │   ├── bucket_file.go
│   │   │   └── crypto/
│   │   │       ├── crypto.go
│   │   │       ├── crypto_test.go
│   │   │       ├── decrypter.go
│   │   │       └── encrypter.go
│   │   ├── bucket_factory.go
│   │   ├── client.go
│   │   ├── common/
│   │   │   └── common.go
│   │   ├── event_handler.go
│   │   ├── hub/
│   │   │   ├── hmacTestKey
│   │   │   ├── hub_auth.go
│   │   │   └── hub_auth_test.go
│   │   ├── listener.go
│   │   ├── mailbox.go
│   │   ├── mailbox_test.go
│   │   ├── mirror.go
│   │   ├── model/
│   │   │   ├── buckets.go
│   │   │   ├── mirror_file.go
│   │   │   ├── model.go
│   │   │   ├── received_file.go
│   │   │   ├── received_file_test.go
│   │   │   ├── search.go
│   │   │   ├── sent_file.go
│   │   │   └── shared_public_key.go
│   │   ├── notifier/
│   │   │   └── notifier.go
│   │   ├── public.go
│   │   ├── search.go
│   │   ├── secure_bucket_client.go
│   │   ├── sharing.go
│   │   ├── sync/
│   │   │   ├── mirror.go
│   │   │   ├── pinning.go
│   │   │   ├── queue.go
│   │   │   ├── restore.go
│   │   │   ├── sync.go
│   │   │   ├── sync_test.go
│   │   │   ├── synchronizer.go
│   │   │   ├── task-executors.go
│   │   │   ├── task.go
│   │   │   └── threads.go
│   │   ├── textile.go
│   │   └── utils/
│   │       ├── utils.go
│   │       └── utils_test.go
│   ├── util/
│   │   ├── address/
│   │   │   ├── PROTOCOL.md
│   │   │   └── address.go
│   │   ├── paths.go
│   │   └── rlimit/
│   │       ├── rlimit_unix.go
│   │       └── rlimit_windows.go
│   ├── vault/
│   │   ├── vault.go
│   │   └── vault_test.go
│   └── watcher/
│       ├── blacklist.go
│       ├── blacklist_windows.go
│       ├── handler.go
│       ├── options.go
│       ├── watcher.go
│       └── watcher_test.go
├── coverage/
│   └── .gitkeep
├── devtools/
│   └── googleapis/
│       ├── LICENSE
│       ├── README.grpc-gateway
│       └── google/
│           ├── api/
│           │   ├── annotations.proto
│           │   ├── http.proto
│           │   └── httpbody.proto
│           └── rpc/
│               ├── code.proto
│               ├── error_details.proto
│               └── status.proto
├── docs/
│   ├── crypto/
│   │   └── vault.md
│   └── sharing/
│       └── types-of-sharing.md
├── examples/
│   ├── ipfsLite/
│   │   └── ipfsLite.go
│   └── textileBucketsClient/
│       ├── README.md
│       ├── bucket-sync/
│       │   └── bucket-sync.go
│       ├── buckets.go
│       ├── create-thread-with-key/
│       │   └── create-thread-with-key.go
│       ├── join-thread/
│       │   └── join-thread.go
│       ├── local-buck/
│       │   └── local-buck.go
│       ├── open-share-file/
│       │   └── open-share-file.go
│       ├── set-envs
│       └── sync-test/
│           └── sync-test.go
├── go.mod
├── go.sum
├── grpc/
│   ├── auth/
│   │   ├── app_token_auth/
│   │   │   ├── app_token_auth.go
│   │   │   └── auth_from_md.go
│   │   └── middleware/
│   │       └── grpc_auth.go
│   ├── grpc.go
│   ├── handlers.go
│   ├── handlers_account.go
│   ├── handlers_app_token.go
│   ├── handlers_backup.go
│   ├── handlers_central_services.go
│   ├── handlers_fuse.go
│   ├── handlers_key_pair.go
│   ├── handlers_notif.go
│   ├── handlers_search.go
│   ├── handlers_sharing.go
│   ├── handlers_textile.go
│   ├── handlers_vault.go
│   ├── pb/
│   │   ├── space.pb.go
│   │   └── space.pb.gw.go
│   └── proto/
│       └── space.proto
├── integration_tests/
│   ├── README.md
│   ├── fixtures/
│   │   ├── app.go
│   │   ├── client.go
│   │   ├── configs.go
│   │   └── directories.go
│   ├── helpers/
│   │   ├── assertions.go
│   │   ├── directories.go
│   │   └── initialize.go
│   ├── integration_tests_suite_test.go
│   ├── sharing_test.go
│   └── uploads_test.go
├── log/
│   └── logger.go
├── mocks/
│   ├── Bucket.go
│   ├── Client.go
│   ├── FilesSearchEngine.go
│   ├── HubAuth.go
│   ├── Keychain.go
│   ├── Keyring.go
│   ├── Mailbox.go
│   ├── Model.go
│   ├── Store.go
│   ├── Syncer.go
│   ├── Vault.go
│   ├── fuse/
│   │   ├── FSDataSource.go
│   │   └── FuseInstaller.go
│   ├── mock.go
│   ├── mock_config.go
│   ├── mock_env.go
│   ├── mock_textile_handler.go
│   └── mock_textile_users_client.go
├── scripts/
│   └── windows.bat
├── swagger/
│   └── ui/
│       └── space.swagger.json
└── tracing/
    └── tracing.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/release.yml
================================================
name: Release with goreleaser
on:
  push:
    tags:
      - v*.*.*
jobs:
  build:
    runs-on: macos-latest
    name: goreleaser
    steps:
      - uses: actions/checkout@v2
      - name: Unshallow Fetch
        run: git fetch --prune --unshallow
      - uses: actions/setup-go@v2
        with:
          go-version: 1.14
      - name: Add MacOS certs
        run: cp ./ci/add-osx-cert.sh /tmp/add-osx-cert.sh && chmod +x /tmp/add-osx-cert.sh && /tmp/add-osx-cert.sh
        env:
          CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
          CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
      - name: Install gon via HomeBrew for code signing and app notarization
        run: |
          brew tap mitchellh/gon
          brew install mitchellh/gon/gon
      - name: Set stage to prd for all
        run: |
          echo "STAGE=PRD" >> $GITHUB_ENV
      - name: Set stage to dev if tagged develop
        if: endsWith(github.ref, '-dev')
        run: |
          echo "STAGE=DEV" >> $GITHUB_ENV
      - name: Set secret names
        id: secretnames
        run: |
          echo $STAGE
          echo "::set-output name=SERVICES_API_URL::SERVICES_API_URL_${STAGE}"
          echo "::set-output name=VAULT_API_URL::VAULT_API_URL_${STAGE}"
          echo "::set-output name=VAULT_SALT_SECRET::VAULT_SALT_SECRET_${STAGE}"
          echo "::set-output name=SERVICES_HUB_AUTH_URL::SERVICES_HUB_AUTH_URL_${STAGE}"
          echo "::set-output name=TXL_HUB_TARGET::TXL_HUB_TARGET_${STAGE}"
          echo "::set-output name=TXL_HUB_MA::TXL_HUB_MA_${STAGE}"
          echo "::set-output name=TXL_THREADS_TARGET::TXL_THREADS_TARGET_${STAGE}"
          echo "::set-output name=TXL_HUB_GATEWAY_URL::TXL_HUB_GATEWAY_URL_${STAGE}"
          echo "::set-output name=TXL_USER_KEY::TXL_USER_KEY_${STAGE}"
          echo "::set-output name=TXL_USER_SECRET::TXL_USER_SECRET_${STAGE}"
          echo "::set-output name=SPACE_STORAGE_SITE_URL::SPACE_STORAGE_SITE_URL_${STAGE}"
      - name: Release via goreleaser
        uses: goreleaser/goreleaser-action@master
        with:
          args: release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          IPFS_ADDR: ${{ secrets.IPFS_ADDR }}
          IPFS_NODE_ADDR: ${{ secrets.IPFS_NODE_ADDR }}
          IPFS_NODE_PATH: ${{ secrets.IPFS_NODE_PATH }}
          SERVICES_API_URL: ${{ secrets[steps.secretnames.outputs.SERVICES_API_URL] }}
          VAULT_API_URL: ${{ secrets[steps.secretnames.outputs.VAULT_API_URL] }}
          VAULT_SALT_SECRET: ${{ secrets[steps.secretnames.outputs.VAULT_SALT_SECRET] }}
          SERVICES_HUB_AUTH_URL: ${{ secrets[steps.secretnames.outputs.SERVICES_HUB_AUTH_URL] }}
          TXL_HUB_TARGET: ${{ secrets[steps.secretnames.outputs.TXL_HUB_TARGET] }}
          TXL_HUB_MA: ${{ secrets[steps.secretnames.outputs.TXL_HUB_MA] }}
          TXL_THREADS_TARGET: ${{ secrets[steps.secretnames.outputs.TXL_THREADS_TARGET] }}
          TXL_HUB_GATEWAY_URL: ${{ secrets[steps.secretnames.outputs.TXL_HUB_GATEWAY_URL] }}
          TXL_USER_KEY: ${{ secrets[steps.secretnames.outputs.TXL_USER_KEY] }}
          TXL_USER_SECRET: ${{ secrets[steps.secretnames.outputs.TXL_USER_SECRET] }}
          SPACE_STORAGE_SITE_URL: ${{ secrets[steps.secretnames.outputs.SPACE_STORAGE_SITE_URL] }}


================================================
FILE: .github/workflows/test.yml
================================================
#on: [push, pull_request]
on: [pull_request]
name: Test
jobs:
  unit-test:
    strategy:
      matrix:
        go-version: [1.14.x]
        platform: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.platform }}
    steps:
      - name: Install Go
        uses: actions/setup-go@v2
        with:
          go-version: ${{ matrix.go-version }}
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Unit Test
        if: ${{ matrix.platform != 'windows-latest' }}
        run: go test -race -coverprofile=coverage/unitcoverage.out $(go list ./... | grep -v integration_tests)
      - name: Unit Test (Win)
        if: ${{ matrix.platform == 'windows-latest' }} # skipping coverage collection on windows
        run: go test -race $(go list ./... | grep -v integration_tests)
      - name: Coveralls
        if: ${{ matrix.platform != 'windows-latest' }}
        uses: shogo82148/actions-goveralls@v1
        with:
          flag-name: unit-test-${{ matrix.platform }}
          path-to-profile: coverage/unitcoverage.out
          parallel: true
  integration-test:
    strategy:
      matrix:
        go-version: [ 1.14.x ]
#        platform: [ ubuntu-latest, macos-latest, windows-latest ]
        platform: [ macos-latest ]
    runs-on: ${{ matrix.platform }}
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      SERVICES_API_URL: ${{ secrets.outputs.SERVICES_API_URL_DEV }}
      VAULT_API_URL: ${{ secrets.VAULT_API_URL_DEV }}
      VAULT_SALT_SECRET: ${{ secrets.VAULT_SALT_SECRET_DEV }}
      SERVICES_HUB_AUTH_URL: ${{ secrets.SERVICES_HUB_AUTH_URL_DEV }}
      TXL_HUB_TARGET: ${{ secrets.TXL_HUB_TARGET_DEV }}
      TXL_HUB_MA: ${{ secrets.TXL_HUB_MA_DEV }}
      TXL_THREADS_TARGET: ${{ secrets.TXL_THREADS_TARGET_DEV }}
      TXL_HUB_GATEWAY_URL: ${{ secrets.TXL_HUB_GATEWAY_URL_DEV }}
      TXL_USER_KEY: ${{ secrets.TXL_USER_KEY_DEV }}
      TXL_USER_SECRET: ${{ secrets.TXL_USER_SECRET_DEV }}
      SPACE_STORAGE_SITE_URL: ${{ secrets.SPACE_STORAGE_SITE_URL_DEV }}
    steps:
      - name: Install Go
        uses: actions/setup-go@v2
        with:
          go-version: ${{ matrix.go-version }}
      - name: Install gnome-keyring (Ubuntu)
        if: ${{ matrix.platform == 'ubuntu-latest' }}
        run: sudo apt-get install pass gnome-keyring dbus-x11
      - name: Verify gnome-keyring is installed (Ubuntu)
        if: ${{ matrix.platform == 'ubuntu-latest' }}
        run: gnome-keyring-daemon -V
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Integration Test
        if: ${{ matrix.platform != 'windows-latest' }}
        run: go test -v -timeout 60m -coverprofile=coverage/integrationcoverage.out ./integration_tests/...
      - name: Integration Test (Win)
        if: ${{ matrix.platform == 'windows-latest' }} # skipping coverage collection on windows
        run: go test -v -timeout 60m ./integration_tests/...
      - name: Coveralls
        if: ${{ matrix.platform != 'windows-latest' }}
        uses: shogo82148/actions-goveralls@v1
        with:
          flag-name: integration-test-${{ matrix.platform }}
          path-to-profile: coverage/integrationcoverage.out
          parallel: true
  submit-coverage:
    needs: [unit-test, integration-test]
    runs-on: ubuntu-latest
    steps:
      - name: Coveralls Finished
        uses: shogo82148/actions-goveralls@v1
        with:
          parallel-finished: true

================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
coverage/*
!coverage/.gitkeep

# Dependency directories (remove the comment below to include it)
# vendor/

.idea/
debug/
.DS_Store

.env
space.json
bin

debug/

dist/
main
devtools/grpc-ecosystem
__debug_bin

================================================
FILE: .goreleaser.yml
================================================
# Make sure to check the documentation at http://goreleaser.com
before:
  hooks:
    # You may remove this if you don't use go modules.
    - go mod download
    # you may remove this if you don't need go generate
    # - go generate ./...
project_name: space
builds:
  - id: space
    # env:
    #   - CGO_ENABLED=0
    ldflags:
      - -s -w -X  main.spaceapi={{ .Env.SERVICES_API_URL }}
      - -X main.vaultapi={{ .Env.VAULT_API_URL }}
      - -X main.vaultsaltsecret={{ .Env.VAULT_SALT_SECRET }}
      - -X main.spacehubauth={{ .Env.SERVICES_HUB_AUTH_URL }}
      - -X main.textilehub={{ .Env.TXL_HUB_TARGET }}
      - -X main.textilehubma={{ .Env.TXL_HUB_MA }}
      - -X main.textilethreads={{ .Env.TXL_THREADS_TARGET }}
      - -X main.textilehubgatewayurl={{ .Env.TXL_HUB_GATEWAY_URL }}
      - -X main.textileuserkey={{ .Env.TXL_USER_KEY }}
      - -X main.textileusersecret={{ .Env.TXL_USER_SECRET }}
      - -X main.spacestoragesiteurl={{ .Env.SPACE_STORAGE_SITE_URL }}
      - -X main.ipfsaddr={{ .Env.IPFS_ADDR }}
      - -X main.ipfsnodeaddr={{ .Env.IPFS_NODE_ADDR }}
      - -X main.ipfsnodepath={{ .Env.IPFS_NODE_PATH }}
    main: ./cmd/space-daemon/main.go
    binary: space
    goos:
      - linux

  - id: space-darwin
    # env:
    #   - CGO_ENABLED=0
    ldflags:
      - -s -w -X main.spaceapi={{ .Env.SERVICES_API_URL }}
      - -X main.vaultapi={{ .Env.VAULT_API_URL }}
      - -X main.vaultsaltsecret={{ .Env.VAULT_SALT_SECRET }}
      - -X main.spacehubauth={{ .Env.SERVICES_HUB_AUTH_URL }}
      - -X main.textilehub={{ .Env.TXL_HUB_TARGET }}
      - -X main.textilehubma={{ .Env.TXL_HUB_MA }}
      - -X main.textilethreads={{ .Env.TXL_THREADS_TARGET }}
      - -X main.textilehubgatewayurl={{ .Env.TXL_HUB_GATEWAY_URL }}
      - -X main.textileuserkey={{ .Env.TXL_USER_KEY }}
      - -X main.textileusersecret={{ .Env.TXL_USER_SECRET }}
      - -X main.spacestoragesiteurl={{ .Env.SPACE_STORAGE_SITE_URL }}
      - -X main.ipfsaddr={{ .Env.IPFS_ADDR }}
      - -X main.ipfsnodeaddr={{ .Env.IPFS_NODE_ADDR }}
      - -X main.ipfsnodepath={{ .Env.IPFS_NODE_PATH }}
    main: ./cmd/space-daemon/main.go
    binary: space
    goos:
      - darwin
    # hooks:
    #   post: gon -log-level debug ci/gon.hcl

  - id: space-win
    # env:
    #   - CGO_ENABLED=1
    ldflags:
      - -s -w -X main.spaceapi={{ .Env.SERVICES_API_URL }}
      - -X main.vaultapi={{ .Env.VAULT_API_URL }}
      - -X main.vaultsaltsecret={{ .Env.VAULT_SALT_SECRET }}
      - -X main.spacehubauth={{ .Env.SERVICES_HUB_AUTH_URL }}
      - -X main.textilehub={{ .Env.TXL_HUB_TARGET }}
      - -X main.textilehubma={{ .Env.TXL_HUB_MA }}
      - -X main.textilethreads={{ .Env.TXL_THREADS_TARGET }}
      - -X main.textilehubgatewayurl={{ .Env.TXL_HUB_GATEWAY_URL }}
      - -X main.textileuserkey={{ .Env.TXL_USER_KEY }}
      - -X main.textileusersecret={{ .Env.TXL_USER_SECRET }}
      - -X main.spacestoragesiteurl={{ .Env.SPACE_STORAGE_SITE_URL }}
      - -X main.ipfsaddr={{ .Env.IPFS_ADDR }}
      - -X main.ipfsnodeaddr={{ .Env.IPFS_NODE_ADDR }}
      - -X main.ipfsnodepath={{ .Env.IPFS_NODE_PATH }}
    main: ./cmd/space-daemon/main.go
    binary: space
    goos:
      - windows
    # ignore:
    #   - goos: windows
    #     goarch: 386
archives:
- name_template: '{{ .Binary }}_{{ .Os }}_{{ .Arch }}'
  format: binary
  files:
    - LICENSE*
    - README*
    - CHANGELOG*
    - dist/space-macos-i386.dmg
    - dist/space-macos-x86_64.dmg
  replacements:
    darwin: Darwin
    linux: Linux
    windows: Windows
    386: i386
    amd64: x86_64
checksum:
  name_template: 'checksums.txt'
snapshot:
  name_template: "{{ .Tag }}-next"
changelog:
  sort: asc
  filters:
    exclude:
    - '^docs:'
    - '^test:'


================================================
FILE: .vscode/launch.json
================================================
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch",
      "type": "go",
      "request": "launch",
      "mode": "auto",
      "program": "${workspaceFolder}/cmd/space-daemon",
      "envFile": "${workspaceFolder}/.env",
      "args": ["-dev=true"]
    }
  ]
}

================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   Copyright 2020 FleekHQ

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

================================================
FILE: Makefile
================================================
build:
	go build \
	-o bin/space \
	-ldflags \
	"-X 'main.ipfsaddr=${IPFS_ADDR}' \
	-X 'main.ipfsnodeaddr=${IPFS_NODE_ADDR}' \
	-X 'main.ipfsnodepath=${IPFS_NODE_PATH}' \
	-X 'main.spaceapi=${SERVICES_API_URL}' \
	-X 'main.spacestoragesiteurl=${SPACE_STORAGE_SITE_URL}' \
	-X 'main.vaultapi=${VAULT_API_URL}' \
	-X 'main.vaultsaltsecret=${VAULT_SALT_SECRET}' \
	-X 'main.spacehubauth=${SERVICES_HUB_AUTH_URL}' \
	-X 'main.textilehub=${TXL_HUB_TARGET}' \
	-X 'main.textilehubma=${TXL_HUB_MA}' \
	-X 'main.textilethreads=${TXL_THREADS_TARGET}' \
	-X 'main.textilehubgatewayurl=${TXL_HUB_GATEWAY_URL}' \
    -X 'main.textileuserkey=${TXL_USER_KEY}' \
	-X 'main.textileusersecret=${TXL_USER_SECRET}'" \
	cmd/space-daemon/main.go

test:
	go test $$(go list ./... | grep -v integration_tests)

test_coverage:
	go test -coverprofile=coverage/unitcoverage.out $$(go list ./... | grep -v integration_tests)

integration_test:
	go test -v -p 1 ./integration_tests/...

integration_test_coverage:
	go test -v -p 1 -coverprofile=coverage/integrationcoverage.out ./integration_tests/...

proto_gen:
	protoc -I grpc/pb/ -I grpc/proto/ -I./devtools/googleapis grpc/proto/space.proto --go_out=plugins=grpc:grpc/pb

gen_rest:
	protoc -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


gen_all: proto_gen gen_rest

## runs jaeger tracing server, should be used when trace is enabled on daemon
jaegar:
	docker run \
		--rm \
		--name jaeger \
		-p 6831:6831/udp \
		-p 16686:16686 \
		jaegertracing/all-in-one:latest


================================================
FILE: README.md
================================================
# Space Daemon

Space 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:

- A running local instance of [Textile Threads](https://github.com/textileio/go-threads).

- Interfaces to create local private, encrypted buckets.

- Interfaces for sharing those buckets and the files within.

- Identity service so that sharing can be done through usernames or emails.

- FUSE for drive mounting, so that the files can be explored natively in your OS.

- Key management.

Note: This project is in active development, so it might change its API until it reaches a stable version.

## Installation

By 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).

### Downloading the binary

Check 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.

If you want to run Space Daemon by source, check out [this section](https://github.com/FleekHQ/space-daemon#Running)

## Usage

Space 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:

- Create files and directories

- List files and directories

- Creating buckets

- Sharing buckets

- Creating identities

You can also use the JavaScript client here [https://github.com/FleekHQ/space-client](https://github.com/FleekHQ/space-client)

This can be useful if, for example, you are building a web app that needs to interact with a user's locally running Space Daemon.

## Modules

Space 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.

### IPFS Node

All 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. 

If 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`).

In 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`.

### Textile Hub

Required 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.

If you want to host your own Textile Hub node, you can [read its documentation here](https://github.com/textileio/textile)

### Space Services

We provide hosted alternatives for these services. You can deploy your own by following the instructions in its repo:

[https://github.com/fleekHQ/space-services](https://github.com/fleekHQ/space-services)

#### Identity

These 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.

#### Authentication

Our 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.

## Running from source

After 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:

```
IPFS_ADDR=[Your IPFS node address]
SERVICES_API_URL=[The URL where Space Services API is located]
VAULT_API_URL=[The URL where Space Vault API is located]
VAULT_SALT_SECRET=[A random string used for kdf functions before storing keys to the vault]
SERVICES_HUB_AUTH_URL=[The URL where Space Services Textile Hub Authorizer is located]
TXL_HUB_TARGET=[The URL of the Textile Hub]
TXL_HUB_MA=[The multiaddress for the Textile hub]
TXL_THREADS_TARGET=[The URL of the Textile Hub where Threads are hosted, can be the same that TXL_HUB_TARGET]

# NOTE: the following are required temporarily and will be removed once hub auth wrapper is setup
TXL_USER_KEY=[Space level key for hub access]
TXL_USER_SECRET=[Space level secret for hub access]
```

Alternatively, 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`.

## Contributting

We 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.

Read the following sections for an introduction into the code.

### Package Structure

Loosely based on these resources:
https://github.com/golang-standards/project-layout


- `/grpc` Folder structure for gRPC and REST API.
- `/cmd` Entry point directory for all binaries this repo handles. E.g cmd/{binary-name}/main.go
- `/config` Global Config code
- `/core` Directory for the core objects of the package
- `/logger` Directory for app logging
- `/examples` Directory playground for general examples and drafts

### Main classes

- `ipfs`: contains utils for general IPFS operations.
- `keychain`: manages user public/private key pair.
- `libfuse`: interoperates with FUSE for mounting drives.
- `space`: contains the main integration from the services to the final Textile or FS operations.
- `store`: contains a wrapper around a local db.
- `sync`: keeps track of open files so that the updates get pushed to IPFS
- `textile`: wrapper around Textile booting and operations

### Generating Mocks

Mocks are generated using https://github.com/vektra/mockery.

For Linux it needs to be built from source.

`mockery --name InterfaceToMock --dir path/to/go/files`

### Protobuf

If you update the gRPC API, you need to regenerate the Protobuf file.

You will need to install the following binaries in your Go path:

- `go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway`

Checking the binaries:
`ls $GOPATH/bin`
Should show the following binaries in your path: protoc-gen-go, protoc-gen-grpc-gateway

Run the protobuf generation:
`make proto_gen`

Run the REST proxy generation:
`make gen_rest`

** Ideally you should run `make gen_all` before commiting as this would run all the above three code generations and
ensure everything is up to date **

NOTE: See here for instructions on Reverse Proxy:
https://github.com/grpc-ecosystem/grpc-gateway

### Debugging, Profiling and Tracing

The following flags can be run with the binary to output profiling files for debugging.
Flags support a full path to a file.
`-cpuprofile cpu.prof -memprofile mem.prof`

By default, the binary runs in debug mode (this may change after release) and it boots a pprof
server in localhost:6060. See docs how to interact with pprof server here: https://github.com/google/pprof/blob/master/doc/README.md

To disable debug mode add this flag to binary arguments
`-debug=false`

To enable trace in the daemon, pass `-trace` to the binary arguments. The daemon uses [jaegar](https://www.jaegertracing.io/) 
for collecting trace information. Run `make jaegar` to quickly start a jaeger agent that collects the daemons trace information.
You can `http://localhost:16686/` to explore the web ui for traces collected.

### CI Secrets

Secrets 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.

If 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.

Stage 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 }}`.

So to add a new secret:
* 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.
* 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

================================================
FILE: app/app.go
================================================
package app

import (
	"context"
	"fmt"

	"github.com/FleekHQ/space-daemon/core/space/fuse/installer"

	"github.com/FleekHQ/space-daemon/core/search/bleve"
	"github.com/pkg/errors"

	"github.com/FleekHQ/space-daemon/core"
	"github.com/FleekHQ/space-daemon/grpc"

	"github.com/FleekHQ/space-daemon/core/space/fuse"
	"github.com/FleekHQ/space-daemon/core/vault"

	"github.com/FleekHQ/space-daemon/core/fsds"

	"github.com/FleekHQ/space-daemon/core/spacefs"
	textile "github.com/FleekHQ/space-daemon/core/textile"
	"github.com/FleekHQ/space-daemon/core/textile/hub"

	"github.com/FleekHQ/space-daemon/core/env"
	"github.com/FleekHQ/space-daemon/core/space"

	node "github.com/FleekHQ/space-daemon/core/ipfs/node"
	"github.com/FleekHQ/space-daemon/core/keychain"
	"github.com/FleekHQ/space-daemon/core/sync"
	"github.com/FleekHQ/space-daemon/log"

	"golang.org/x/sync/errgroup"

	"github.com/FleekHQ/space-daemon/config"
	"github.com/FleekHQ/space-daemon/core/store"
	w "github.com/FleekHQ/space-daemon/core/watcher"
	"github.com/golang-collections/collections/stack"
)

// Shutdown logic follows this example https://gist.github.com/akhenakh/38dbfea70dc36964e23acc19777f3869
type App struct {
	eg         *errgroup.Group
	components *stack.Stack
	cfg        config.Config
	env        env.SpaceEnv
	IsRunning  bool
}

type componentMap struct {
	name      string
	component core.Component
}

func New(cfg config.Config, env env.SpaceEnv) *App {
	return &App{
		components: stack.New(),
		cfg:        cfg,
		env:        env,
		IsRunning:  false,
	}
}

// Start is the Entry point for the app.
// All module components are initialized and managed here.
// When a top level module that need to be shutdown on exit is initialized. It should be
// added to the apps list of tracked components using the `Run()` function, but if the component has a blocking
// start/run function it should be tracked with the `RunAsync()` function and call the blocking function in the
// input function block.
func (a *App) Start() error {
	var ctx context.Context
	a.eg, ctx = errgroup.WithContext(context.Background())

	log.SetLogLevel(a.cfg.GetString(config.LogLevel, "debug"))

	// init appStore
	appStore := store.New(
		store.WithPath(a.cfg.GetString(config.SpaceStorePath, "")),
	)
	if err := appStore.Open(); err != nil {
		return err
	}
	a.Run("Store", appStore)

	// Init keychain
	kc := keychain.New(keychain.WithPath(a.cfg.GetString(config.SpaceStorePath, "")), keychain.WithStore(appStore))

	// Init Vault
	v := vault.New(a.cfg.GetString(config.SpaceVaultAPIURL, ""), a.cfg.GetString(config.SpaceVaultSaltSecret, ""))

	watcher, err := w.New()
	if err != nil {
		return err
	}
	a.Run("FolderWatcher", watcher)

	// setup local ipfs node if Ipfsnode is set
	if a.cfg.GetBool(config.Ipfsnode, true) {
		// setup local ipfs node
		node := node.NewIpsNode(a.cfg)
		err = a.RunAsync("IpfsNode", node, func() error {
			return node.Start(ctx)
		})
		if err != nil {
			log.Error("error starting embedded IPFS node", err)
			return err
		}
	} else {
		log.Info("Skipping embedded IPFS node")
	}

	// setup local buckets
	buckd := textile.NewBuckd(a.cfg)
	err = a.RunAsync("BucketDaemon", buckd, func() error {
		return buckd.Start(ctx)
	})
	if err != nil {
		return err
	}

	hubAuth := hub.New(appStore, kc, a.cfg)

	// setup files search engine
	searchEngine := bleve.NewSearchEngine(bleve.WithDBPath(a.cfg.GetString(config.SpaceStorePath, "")))
	a.Run("FilesSearchEngine", searchEngine)

	// setup textile client
	uc := textile.CreateUserClient(a.cfg.GetString(config.TextileHubTarget, ""))
	textileClient := textile.NewClient(appStore, kc, hubAuth, uc, nil, searchEngine)
	err = a.RunAsync("TextileClient", textileClient, func() error {
		return textileClient.Start(ctx, a.cfg)
	})
	if err != nil {
		return err
	}

	// watcher is started inside bucket sync
	bucketSync := sync.New(watcher, textileClient, appStore, nil)

	// setup the Space Service
	sv, svErr := space.NewService(
		appStore,
		textileClient,
		bucketSync,
		a.cfg,
		kc,
		v,
		hubAuth,
		space.WithEnv(a.env),
	)
	if svErr != nil {
		return svErr
	}

	// setup FUSE FS Handler
	sfs := spacefs.New(fsds.NewSpaceFSDataSource(
		sv,
		fsds.WithFilesDataSources(sv),
		fsds.WithSharedWithMeDataSources(sv),
	))
	fuseInstaller := installer.NewFuseInstaller()
	fuseController := fuse.NewController(ctx, a.cfg, appStore, sfs, fuseInstaller)
	if fuseController.ShouldMount() {
		log.Info("Mounting FUSE Drive")
		if err := fuseController.Mount(); err != nil {
			log.Error("Mounting FUSE drive failed", err)
		} else {
			log.Info("Mounting FUSE Drive successful")
		}
	}
	a.Run("FuseController", fuseController)

	// setup gRPC Server
	srv := grpc.New(
		sv,
		fuseController,
		kc,
		grpc.WithPort(a.cfg.GetInt(config.SpaceServerPort, 0)),
		grpc.WithProxyPort(a.cfg.GetInt(config.SpaceProxyServerPort, 0)),
		grpc.WithRestProxyPort(a.cfg.GetInt(config.SpaceRestProxyServerPort, 0)),
	)

	textileClient.AttachMailboxNotifier(srv)
	textileClient.AttachSynchronizerNotifier(srv)

	// start the gRPC server
	err = a.RunAsync("gRPCServer", srv, func() error {
		return srv.Start(ctx)
	})
	if err != nil {
		return err
	}

	err = a.RunAsync("BucketSync", bucketSync, func() error {
		bucketSync.RegisterNotifier(srv)
		return bucketSync.Start(ctx)
	})
	if err != nil {
		return err
	}

	log.Info("Daemon ready")
	a.IsRunning = true

	return nil
}

// Run registers this component to be cleaned up on Shutdown
func (a *App) Run(name string, component core.Component) {
	log.Debug("Starting Component", "name:"+name)
	a.components.Push(&componentMap{
		name:      name,
		component: component,
	})
}

// RunAsync performs the same function as Run() but also accepts an function to be run
// async to initialize the component.
func (a *App) RunAsync(name string, component core.AsyncComponent, fn func() error) error {
	log.Debug("Starting Async Component", "name:"+name)
	if a.eg == nil {
		log.Warn("App.RunAsync() should be called after App.Start()")
		return nil
	}

	errc := make(chan error)

	a.eg.Go(func() error {
		err := fn()
		if err != nil {
			errc <- err
		}

		return err
	})

	select {
	case err := <-errc:
		return err
	case <-component.WaitForReady():
		a.components.Push(&componentMap{
			name:      name,
			component: component,
		})
	}

	return nil
}

// Shutdown would perform a graceful shutdown of all components added through the
// Run() or RunAsync() functions
func (a *App) Shutdown() error {
	log.Info("Daemon shutdown started")
	if !a.IsRunning {
		return errors.New("app is not running")
	}

	for a.components.Len() > 0 {
		m, ok := a.components.Pop().(*componentMap)
		if ok {
			log.Debug("Shutting down Component", fmt.Sprintf("name:%s", m.name))
			if err := m.component.Shutdown(); err != nil {
				log.Error(fmt.Sprintf("error shutting down %s", m.name), err)
			}
		}
	}

	err := a.eg.Wait()
	log.Info("Shutdown complete")
	a.IsRunning = false
	return err
}


================================================
FILE: ci/add-osx-cert.sh
================================================
#!/usr/bin/env sh

KEY_CHAIN=build.keychain
CERTIFICATE_P12=certificate.p12

# Recreate the certificate from the secure environment variable
echo $CERTIFICATE_OSX_APPLICATION | base64 --decode > $CERTIFICATE_P12

#create a keychain
security create-keychain -p actions $KEY_CHAIN

# Make the keychain the default so identities are found
security default-keychain -s $KEY_CHAIN

# Unlock the keychain
security unlock-keychain -p actions $KEY_CHAIN

security import $CERTIFICATE_P12 -k $KEY_CHAIN -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign;

security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN

# remove certs
rm -fr *.p12

================================================
FILE: ci/gon.hcl
================================================
# The path follows a pattern
# ./dist/BUILD-ID_TARGET/BINARY-NAME
source = ["./dist/space-darwin_darwin_amd64/space","./dist/space-darwin_darwin_386/space"]
bundle_id = "co.fleek.space"

apple_id {
  username = "daniel@fleek.co"
  password = "@env:APPLE_DEVELOPER_DANIEL_PASSWORD"
}

sign {
  application_identity = "Mac Developer: Daniel Merrill (8257VLCFL7)"
}

================================================
FILE: cmd/space-daemon/main.go
================================================
package main

import (
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"syscall"

	"github.com/FleekHQ/space-daemon/tracing"

	"github.com/opentracing/opentracing-go"

	"github.com/FleekHQ/space-daemon/log"

	"github.com/FleekHQ/space-daemon/app"
	"github.com/FleekHQ/space-daemon/config"
	"github.com/FleekHQ/space-daemon/core/env"
	"github.com/FleekHQ/space-daemon/core/util/rlimit"
)

var (
	cpuprofile           = flag.String("cpuprofile", "", "write cpu profile to `file`")
	memprofile           = flag.String("memprofile", "", "write memory profile to `file`")
	debugMode            = flag.Bool("debug", true, "run daemon with debug mode for profiling")
	enableTracing        = flag.Bool("trace", false, "run tracing on daemon rpc")
	devMode              = flag.Bool("dev", false, "run daemon in dev mode to use .env file")
	ipfsnode             = flag.Bool("ipfsnode", true, "run IPFS embedded into the daemon (defaults to true)")
	ipfsaddr             string
	ipfsnodeaddr         string
	ipfsnodepath         string
	spaceapi             string
	spacestoragesiteurl  string
	vaultapi             string
	vaultsaltsecret      string
	spacehubauth         string
	textilehub           string
	textilehubma         string
	textilethreads       string
	textilehubgatewayurl string
	textileuserkey       string
	textileusersecret    string
)

func main() {
	// this defer code here ensures all profile defer call work properly
	returnCode := 0
	defer func() { os.Exit(returnCode) }()

	// flags
	flag.Parse()

	log.Debug("Running mode", fmt.Sprintf("DevMode:%v", *devMode))

	cf := &config.Flags{
		Ipfsaddr:             ipfsaddr,
		Ipfsnode:             *ipfsnode == true,
		Ipfsnodeaddr:         ipfsnodeaddr,
		Ipfsnodepath:         ipfsnodepath,
		ServicesAPIURL:       spaceapi,
		SpaceStorageSiteUrl:  spacestoragesiteurl,
		VaultAPIURL:          vaultapi,
		VaultSaltSecret:      vaultsaltsecret,
		ServicesHubAuthURL:   spacehubauth,
		DevMode:              *devMode == true,
		TextileHubTarget:     textilehub,
		TextileHubMa:         textilehubma,
		TextileThreadsTarget: textilethreads,
		TextileHubGatewayUrl: textilehubgatewayurl,
		TextileUserKey:       textileuserkey,
		TextileUserSecret:    textileusersecret,
	}

	// CPU profiling
	if *debugMode == true {
		log.Debug("Running daemon with profiler. Visit http://localhost:6060/debug/pprof")
		go func() {
			fmt.Println(http.ListenAndServe("localhost:6060", nil))
		}()
	}

	// initialize tracing
	if *enableTracing {
		log.Debug("Enabling Tracing on the Daemon")
		tracer, closer := tracing.MustInit("space-daemon")
		defer closer.Close()
		opentracing.SetGlobalTracer(tracer)
	}

	if *cpuprofile != "" {
		cleanupCpuProfile := runCpuProfiler(*cpuprofile)
		defer cleanupCpuProfile()
	}

	// env
	env := env.New()

	// load configs
	cfg := config.NewMap(cf)

	rlimit.SetRLimit()

	spaceApp := app.New(cfg, env)

	err := spaceApp.Start()
	if err != nil {
		log.Error("Application startup failed", err)
		returnCode = 1
	}

	// setup to detect interruption
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
	defer signal.Stop(interrupt)

	<-interrupt // wait for interrupt and then shutdown app
	err = spaceApp.Shutdown()

	if *memprofile != "" {
		cleanupMemProfile := runMemProfiler(*memprofile)
		defer cleanupMemProfile()
	}

	if err != nil {
		log.Error("Application shutdown failed", err)
		returnCode = 1
	}
}

func runCpuProfiler(outputFilePath string) func() {
	f, err := os.Create(outputFilePath)
	if err != nil {
		log.Error("Could not create CPU profile", err)
		return func() {}
	}

	if err := pprof.StartCPUProfile(f); err != nil {
		log.Error("Could not start CPU profile", err)
	}

	// return cleanup function
	return func() {
		pprof.StopCPUProfile()
		if f != nil {
			_ = f.Close() // error is ignored
		}
	}
}

func runMemProfiler(outputFilePath string) func() {
	f, err := os.Create(outputFilePath)
	if err != nil {
		log.Error("could not create memory profile", err)
		return func() {}
	}

	runtime.GC() // get up-to-date statistics
	if err := pprof.WriteHeapProfile(f); err != nil {
		log.Error("could not write memory profile", err)
	}

	// return cleanup function
	return func() {
		if f != nil {
			_ = f.Close()
		}
	}
}


================================================
FILE: config/config.go
================================================
package config

import (
	"errors"
)

const (
	JsonConfigFileName       = "space.json"
	SpaceServerPort          = "space/rpcPort"
	SpaceProxyServerPort     = "space/rpcProxyPort"
	SpaceRestProxyServerPort = "space/restProxyPort"
	SpaceStorageSiteUrl      = "space/storageSiteUrl"
	SpaceStorePath           = "space/storePath"
	TextileHubTarget         = "space/textileHubTarget"
	TextileHubMa             = "space/textileHubMa"
	TextileThreadsTarget     = "space/textileThreadsTarget"
	TextileHubGatewayUrl     = "space/TextileHubGatewayUrl"
	TextileUserKey           = "space/textileUserKey"
	TextileUserSecret        = "space/textileUserSecret"
	MountFuseDrive           = "space/mountFuseDrive"
	FuseMountPath            = "space/fuseMountPath"
	FuseDriveName            = "space/fuseDriveName"
	SpaceServicesAPIURL      = "space/servicesApiUrl"
	SpaceVaultAPIURL         = "space/vaultApiUrl"
	SpaceVaultSaltSecret     = "space/vaultSaltSecret"
	SpaceServicesHubAuthURL  = "space/servicesHubAuthUrl"
	Ipfsaddr                 = "space/ipfsAddr"
	Ipfsnode                 = "space/ipfsNode"
	Ipfsnodeaddr             = "space/ipfsNodeAddr"
	Ipfsnodepath             = "space/ipfsNodePath"
	MinThreadsConnection     = "space/minThreadsConn"
	MaxThreadsConnection     = "space/maxThreadsConn"
	BuckdPath                = "space/BuckdPath"
	BuckdApiMaAddr           = "space/BuckdApiMaAddr"
	BuckdApiProxyMaAddr      = "space/BuckdApiProxyMaAddr"
	BuckdThreadsHostMaAddr   = "Space/BuckdThreadsHostMaAddr"
	BuckdGatewayPort         = "Space/BuckdGatewayPort"
	LogLevel                 = "Space/LogLevel"
)

var (
	ErrConfigNotLoaded = errors.New("config file was not loaded correctly or it does not exist")
)

type Flags struct {
	Ipfsaddr               string
	Ipfsnode               bool
	Ipfsnodeaddr           string
	Ipfsnodepath           string
	DevMode                bool
	ServicesAPIURL         string
	SpaceStorageSiteUrl    string
	VaultAPIURL            string
	VaultSaltSecret        string
	ServicesHubAuthURL     string
	TextileHubTarget       string
	TextileHubMa           string
	TextileThreadsTarget   string
	TextileHubGatewayUrl   string
	TextileUserKey         string
	TextileUserSecret      string
	SpaceStorePath         string
	RpcServerPort          int
	RpcProxyServerPort     int
	RestProxyServerPort    int
	BuckdPath              string
	BuckdApiMaAddr         string
	BuckdApiProxyMaAddr    string
	BuckdThreadsHostMaAddr string
	BuckdGatewayPort       int
	LogLevel               string
}

// Config used to fetch config information
type Config interface {
	GetString(key string, defaultValue interface{}) string
	GetInt(key string, defaultValue interface{}) int
	GetBool(key string, defaultValue interface{}) bool
}


================================================
FILE: config/json_config.go
================================================
package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/FleekHQ/space-daemon/core/env"
	"github.com/FleekHQ/space-daemon/log"
	"github.com/creamdog/gonfig"
)

// standardConfig implements Config
// It loads its config information from the space.json file
type jsonConfig struct {
	cfg gonfig.Gonfig
}

type defaultSpaceJson struct {
	TextileHubTarget     string `json:"textileHubTarget"`
	TextileThreadsTarget string `json:"textileThreadsTarget"`
	RPCPort              int    `json:"rpcPort"`
	StorePath            string `json:"storePath"`
}

type defaultJson struct {
	Space defaultSpaceJson `json:"space"`
}

// Deprecated for the default values config
func NewJson(env env.SpaceEnv) Config {
	wd := env.WorkingFolder()
	f, err := os.Open(wd + "/" + JsonConfigFileName)
	if err != nil {
		// TODO: this may turn into a fatal panic error
		log.Info("could not find space.json file in " + wd + ", using defaults")
	}

	defer f.Close()
	config, err := gonfig.FromJson(f)
	if err != nil {
		log.Info("could not read space.json file, using defaults")
	}

	c := jsonConfig{
		cfg: config,
	}

	return c
}

// Gets the configuration value given a path in the json config file
// defaults to empty value if non is found and just logs errors
func (c jsonConfig) GetString(key string, defaultValue interface{}) string {
	if c.cfg == nil {
		return ""
	}
	v, err := c.cfg.GetString(key, defaultValue)
	if err != nil {
		log.Error(fmt.Sprintf("error getting key %s from config", key), err)
		return ""
	}
	log.Debug("Getting conf " + key + ": " + v)

	return v
}

// Gets the configuration value given a path in the json config file
// defaults to empty value if non is found and just logs errors
func (c jsonConfig) GetInt(key string, defaultValue interface{}) int {
	if c.cfg == nil {
		return 0
	}
	v, err := c.cfg.GetInt(key, defaultValue)
	if err != nil {
		log.Error(fmt.Sprintf("error getting key %s from config", key), err)
		return 0
	}

	return v
}

// Gets the configuration value given a path in the json config file
// defaults to empty value if non is found and just logs errors
func (c jsonConfig) GetBool(key string, defaultValue interface{}) bool {
	if c.cfg == nil {
		return false
	}
	v, err := c.cfg.GetBool(key, defaultValue)
	if err != nil {
		log.Error(fmt.Sprintf("error getting key %s from config", key), err)
		return false
	}

	return v
}

func CreateConfigJson() error {
	fmt.Println("Generating default config file")
	spaceJson := defaultSpaceJson{
		TextileHubTarget:     "textile-hub-dev.fleek.co:3006",
		TextileThreadsTarget: "textile-hub-dev.fleek.co:3006",
		RPCPort:              9999,
		StorePath:            "~/.fleek-space",
	}

	finalJson := defaultJson{
		Space: spaceJson,
	}

	currExecutablePath, err := os.Executable()
	if err != nil {
		return err
	}

	pathSegments := strings.Split(currExecutablePath, "/")
	wd := strings.Join(pathSegments[:len(pathSegments)-1], "/")

	jsonPath := wd + "/" + JsonConfigFileName
	marshalled, err := json.MarshalIndent(finalJson, "", "  ")
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(jsonPath, marshalled, 0644)
	if err != nil {
		return err
	}

	fmt.Println("Default config file generated")

	return nil
}


================================================
FILE: config/map_config.go
================================================
package config

import (
	"os"
	"os/user"
	"path/filepath"

	"github.com/FleekHQ/space-daemon/core/env"
)

type mapConfig struct {
	configStr  map[string]string
	configInt  map[string]int
	configBool map[string]bool
}

func NewMap(flags *Flags) Config {
	configStr := make(map[string]string)
	configInt := make(map[string]int)
	configBool := make(map[string]bool)

	usr, _ := user.Current()

	// default values
	configStr[LogLevel] = flags.LogLevel
	configStr[SpaceStorePath] = filepath.Join(usr.HomeDir, ".fleek-space")
	configStr[MountFuseDrive] = "false"
	configStr[FuseDriveName] = "Space"
	configInt[SpaceServerPort] = 9999
	configInt[SpaceProxyServerPort] = 9998
	configInt[SpaceRestProxyServerPort] = 9997
	if flags.DevMode {
		configStr[Ipfsaddr] = os.Getenv(env.IpfsAddr)
		configStr[Ipfsnodeaddr] = os.Getenv(env.IpfsNodeAddr)
		configStr[Ipfsnodepath] = os.Getenv(env.IpfsNodePath)
		configStr[SpaceServicesAPIURL] = os.Getenv(env.ServicesAPIURL)
		configStr[SpaceVaultAPIURL] = os.Getenv(env.VaultAPIURL)
		configStr[SpaceVaultSaltSecret] = os.Getenv(env.VaultSaltSecret)
		configStr[SpaceServicesHubAuthURL] = os.Getenv(env.ServicesHubAuthURL)
		configStr[SpaceStorageSiteUrl] = os.Getenv(env.SpaceStorageSiteUrl)
		configStr[TextileHubTarget] = os.Getenv(env.TextileHubTarget)
		configStr[TextileHubMa] = os.Getenv(env.TextileHubMa)
		configStr[TextileThreadsTarget] = os.Getenv(env.TextileThreadsTarget)
		configStr[TextileHubGatewayUrl] = os.Getenv(env.TextileHubGatewayUrl)
		configStr[TextileUserKey] = os.Getenv(env.TextileUserKey)
		configStr[TextileUserSecret] = os.Getenv(env.TextileUserSecret)

		if os.Getenv(env.IpfsNode) != "false" {
			configBool[Ipfsnode] = true
		}
	} else {
		configStr[Ipfsaddr] = flags.Ipfsaddr
		configStr[Ipfsnodeaddr] = flags.Ipfsnodeaddr
		configStr[Ipfsnodepath] = flags.Ipfsnodepath
		configStr[SpaceServicesAPIURL] = flags.ServicesAPIURL
		configStr[SpaceVaultAPIURL] = flags.VaultAPIURL
		configStr[SpaceVaultSaltSecret] = flags.VaultSaltSecret
		configStr[SpaceServicesHubAuthURL] = flags.ServicesHubAuthURL
		if flags.SpaceStorageSiteUrl != "" {
			configStr[SpaceStorageSiteUrl] = flags.SpaceStorageSiteUrl
		}
		configStr[TextileHubTarget] = flags.TextileHubTarget
		configStr[TextileHubMa] = flags.TextileHubMa
		configStr[TextileThreadsTarget] = flags.TextileThreadsTarget
		configStr[TextileHubGatewayUrl] = flags.TextileHubGatewayUrl
		configStr[TextileUserKey] = flags.TextileUserKey
		configStr[TextileUserSecret] = flags.TextileUserSecret
		configBool[Ipfsnode] = flags.Ipfsnode
		if flags.SpaceStorePath != "" {
			configStr[SpaceStorePath] = flags.SpaceStorePath
		}
		if flags.RpcServerPort != 0 {
			configInt[SpaceServerPort] = flags.RpcServerPort
		}
		if flags.RpcProxyServerPort != 0 {
			configInt[SpaceProxyServerPort] = flags.RpcProxyServerPort
		}
		if flags.RestProxyServerPort != 0 {
			configInt[SpaceRestProxyServerPort] = flags.RestProxyServerPort
		}
		if flags.BuckdPath != "" {
			configStr[BuckdPath] = flags.BuckdPath
		}
		if flags.BuckdApiMaAddr != "" {
			configStr[BuckdApiMaAddr] = flags.BuckdApiMaAddr
		}
		if flags.BuckdApiProxyMaAddr != "" {
			configStr[BuckdApiProxyMaAddr] = flags.BuckdApiProxyMaAddr
		}
		if flags.BuckdThreadsHostMaAddr != "" {
			configStr[BuckdThreadsHostMaAddr] = flags.BuckdThreadsHostMaAddr
		}
		if flags.BuckdGatewayPort != 0 {
			configInt[BuckdGatewayPort] = flags.BuckdGatewayPort
		}
	}

	// Temp fix until we move to viper
	if configStr[Ipfsaddr] == "" {
		configStr[Ipfsaddr] = "/ip4/127.0.0.1/tcp/5001"
	}

	c := mapConfig{
		configStr:  configStr,
		configInt:  configInt,
		configBool: configBool,
	}

	return c
}

func (m mapConfig) GetString(key string, defaultValue interface{}) string {
	if val, exists := m.configStr[key]; exists {
		return val
	}

	if stringValue, ok := defaultValue.(string); ok {
		return stringValue
	}

	return ""
}

func (m mapConfig) GetInt(key string, defaultValue interface{}) int {
	if val, exists := m.configInt[key]; exists {
		return val
	}

	if intVal, ok := defaultValue.(int); ok {
		return intVal
	}

	return 0
}

func (m mapConfig) GetBool(key string, defaultValue interface{}) bool {
	if val, exists := m.configBool[key]; exists {
		return val
	}

	if boolVal, ok := defaultValue.(bool); ok {
		return boolVal
	}

	return false
}


================================================
FILE: core/backup/backup.go
================================================
package backup

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
)

type Backup struct {
	PrivateKey string `json:"privateKey"`
}

// Note: Using static key since the goal of this is to obfuscate the file, not to encrypt it
var key = []byte{0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC}

func obfuscate(data []byte) ([]byte, error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonce := make([]byte, gcm.NonceSize())
	_, err = io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return nil, err
	}

	return gcm.Seal(nonce, nonce, data, nil), nil
}

func deobfuscate(ciphertext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	if len(ciphertext) < gcm.NonceSize() {
		return nil, errors.New("malformed ciphertext")
	}

	return gcm.Open(nil,
		ciphertext[:gcm.NonceSize()],
		ciphertext[gcm.NonceSize():],
		nil,
	)
}

// Creates a backup file in the given path
func MarshalBackup(path string, b *Backup) error {
	jsonData, err := json.Marshal(b)
	if err != nil {
		return err
	}

	obfuscatedBackup, err := obfuscate(jsonData)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(path, obfuscatedBackup, 0644)
	return err
}

// Reads a file in the given path and returns a Backup object
func UnmarshalBackup(path string) (*Backup, error) {
	obfuscatedBackup, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	jsonData, err := deobfuscate(obfuscatedBackup)
	if err != nil {
		return nil, err
	}

	var result Backup
	err = json.Unmarshal(jsonData, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}


================================================
FILE: core/component.go
================================================
package core

// Component represents core application components. Modules should implement this interface to allow for proper
// dependency checks and shutdown
type Component interface {
	Shutdown() error
}

// AsyncComponent represents components that have some async initialization
// and therefore must provide a ready channel to listen to
type AsyncComponent interface {
	Component
	WaitForReady() chan bool
}


================================================
FILE: core/env/env.go
================================================
package env

import (
	syslog "log"
	"os"
	"strings"
)

const (
	SpaceWorkingDir      = "SPACE_APP_DIR"
	LogLevel             = "LOG_LEVEL"
	IpfsAddr             = "IPFS_ADDR"
	IpfsNode             = "IPFS_NODE"
	IpfsNodeAddr         = "IPFS_NODE_ADDR"
	IpfsNodePath         = "IPFS_NODE_PATH"
	ServicesAPIURL       = "SERVICES_API_URL"
	VaultAPIURL          = "VAULT_API_URL"
	VaultSaltSecret      = "VAULT_SALT_SECRET"
	ServicesHubAuthURL   = "SERVICES_HUB_AUTH_URL"
	SpaceStorageSiteUrl  = "SPACE_STORAGE_SITE_URL"
	TextileHubTarget     = "TXL_HUB_TARGET"
	TextileHubMa         = "TXL_HUB_MA"
	TextileThreadsTarget = "TXL_THREADS_TARGET"
	TextileHubGatewayUrl = "TXL_HUB_GATEWAY_URL"
	TextileUserKey       = "TXL_USER_KEY"
	TextileUserSecret    = "TXL_USER_SECRET"
)

type SpaceEnv interface {
	CurrentFolder() (string, error)
	WorkingFolder() string
	LogLevel() string
}

type defaultEnv struct {
}

func (d defaultEnv) CurrentFolder() (string, error) {
	path, err := os.Executable()
	if err != nil {
		return "", err
	}

	pathSegments := strings.Split(path, "/")
	wd := strings.Join(pathSegments[:len(pathSegments)-1], "/")

	return wd, nil
}

func (d defaultEnv) WorkingFolder() string {
	cf, err := d.CurrentFolder()
	if err != nil {
		syslog.Fatal("unable to get working folder", err)
		panic(err)
	}
	return cf
}

func (d defaultEnv) LogLevel() string {
	return "Info"
}

// TODO: use this one after figuring textile keys
func NewDefault() SpaceEnv {
	return defaultEnv{}
}


================================================
FILE: core/env/file_env.go
================================================
package env

import (
	syslog "log"
	"os"
	"strings"

	"github.com/joho/godotenv"
)

type spaceEnv struct {
}

// Loads environment from .env file for dev mode
func New() SpaceEnv {
	err := godotenv.Load()
	if err != nil {
		syslog.Println("Error loading .env file. Using defaults")
	}

	return spaceEnv{}
}

func (s spaceEnv) CurrentFolder() (string, error) {
	path, err := os.Executable()
	if err != nil {
		return "", err
	}

	pathSegments := strings.Split(path, "/")
	wd := strings.Join(pathSegments[:len(pathSegments)-1], "/")

	return wd, nil
}

func (s spaceEnv) WorkingFolder() string {
	var wd = os.Getenv(SpaceWorkingDir)
	// use default
	if wd == "" {
		cf, err := s.CurrentFolder()
		if err != nil {
			syslog.Fatal("unable to get working folder", err)
			panic(err)
		}
		wd = cf
	}

	return wd
}

func (s spaceEnv) LogLevel() string {
	var ll = os.Getenv(LogLevel)

	if ll == "" {
		return "Info"
	}

	return ll
}


================================================
FILE: core/events/events.go
================================================
package events

import "github.com/FleekHQ/space-daemon/core/space/domain"

// These file defines events that daemon can propagate through all layers

type FileEventType string

const (
	FileAdded            FileEventType = "FileAdded"
	FileDeleted          FileEventType = "FileDeleted"
	FileUpdated          FileEventType = "FileUpdated"
	FileBackupInProgress FileEventType = "FileBackupInProgress"
	FileBackupReady      FileEventType = "FileBackupReady"

	FileRestored  FileEventType = "FileRestored"
	FileRestoring FileEventType = "FileRestoring"

	FolderAdded   FileEventType = "FolderAdded"
	FolderDeleted FileEventType = "FolderDeleted"
	// NOTE: not sure if this needs to be specific to rename or copy
	FolderUpdated FileEventType = "FolderUpdated"
)

type FileEvent struct {
	Info   domain.FileInfo
	Type   FileEventType
	Bucket string
	DbID   string
}

func NewFileEvent(info domain.FileInfo, eventType FileEventType, bucket, dbID string) FileEvent {
	return FileEvent{
		Info:   info,
		Type:   eventType,
		Bucket: bucket,
		DbID:   dbID,
	}
}

type TextileEvent struct {
	BucketName string
}

func NewTextileEvent(bucketname string) TextileEvent {
	return TextileEvent{
		BucketName: bucketname,
	}
}

type InvitationStatus int

const (
	Pending InvitationStatus = 0
	Accepted
	Rejected
)

type NotificationType int

const (
	InvitationType NotificationType = 0
)

type Invitation struct {
	InviterPublicKey string
	InvitationID     string
	Status           InvitationStatus
	ItemPaths        []string
}

type NotificationEvent struct {
	Subject       string
	Body          string
	RelatedObject interface{}
	Type          NotificationType
	CreatedAt     int64
	ReadAt        int64
}


================================================
FILE: core/fsds/config.go
================================================
package fsds

import (
	"fmt"
	"os"

	"github.com/FleekHQ/space-daemon/core/space"
)

var DefaultBucketName = "personal"

type dataSourceConfig struct {
	tlfSources []*TLFDataSource
}

type FSDataSourceConfig func(config *dataSourceConfig)

func WithTLFDataSource(source *TLFDataSource) FSDataSourceConfig {
	return func(config *dataSourceConfig) {
		config.tlfSources = append(config.tlfSources, source)
	}
}

// Configure the default 'Files` data source to be included as a data source
func WithFilesDataSources(service space.Service) FSDataSourceConfig {
	basePath := fmt.Sprintf("%cFiles", os.PathSeparator)
	return WithTLFDataSource(&TLFDataSource{
		name:         "Files",
		basePath:     basePath,
		FSDataSource: &filesDataSource{service: service},
	})
}

// Configure the default 'Shared With Me` data source to be included as a data source
func WithSharedWithMeDataSources(service space.Service) FSDataSourceConfig {
	basePath := fmt.Sprintf("%cShared With Me", os.PathSeparator)
	return WithTLFDataSource(&TLFDataSource{
		name:     "Shared With Me",
		basePath: basePath,
		FSDataSource: &sharedWithMeDataSource{
			service:     service,
			maxDirLimit: 1000,
			cache:       make(map[string]*sharedFileEntry),
		},
	})
}

var blackListedDirEntryNames = map[string]bool{
	// OSX specific special directories
	".Trashes":              true,
	".localized":            true,
	".fseventsd":            true,
	".ql_disablethumbnails": true,
	".ql_disablecache":      true,
	// special space empty directory file
	".keep": true,
}


================================================
FILE: core/fsds/data_source.go
================================================
package fsds

import (
	"context"
	"os"
	"path/filepath"
	"strings"
)

// FileReadWriterCloser implements interfaces to read, copy, seek and close.
type FileReadWriterCloser interface {
	Read(ctx context.Context, data []byte, offset int64) (int, error)
	Write(ctx context.Context, data []byte, offset int64) (int, error)
	Close(ctx context.Context) error
	Stats(ctx context.Context) (*DirEntry, error)
	Truncate(ctx context.Context, size uint64) error
}

// FSDataSource is data source of file/directories and their information
// It is used as a local/remote cache for looking up information about the directories.
// It should also ensure that the user in the context has permission to data that is being request
type FSDataSource interface {
	// Get a single node, this can be called on either a file or folder entry
	// This is typically used by the OS for lookup of the information about the entry at path
	Get(ctx context.Context, path string) (*DirEntry, error)
	// GetChildren returns child entries in the directory/folder
	GetChildren(ctx context.Context, path string) ([]*DirEntry, error)
	// OpenReader returns a file reader
	Open(ctx context.Context, path string) (FileReadWriterCloser, error)
	// CreateEntry should create a directory or file based on the mode at the path
	CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error)
	// RenameEntry should rename the directory entry from old to new
	RenameEntry(ctx context.Context, oldPath, newPath string) error
	// DeleteEntry should delete the item at the path
	DeleteEntry(ctx context.Context, path string) error
}

// TLFDataSource represents a data source handler for a particular top level file.
type TLFDataSource struct {
	name     string
	basePath string
	FSDataSource
}

// Returns child path inside data source
func (t *TLFDataSource) ChildPath(path string) string {
	return strings.TrimPrefix(path, t.basePath)
}

// returns the path with the datasource base path prefixed
func (t *TLFDataSource) ParentPath(path string) string {
	return filepath.Join(t.basePath, path)
}


================================================
FILE: core/fsds/dir_entry.go
================================================
package fsds

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/FleekHQ/space-daemon/log"

	"github.com/FleekHQ/space-daemon/core/space/domain"
)

var StandardFileAccessMode os.FileMode = 0777   // -rw-------
var StandardDirAccessMode = os.ModeDir | 0777   //0700   // drwx------
var RestrictedDirAccessMode = os.ModeDir | 0500 // dr-x------ only allow reading and opening directory for user

// DirEntry implements the DirEntryOps
type DirEntry struct {
	entry domain.DirEntry
	mode  os.FileMode
	dbId  string
}

func NewDirEntry(entry domain.DirEntry) *DirEntry {
	return NewDirEntryWithMode(entry, 0)
}

func NewDirEntryFromFileInfo(info os.FileInfo, path string) *DirEntry {
	return &DirEntry{
		entry: domain.DirEntry{
			Path:          filepath.Dir(path),
			IsDir:         info.IsDir(),
			Name:          filepath.Base(path),
			SizeInBytes:   fmt.Sprintf("%d", info.Size()),
			Created:       info.ModTime().Format(time.RFC3339),
			Updated:       info.ModTime().Format(time.RFC3339),
			FileExtension: filepath.Ext(path),
		},
		mode: StandardFileAccessMode,
		dbId: "",
	}
}

func NewDirEntryWithMode(entry domain.DirEntry, mode os.FileMode) *DirEntry {
	return &DirEntry{
		entry: entry,
		mode:  mode,
	}
}

func (d *DirEntry) Path() string {
	if d.IsDir() {
		return fmt.Sprintf(
			"%s%c",
			strings.TrimRight(d.entry.Path, fmt.Sprintf("%c", os.PathSeparator)),
			os.PathSeparator,
		)
	}

	return d.entry.Path
}

// IsDir implement DirEntryAttribute
// And returns if the directory is a boolean or not
func (d *DirEntry) IsDir() bool {
	return d.entry.IsDir
}

// Name implements the DirEntryAttribute Interface
func (d *DirEntry) Name() string {
	return d.entry.Name
}

// Size implements the DirEntryAttribute Interface and return the size of the item
func (d *DirEntry) Size() uint64 {
	intSize, err := strconv.ParseUint(d.entry.SizeInBytes, 10, 64)
	if err != nil {
		log.Error("Error getting direntry size", err)
		// error, so returning 0 in the meantime
		return 0
	}
	return intSize
}

// Mode implements the DirEntryAttribute Interface
// Currently if it is a file, returns all access permission 0766
// but ideally should restrict the permission if owner is not the same as file
func (d *DirEntry) Mode() os.FileMode {
	if d.mode != 0 {
		return d.mode
	}

	if d.IsDir() {
		return StandardDirAccessMode
	}

	return StandardFileAccessMode
}

func (d *DirEntry) Uid() uint32 {
	// for now return id of currently logged in user
	return uint32(os.Getuid())
}

func (d *DirEntry) Gid() uint32 {
	return uint32(os.Getgid())
}

// Ctime implements the DirEntryAttribute Interface
// It returns the time the directory was created
func (d *DirEntry) Ctime() time.Time {
	t, err := time.Parse(time.RFC3339, d.entry.Created)

	if err != nil {
		log.Error("Error parsing direntry created time", err)
		return time.Time{}
	}

	return t
}

// ModTime returns the modification time
func (d *DirEntry) ModTime() time.Time {
	t, err := time.Parse(time.RFC3339, d.entry.Updated)

	if err != nil {
		log.Error("Error parsing direntry updated time", err)
		return time.Time{}
	}

	return t
}


================================================
FILE: core/fsds/files_ds.go
================================================
package fsds

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/FleekHQ/space-daemon/core/space/domain"

	"github.com/FleekHQ/space-daemon/core/space"
	"github.com/FleekHQ/space-daemon/log"
)

// Provides content for the 'Files' content managed by the space user
// Requests for items in this path are dispatched to this datasource from SpaceFSDataSource
type filesDataSource struct {
	service space.Service
}

// Maybe consider caching at the level of SpaceFSDataSource when results are returned from top level file
func (f *filesDataSource) Get(ctx context.Context, path string) (*DirEntry, error) {
	baseName := filepath.Base(path)
	if isBaseDirectory(path) || path == "" {
		return NewDirEntryWithMode(domain.DirEntry{
			Path:    path,
			IsDir:   true,
			Name:    baseName,
			Created: time.Now().Format(time.RFC3339),
			Updated: time.Now().Format(time.RFC3339),
		}, RestrictedDirAccessMode), nil
	}

	log.Debug("FileDS Get", fmt.Sprintf("path:%s", path))

	itemsInParent, err := f.service.ListDir(ctx, path, DefaultBucketName, true)
	if err != nil {
		if !isNotExistError(err) {
			return nil, EntryNotFound
		}

		return nil, err
	}

	// If space service.ListDir on path is empty, then it is a file
	// if it is not empty, then it is a directory
	if len(itemsInParent) != 0 {
		// is a directory because space directory cannot be empty (must at least contain a .keep file)
		return NewDirEntry(domain.DirEntry{
			Path:    path,
			IsDir:   true,
			Name:    baseName,
			Created: time.Now().Format(time.RFC3339),
			Updated: time.Now().Format(time.RFC3339),
		}), nil
	}

	// OpenFile to get Size information of file
	// TODO: Verify service.OpenFile() logic to ensure that multiple open file doesn't recreate multiple local copies for the same file without cleanup
	r, err := f.service.OpenFile(ctx, path, DefaultBucketName, "")
	if err != nil {
		//if isNotExistError(err) {
		return nil, EntryNotFound
		//}
	}

	fileStat, err := os.Stat(r.Location)
	if err != nil {
		return nil, err
	}

	//is a file, so return file entry
	return NewDirEntry(domain.DirEntry{
		Path:          path,
		IsDir:         false,
		Name:          baseName,
		SizeInBytes:   fmt.Sprintf("%d", fileStat.Size()),
		Created:       time.Now().Format(time.RFC3339),
		Updated:       time.Now().Format(time.RFC3339),
		FileExtension: filepath.Ext(path),
	}), nil
}

func (f *filesDataSource) GetChildren(ctx context.Context, path string) ([]*DirEntry, error) {
	log.Debug("FileDS GetChildren", fmt.Sprintf("path:%s", path))
	domainEntries, err := f.service.ListDir(ctx, path, DefaultBucketName, true)
	if err != nil {
		return nil, err
	}

	dirEntries := make([]*DirEntry, len(domainEntries))
	for i, domainEntries := range domainEntries {
		dirEntries[i] = NewDirEntry(domainEntries.DirEntry)
	}

	return dirEntries, nil
}

func (f *filesDataSource) Open(ctx context.Context, path string) (FileReadWriterCloser, error) {
	log.Debug("FileDS Open", fmt.Sprintf("path:%s", path))
	openFileInfo, err := f.service.OpenFile(ctx, path, DefaultBucketName, "")
	if err != nil {
		return nil, err
	}

	return OpenSpaceFilesHandler(f.service, openFileInfo.Location, path, DefaultBucketName), nil
}

// Create the entry at the specified path and return a DirEntry representing it.
// The DirEntry would be used to write/copy the items necessary at the point
func (f *filesDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error) {
	log.Debug("FileDS CreateEntry", fmt.Sprintf("path:%s", path), fmt.Sprintf("mode:%v", mode))
	entryName := filepath.Base(path)
	parentDir := filepath.Dir(path)

	if mode.IsDir() {
		err := f.service.CreateFolder(ctx, path, DefaultBucketName)
		if err != nil {
			return nil, err
		}

		return NewDirEntry(domain.DirEntry{
			Path:    path,
			IsDir:   true,
			Name:    entryName,
			Created: time.Now().Format(time.RFC3339),
			Updated: time.Now().Format(time.RFC3339),
		}), nil
	}

	// create an empty file to uploaded to the specified path
	newFilePath := filepath.Join(os.TempDir(), path)
	_ = os.MkdirAll(filepath.Dir(newFilePath), os.ModePerm)
	err := ioutil.WriteFile(newFilePath, []byte{}, mode)
	if err != nil {
		log.Error("Error creating empty file", err, "newFilePath:"+newFilePath)
		return nil, err
	}

	waitChan, _, err := f.service.AddItems(
		ctx,
		[]string{
			newFilePath,
		},
		parentDir,
		DefaultBucketName,
	)
	if err != nil {
		return nil, err
	}

	r := <-waitChan
	if r.Error != nil {
		log.Error("FileDS Failed to upload file", r.Error)
		return nil, err
	}

	return NewDirEntry(domain.DirEntry{
		Path:    path,
		IsDir:   false,
		Name:    entryName,
		Created: time.Now().Format(time.RFC3339),
		Updated: time.Now().Format(time.RFC3339),
	}), nil
}

// RenameEntry for now only supports renaming of empty folders
// Depending on user request and textile support, non-empty folders and file renames will be supported
func (f *filesDataSource) RenameEntry(ctx context.Context, oldPath, newPath string) error {
	log.Debug("FileDS RenameEntry", "oldPath:"+oldPath, "newPath:"+newPath)
	entry, err := f.Get(ctx, oldPath)
	if err != nil {
		return err
	}

	if !entry.IsDir() {
		log.Warn("FileDS trying to rename an entry that is not a directory")
		return syscall.ENOTSUP
	}

	childEntries, err := f.GetChildren(ctx, oldPath)
	if err != nil {
		log.Error("failed to get children of old path", err, "oldPath:"+oldPath)
		return err
	}

	if len(childEntries) != 0 && !areAllEntriesHidden(childEntries) {
		log.Warn("FileDS renaming directory that is not empty")
		// folder is not empty, so just error out
		return syscall.ENOTSUP
		// in the future, we should do a recursive copy to the newPath and then delete old path
	}

	if err = f.service.CreateFolder(ctx, newPath, DefaultBucketName); err != nil {
		log.Error("failed to new path create folder", err, "newPath:"+newPath)
		return syscall.ENOTSUP
	}

	return f.service.RemoveDirOrFile(ctx, oldPath, DefaultBucketName)
}

func areAllEntriesHidden(entries []*DirEntry) bool {
	for _, entry := range entries {
		baseName := filepath.Base(entry.Name())
		if !blackListedDirEntryNames[baseName] {
			return false
		}
	}
	return true
}

func (f *filesDataSource) DeleteEntry(ctx context.Context, path string) error {
	log.Debug("FileDS DeletEntry", "path:"+path)
	return f.service.RemoveDirOrFile(ctx, path, DefaultBucketName)
}


================================================
FILE: core/fsds/read_write_wrapper.go
================================================
package fsds

import (
	"context"
	"fmt"
	"io"
	"os"

	"github.com/FleekHQ/space-daemon/core/space/domain"

	"github.com/FleekHQ/space-daemon/log"
)

// Wrapper around space files read and write logic.
// On close, it pushes changes to space.Service
type SpaceFilesHandler struct {
	service       SyncService
	localFile     *os.File
	localFilePath string
	remotePath    string
	bucketName    string
	editted       bool
}

type SyncService interface {
	AddItemWithReader(ctx context.Context, reader io.Reader, targetPath, bucketName string) (domain.AddItemResult, error)
}

func OpenSpaceFilesHandler(
	service SyncService,
	localFilePath,
	remoteFilePath,
	bucketName string,
) *SpaceFilesHandler {
	return &SpaceFilesHandler{
		service:       service,
		localFilePath: localFilePath,
		localFile:     nil,
		remotePath:    remoteFilePath,
		bucketName:    bucketName,
		editted:       false,
	}
}

func (s *SpaceFilesHandler) Read(ctx context.Context, b []byte, offset int64) (int, error) {
	log.Debug(
		"Reading bytes from file handler",
		"path:"+s.remotePath,
		"bucket:"+s.bucketName,
		fmt.Sprintf("offset:%d", offset),
	)
	s.openLocalFile()

	_, err := s.localFile.Seek(offset, io.SeekStart)
	if err != nil {
		return 0, err
	}
	return s.localFile.Read(b)
}

func (s *SpaceFilesHandler) Write(ctx context.Context, b []byte, offset int64) (int, error) {
	log.Debug(
		"Writing bytes to file handler",
		"path:"+s.remotePath,
		"bucket:"+s.bucketName,
		fmt.Sprintf("offset:%d", offset),
	)
	s.openLocalFile()

	_, err := s.localFile.Seek(offset, io.SeekStart)
	if err != nil {
		return 0, err
	}

	n, err := s.localFile.Write(b)
	if err == nil {
		s.editted = true
	}
	return n, err
}

func (s *SpaceFilesHandler) Close(ctx context.Context) error {
	log.Debug("Closing access to SpaceFileHandler", "remotePath:"+s.remotePath, "localPath:"+s.localFilePath)
	defer func() {
		if s.localFile != nil {
			// background synchronizer should handle sync on close
			s.localFile.Close()
			s.localFile = nil
		}
	}()

	//if s.editted && s.localFile != nil {
	//	_, err := s.localFile.Seek(0, 0)
	//	if err != nil {
	//		log.Error("Error seeking local file to beginning for upload", err)
	//		return err
	//	}
	//
	//	_, err = s.service.AddItemWithReader(
	//		ctx,
	//		s.localFile,
	//		s.remotePath,
	//		s.bucketName,
	//	)
	//	if err != nil {
	//		return err
	//	}
	//}

	return nil
}

// Stats for now always reads stats from local file
func (s *SpaceFilesHandler) Stats(ctx context.Context) (*DirEntry, error) {
	s.openLocalFile()
	info, err := os.Stat(s.localFilePath)
	if err != nil {
		return nil, err
	}

	return NewDirEntryFromFileInfo(info, s.remotePath), nil
}

func (s *SpaceFilesHandler) Truncate(ctx context.Context, size uint64) error {
	s.openLocalFile()
	return s.localFile.Truncate(int64(size))
}

func (s *SpaceFilesHandler) openLocalFile() {
	if s.localFile != nil {
		return
	}

	s.localFile, _ = os.OpenFile(s.localFilePath, os.O_APPEND|os.O_RDWR, os.ModeAppend)
}


================================================
FILE: core/fsds/shared_with_me_ds.go
================================================
package fsds

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/FleekHQ/space-daemon/core/space/domain"

	"github.com/FleekHQ/space-daemon/core/space"
	"github.com/FleekHQ/space-daemon/log"
)

type sharedFileEntry struct {
	entry  *DirEntry
	dbId   string
	bucket string
}

// Provides content for the 'Shared With Me' content managed by the space user
// Requests for items in this path are dispatched to this datasource from SpaceFSDataSource
type sharedWithMeDataSource struct {
	service     space.Service
	maxDirLimit int
	cache       map[string]*sharedFileEntry
}

// Maybe consider caching at the level of SpaceFSDataSource when results are returned from top level file
func (f *sharedWithMeDataSource) Get(ctx context.Context, path string) (*DirEntry, error) {
	baseName := filepath.Base(path)

	if isBaseDirectory(path) || path == "" {
		// return parent directory info
		return NewDirEntryWithMode(domain.DirEntry{
			Path:    path,
			IsDir:   true,
			Name:    baseName,
			Created: time.Now().Format(time.RFC3339),
			Updated: time.Now().Format(time.RFC3339),
		}, RestrictedDirAccessMode), nil
	}
	log.Debug("SharedWithMeDS Get", fmt.Sprintf("path:%s", path))

	// check cache if Item is already there
	entry, exists := f.cache[path]
	if exists {
		return entry.entry, nil
	}

	itemsInParent, _, err := f.service.GetSharedWithMeFiles(ctx, "", f.maxDirLimit)
	if err != nil {
		if !isNotExistError(err) {
			return nil, EntryNotFound
		}
		return nil, err
	}

	f.cacheResults(itemsInParent)

	// find item matching path
	for _, entry := range itemsInParent {
		if entry.Path == path {
			return NewDirEntry(entry.DirEntry), nil
		}
	}

	return nil, EntryNotFound
}

// GetChildren should only be called on the parent folder and will always return
func (f *sharedWithMeDataSource) GetChildren(ctx context.Context, path string) ([]*DirEntry, error) {
	log.Debug("SharedWithMeDS GetChildren", fmt.Sprintf("path:%s", path))
	if !isBaseDirectory(path) && path != "" {
		// just return empty directory since shared with me currently only supports files
		return []*DirEntry{}, nil
	}

	entries, _, err := f.service.GetSharedWithMeFiles(ctx, "", f.maxDirLimit)
	if err != nil {
		return nil, err
	}

	// this ensure it always refreshes the cache whenever operating system calls list directory
	f.cacheResults(entries)

	dirEntries := make([]*DirEntry, len(entries))
	for i, entry := range entries {
		dirEntries[i] = NewDirEntry(entry.DirEntry)
	}

	return dirEntries, nil
}

func (f *sharedWithMeDataSource) Open(ctx context.Context, path string) (FileReadWriterCloser, error) {
	log.Debug("SharedWithMeDS Open", fmt.Sprintf("path:%s", path))
	entry, exists := f.cache[path]
	if !exists {
		return nil, EntryNotFound
	}

	openFileInfo, err := f.service.OpenFile(ctx, path, entry.bucket, entry.dbId)
	if err != nil {
		return nil, err
	}

	return OpenSpaceFilesHandler(f.service, openFileInfo.Location, path, entry.bucket), nil
}

// CreateEntry is not supported for shared with me files.
func (f *sharedWithMeDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error) {
	// not allowed so just return error
	return nil, syscall.ENOTSUP
}

func (f *sharedWithMeDataSource) RenameEntry(ctx context.Context, oldPath, newPath string) error {
	// Renaming items in the shared directory is not supported
	return syscall.ENOTSUP
}

func (f *sharedWithMeDataSource) DeleteEntry(ctx context.Context, path string) error {
	// Deleting items in the shared directory is not supported
	return syscall.ENOTSUP
}

func (f *sharedWithMeDataSource) cacheResults(items []*domain.SharedDirEntry) {
	for _, item := range items {
		f.cache[item.Path] = &sharedFileEntry{
			entry:  NewDirEntryWithMode(item.DirEntry, StandardFileAccessMode),
			dbId:   item.DbID,
			bucket: item.Bucket,
		}
	}
}


================================================
FILE: core/fsds/spacefs.go
================================================
package fsds

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/FleekHQ/space-daemon/core/space/domain"

	"github.com/FleekHQ/space-daemon/core/space"
)

// EntryNotFound error when a directory is not found
var EntryNotFound = syscall.ENOENT // errors.New("Directory entry not found")
var baseDir = NewDirEntryWithMode(
	domain.DirEntry{
		Path:  "/",
		IsDir: true,
		Name:  "",
	},
	RestrictedDirAccessMode,
)

// SpaceFSDataSource is an implementation of the FSDataSource
// It interacts with the Space Service Layer to provide data
type SpaceFSDataSource struct {
	service    space.Service
	tlfSources []*TLFDataSource
	// temp cache to speed up node fetching interactions
	// TODO: handle cache invalidation
	entryCache map[string]*DirEntry
}

func NewSpaceFSDataSource(service space.Service, configOptions ...FSDataSourceConfig) *SpaceFSDataSource {
	config := dataSourceConfig{}
	for _, configure := range configOptions {
		configure(&config)
	}

	return &SpaceFSDataSource{
		service:    service,
		tlfSources: config.tlfSources,
		entryCache: make(map[string]*DirEntry),
	}
}

// Get returns the DirEntry information for item at path
func (d *SpaceFSDataSource) Get(ctx context.Context, path string) (*DirEntry, error) {
	//log.Debug("FSDS.Get", "path:"+path)
	baseName := filepath.Base(path)
	if blackListedDirEntryNames[baseName] {
		return nil, EntryNotFound
	}

	// handle quick lookup of home directory
	if isBaseDirectory(path) {
		return baseDir, nil
	}

	// cache get results
	if entry, exists := d.entryCache[path]; exists {
		return entry, nil
	}

	dataSource := d.findTLFDataSource(path)
	if dataSource == nil {
		return nil, EntryNotFound
	}

	result, err := dataSource.Get(ctx, dataSource.ChildPath(path))
	if err != nil {
		return nil, err
	}

	result.entry.Path = dataSource.ParentPath(result.entry.Path)
	d.entryCache[path] = result

	return result, nil
}

func (d *SpaceFSDataSource) findTLFDataSource(path string) *TLFDataSource {
	for _, i := range d.tlfSources {
		if strings.HasPrefix(path, i.basePath) {
			return i
		}
	}

	return nil
}

// GetChildren returns list of entries in a path
func (d *SpaceFSDataSource) GetChildren(ctx context.Context, path string) ([]*DirEntry, error) {
	//log.Debug("FSDS.GetChildren", "path:"+path)
	baseName := filepath.Base(path)
	if blackListedDirEntryNames[baseName] {
		return nil, EntryNotFound
	}
	if isBaseDirectory(path) {
		return d.getTopLevelDirectories(), nil
	}

	dataSource := d.findTLFDataSource(path)
	if dataSource == nil {
		return nil, EntryNotFound
	}

	result, err := dataSource.GetChildren(ctx, dataSource.ChildPath(path))

	// format results
	if result != nil {
		for _, entry := range result {
			entry.entry.Path = dataSource.ParentPath(entry.entry.Path)
			d.entryCache[entry.entry.Path] = entry
		}
	}

	return result, err
}

// Open is invoked to read the content of a file
func (d *SpaceFSDataSource) Open(ctx context.Context, path string) (FileReadWriterCloser, error) {
	//log.Debug("FSDS.Open", "path:"+path)
	dataSource := d.findTLFDataSource(path)
	if dataSource == nil {
		return nil, EntryNotFound
	}

	return dataSource.Open(ctx, dataSource.ChildPath(path))
}

// CreateEntry creates a directory or file based on the mode at the path
func (d *SpaceFSDataSource) CreateEntry(ctx context.Context, path string, mode os.FileMode) (*DirEntry, error) {
	//log.Debug("FSDS.CreateEntry", "path:"+path)
	dataSource := d.findTLFDataSource(path)
	if dataSource == nil {
		return nil, syscall.ENOTSUP
	}

	result, err := dataSource.CreateEntry(ctx, dataSource.ChildPath(path), mode)
	if result != nil {
		result.entry.Path = dataSource.ParentPath(result.entry.Path)
	}

	return result, err
}

func (d *SpaceFSDataSource) RenameEntry(ctx context.Context, oldPath, newPath string) error {
	//log.Debug("FSDS.RenameEntry", "oldPath:"+oldPath, "newPath:"+newPath)
	oldPathDataSource := d.findTLFDataSource(oldPath)
	newPathDataSource := d.findTLFDataSource(newPath)

	if oldPathDataSource.name != newPathDataSource.name {
		// renaming can only happen within the same datasource
		return syscall.ENOTSUP
	}

	return oldPathDataSource.RenameEntry(
		ctx,
		oldPathDataSource.ChildPath(oldPath),
		oldPathDataSource.ChildPath(newPath),
	)
}

func (d *SpaceFSDataSource) DeleteEntry(ctx context.Context, path string) error {
	//log.Debug("FSDS.DeleteEntry", "path:"+path)
	dataSource := d.findTLFDataSource(path)

	return dataSource.DeleteEntry(ctx, dataSource.ChildPath(path))
}

// Returns list of top level entry
func (d *SpaceFSDataSource) getTopLevelDirectories() []*DirEntry {
	var directories []*DirEntry

	for _, ds := range d.tlfSources {
		directories = append(directories, NewDirEntryWithMode(
			domain.DirEntry{
				Path:  ds.basePath,
				IsDir: true,
				Name:  ds.name,
				//Created:       "",
				//Updated:       "",
			},
			RestrictedDirAccessMode,
		))
	}
	return directories
}


================================================
FILE: core/fsds/utils.go
================================================
package fsds

import (
	"fmt"
	"os"
	"strings"
)

func isBaseDirectory(path string) bool {
	return path == "/"
}

func isDirPath(path string) bool {
	return strings.HasSuffix(path, fmt.Sprintf("%c", os.PathSeparator))
}

func isNotExistError(err error) bool {
	if err == nil {
		return false
	}
	// Example of current error representing file not found:
	// error: code = Unknown desc = no link named ".localized" under bafybeievqvkeo2ycggt4lino45pj3olv7yo2e6sybcmyphicejsvq2vimi[]
	if strings.Contains(err.Error(), "no link named") {
		return true
	}

	if strings.Contains(err.Error(), "could not resolve path") {
		return true
	}

	return false
}


================================================
FILE: core/ipfs/dag.go
================================================
package ipfs

import (
	"context"
	"errors"
	cid "github.com/ipfs/go-cid"
	ipld "github.com/ipfs/go-ipld-format"
	"sync"
)

var (
	ErrNotFound =  errors.New("not found")
)

type mapBasedDag struct {
	mu    sync.Mutex
	nodes map[string]ipld.Node
}

func NewDagService() *mapBasedDag {
	return &mapBasedDag{nodes: make(map[string]ipld.Node)}
}

func (d *mapBasedDag) Get(ctx context.Context, cid cid.Cid) (ipld.Node, error) {
	d.mu.Lock()
	defer d.mu.Unlock()
	if n, ok := d.nodes[cid.KeyString()]; ok {
		return n, nil
	}
	return nil, ErrNotFound
}

func (d *mapBasedDag) GetMany(ctx context.Context, cids []cid.Cid) <-chan *ipld.NodeOption {
	d.mu.Lock()
	defer d.mu.Unlock()
	out := make(chan *ipld.NodeOption, len(cids))
	for _, c := range cids {
		if n, ok := d.nodes[c.KeyString()]; ok {
			out <- &ipld.NodeOption{Node: n}
		} else {
			out <- &ipld.NodeOption{Err: ErrNotFound}
		}
	}
	close(out)
	return out
}

func (d *mapBasedDag) Add(ctx context.Context, node ipld.Node) error {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.nodes[node.Cid().KeyString()] = node
	return nil
}

func (d *mapBasedDag) AddMany(ctx context.Context, nodes []ipld.Node) error {
	d.mu.Lock()
	defer d.mu.Unlock()
	for _, n := range nodes {
		d.nodes[n.Cid().KeyString()] = n
	}
	return nil
}

func (d *mapBasedDag) Remove(ctx context.Context, c cid.Cid) error {
	d.mu.Lock()
	defer d.mu.Unlock()
	delete(d.nodes, c.KeyString())
	return nil
}

func (d *mapBasedDag) RemoveMany(ctx context.Context, cids []cid.Cid) error {
	d.mu.Lock()
	defer d.mu.Unlock()
	for _, c := range cids {
		delete(d.nodes, c.KeyString())
	}
	return nil
}

================================================
FILE: core/ipfs/ipfs.go
================================================
package ipfs

import (
	"context"
	"io"
	"sync"

	"github.com/ipfs/go-cid"

	"github.com/pkg/errors"

	"github.com/ipfs/interface-go-ipfs-core/path"

	"github.com/FleekHQ/space-daemon/log"
	ma "github.com/multiformats/go-multiaddr"

	"github.com/FleekHQ/space-daemon/config"
	files "github.com/ipfs/go-ipfs-files"
	httpapi "github.com/ipfs/go-ipfs-http-client"
)

type AddItemResult struct {
	Error    error
	Resolved path.Resolved
}

type LinkNodesInput struct {
	// name of link
	Name string
	Path path.Path
}

type LinkNodesResult struct {
	ParentPath path.Resolved
}

type Client interface {
	AddItems(ctx context.Context, items []io.Reader) []AddItemResult
	AddItem(ctx context.Context, item io.Reader) AddItemResult
	// Links each of the nodes in the input under the same parent
	LinkNodes(ctx context.Context, nodes []LinkNodesInput) (*LinkNodesResult, error)
	PullItem(ctx context.Context, cid cid.Cid) (io.ReadCloser, error)
}

type SpaceIpfsClient struct {
	client *httpapi.HttpApi
}

func NewSpaceIpfsClient(cfg config.Config) (*SpaceIpfsClient, error) {
	ipfsAddr := cfg.GetString(config.Ipfsaddr, "/ip4/127.0.0.1/tcp/5001")

	multiaddress, err := ma.NewMultiaddr(ipfsAddr)
	if err != nil {
		log.Error("Unable to parse IPFS Multiaddr", err)
		return nil, err
	}

	ic, err := httpapi.NewApi(multiaddress)
	if err != nil {
		return nil, err
	}
	return &SpaceIpfsClient{
		client: ic,
	}, nil
}

func (s *SpaceIpfsClient) AddItems(ctx context.Context, items []io.Reader) []AddItemResult {
	results := make([]AddItemResult, len(items))
	wg := sync.WaitGroup{}

	for i, item := range items {
		wg.Add(1)
		go func(i int, item io.Reader) {
			resolved, err := s.client.Unixfs().Add(
				ctx,
				files.NewReaderFile(item),
			)
			results[i] = AddItemResult{
				Error:    err,
				Resolved: resolved,
			}
			wg.Done()
		}(i, item)
	}

	wg.Wait()
	return results
}

func (s *SpaceIpfsClient) AddItem(ctx context.Context, item io.Reader) AddItemResult {
	result := s.AddItems(ctx, []io.Reader{item})
	return result[0]
}

func (s *SpaceIpfsClient) LinkNodes(ctx context.Context, nodes []LinkNodesInput) (*LinkNodesResult, error) {
	if len(nodes) == 0 {
		return nil, errors.New("no nodes passed to link nodes")
	}
	parentNode, err := s.client.Object().New(ctx)
	if err != nil {
		return nil, err
	}

	parentPath := path.IpfsPath(parentNode.Cid())
	for _, node := range nodes {
		parentPath, err = s.client.Object().AddLink(ctx, parentPath, node.Name, node.Path)
		if err != nil {
			return nil, errors.Wrap(err, "failed to link nodes")
		}
	}

	return &LinkNodesResult{
		ParentPath: parentPath,
	}, nil
}

func (s *SpaceIpfsClient) PullItem(ctx context.Context, cid cid.Cid) (io.ReadCloser, error) {
	node, err := s.client.Unixfs().Get(ctx, path.IpfsPath(cid))
	if err != nil {
		return nil, err
	}

	var file files.File
	switch f := node.(type) {
	case files.File:
		file = f
	case files.Directory:
		return nil, errors.New("unsupported cid provided")
	default:
		return nil, errors.New("unsupported cid provided")
	}

	return file, nil
}


================================================
FILE: core/ipfs/node/node.go
================================================
package ipfs

import (
	"context"

	"github.com/FleekHQ/space-daemon/config"
	"github.com/FleekHQ/space-daemon/log"

	"os/user"

	"fmt"
	"io/ioutil"
	"path/filepath"
	"sync"

	icore "github.com/ipfs/interface-go-ipfs-core"

	ma "github.com/multiformats/go-multiaddr"

	ipfsconfig "github.com/ipfs/go-ipfs-config"
	"github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/core/coreapi"
	"github.com/ipfs/go-ipfs/core/corehttp"
	"github.com/ipfs/go-ipfs/core/node/libp2p"
	"github.com/ipfs/go-ipfs/plugin/loader"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
	coreiface "github.com/ipfs/interface-go-ipfs-core"
	"github.com/libp2p/go-libp2p-core/peer"
)

type IpfsNode struct {
	coreApi  coreiface.CoreAPI
	coreNode *core.IpfsNode
	cancel   context.CancelFunc

	IsRunning bool
	Ready     chan bool
	cfg       config.Config
}

func NewIpsNode(cfg config.Config) *IpfsNode {
	return &IpfsNode{
		Ready: make(chan bool),
		cfg:   cfg,
	}
}

func (node *IpfsNode) Start(ctx context.Context) error {
	log.Info("Starting the ipfs node")

	err := node.start()
	if err != nil {
		return err
	}

	log.Info("Running the ipfs node")

	node.IsRunning = true
	node.Ready <- true

	return nil
}

func (node *IpfsNode) WaitForReady() chan bool {
	return node.Ready
}

func (node *IpfsNode) Stop() error {
	return node.stop()
}

func (node *IpfsNode) Shutdown() error {
	close(node.Ready)
	return node.Stop()
}

func (node *IpfsNode) start() error {
	ctx, cancel := context.WithCancel(context.Background())
	node.cancel = cancel

	pathRoot, err := ipfsconfig.PathRoot()
	if err != nil {
		return err
	}

	repoPath := node.cfg.GetString(config.Ipfsnodepath, pathRoot)
	if repoPath == "" {
		repoPath = pathRoot
	} else {
		usr, err := user.Current()
		if err != nil {
			repoPath = pathRoot
		} else {
			repoPath = filepath.Join(usr.HomeDir, repoPath)
		}
	}

	if err := setupPlugins(repoPath); err != nil {
		return err
	}

	// init the repo
	repoCfg, err := ipfsconfig.Init(ioutil.Discard, 2048)
	if err != nil {
		return err
	}

	err = fsrepo.Init(repoPath, repoCfg)
	if err != nil {
		return err
	}

	// open the repo
	repo, err := fsrepo.Open(repoPath)
	if err != nil {
		return err
	}

	// construct the node
	nodeOptions := &core.BuildCfg{
		Online:  true,
		Routing: libp2p.DHTClientOption,
		Repo:    repo,
	}

	node.coreNode, err = core.NewNode(ctx, nodeOptions)
	if err != nil {
		return err
	}

	node.coreApi, err = coreapi.NewCoreAPI(node.coreNode)
	if err != nil {
		return err
	}

	addr := node.cfg.GetString(config.Ipfsnodeaddr, "/ip4/127.0.0.1/tcp/5001")
	if addr == "" {
		addr = "/ip4/127.0.0.1/tcp/5001"
	}

	var opts = []corehttp.ServeOption{
		corehttp.GatewayOption(true, "/ipfs", "/ipns"),
		corehttp.WebUIOption,
		corehttp.CommandsOption(cmdCtx(node.coreNode, repoPath)),
	}

	go func() {
		if err := corehttp.ListenAndServe(node.coreNode, addr, opts...); err != nil {
			log.Error("Error starting api: ", err)
			return
		}
	}()

	// TODO: better place?
	bootstrapNodes := []string{
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
		"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
		"/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
	}

	go connectToPeers(ctx, node.coreApi, bootstrapNodes)

	return nil
}

func (node *IpfsNode) stop() error {
	node.IsRunning = false

	err := node.coreNode.Close()
	if err != nil {
		return err
	}

	node.cancel()

	return nil
}

func connectToPeers(ctx context.Context, ipfs icore.CoreAPI, peers []string) error {
	var wg sync.WaitGroup
	peerInfos := make(map[peer.ID]*peer.AddrInfo, len(peers))
	for _, addrStr := range peers {
		addr, err := ma.NewMultiaddr(addrStr)
		if err != nil {
			return err
		}
		pii, err := peer.AddrInfosFromP2pAddrs(addr)
		if err != nil {
			return err
		}

		pi, ok := peerInfos[pii[0].ID]
		if !ok {
			pi = &peer.AddrInfo{ID: pii[0].ID}
			peerInfos[pi.ID] = pi
		}
		pi.Addrs = append(pi.Addrs, pii[0].Addrs...)
	}

	wg.Add(len(peerInfos))
	for _, peerInfo := range peerInfos {
		go func(peerInfo *peer.AddrInfo) {
			defer wg.Done()
			err := ipfs.Swarm().Connect(ctx, *peerInfo)
			if err != nil {
				return
			}
		}(peerInfo)
	}
	wg.Wait()
	return nil
}

func setupPlugins(externalPluginsPath string) error {
	// load any external plugins if available on externalPluginsPath
	plugins, err := loader.NewPluginLoader(filepath.Join(externalPluginsPath, "plugins"))
	if err != nil {
		return fmt.Errorf("error loading plugins: %s", err)
	}

	// load preloaded and external plugins
	if err := plugins.Initialize(); err != nil {
		return fmt.Errorf("error initializing plugins: %s", err)
	}

	if err := plugins.Inject(); err != nil {
		return fmt.Errorf("error injecting plugins: %s", err)
	}

	return nil
}

func cmdCtx(node *core.IpfsNode, repoPath string) commands.Context {
	return commands.Context{
		ConfigRoot: repoPath,
		LoadConfig: func(path string) (*ipfsconfig.Config, error) {
			return node.Repo.Config()
		},
		ConstructNode: func() (*core.IpfsNode, error) {
			return node, nil
		},
		ReqLog: &commands.ReqLog{},
	}
}


================================================
FILE: core/ipfs/utils.go
================================================
package ipfs

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/ipfs/go-cid"
	chunker "github.com/ipfs/go-ipfs-chunker"
	ipld "github.com/ipfs/go-ipld-format"
	"github.com/ipfs/go-merkledag"
	"github.com/ipfs/go-unixfs/importer/balanced"
	"github.com/ipfs/go-unixfs/importer/helpers"
	"github.com/ipfs/go-unixfs/importer/trickle"
	mh "github.com/multiformats/go-multihash"
)

func GetFileHash(r io.Reader) (string, error) {
	hashFun := "sha2-256"

	prefix, err := merkledag.PrefixForCidVersion(1)
	if err != nil {
		return "", fmt.Errorf("bad CID Version: %s", err)
	}

	hashFunCode, ok := mh.Names[strings.ToLower(hashFun)]
	if !ok {
		return "", fmt.Errorf("unrecognized hash function: %s", hashFun)
	}
	prefix.MhType = hashFunCode
	prefix.MhLength = -1
	prefix.Codec = cid.DagProtobuf

	dagServ := NewDagService()
	dbp := helpers.DagBuilderParams{
		Dagserv:    dagServ,
		RawLeaves:  true,
		Maxlinks:   helpers.DefaultLinksPerBlock,
		NoCopy:     false,
		CidBuilder: &prefix,
	}

	chnk, err := chunker.FromString(r, "")
	if err != nil {
		return "", err
	}
	dbh, err := dbp.New(chnk)
	if err != nil {
		return "", err
	}

	layout := "trickle"
	var n ipld.Node
	switch layout {
	case "trickle":
		n, err = trickle.Layout(dbh)
	case "balanced", "":
		n, err = balanced.Layout(dbh)
	default:
		return "", errors.New("invalid Layout")
	}

	return n.Cid().String(), nil

}

func DownloadIpfsItemViaGateway(ctx context.Context, gatewayUrl string, cid cid.Cid) (io.ReadCloser, error) {
	url := fmt.Sprintf("%s/ipfs/%s", gatewayUrl, cid.String())
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}

	client := http.Client{}

	resp, err := client.Do(req.WithContext(ctx))
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("failed to fetch item %s: status_code %d", cid.String(), resp.StatusCode)
	}

	return resp.Body, nil
}

func DownloadIpfsItem(ctx context.Context, nodeUrl string, cid cid.Cid) (io.ReadCloser, error) {

	// https://docs.ipfs.io/reference/http/api/#api-v0-cat
	url := fmt.Sprintf("http://%s/api/v0/cat?arg=%s", nodeUrl, cid.String())

	req, err := http.NewRequest(http.MethodPost, url, nil)
	if err != nil {
		return nil, err
	}

	client := http.Client{}

	resp, err := client.Do(req.WithContext(ctx))
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("failed to fetch item %s: status_code %d", cid.String(), resp.StatusCode)
	}

	return resp.Body, nil
}


================================================
FILE: core/ipfs/utils_test.go
================================================
package ipfs

import (
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

// fleek hash: bafybeiemzcxynbrrhtcpmmdtkl42molkiyfqu3j5ewp2o7izdmomptfkgi

func TestIpfs_GetFileHash_FromStringReader(t *testing.T) {
	t.Skip()
	r := strings.NewReader("IPFS test data for reader")
	expectedHash := "bafybeie4zu4wu7lexqty2aubpe36dnpd6edgb5mthhtab5hyhuju7jlcgm"

	res, err := GetFileHash(r)

	assert.Nil(t, err)
	assert.NotNil(t, res)
	assert.Equal(t, expectedHash, res)
}

// bafybeic3jetthfk7tjmewz42idwsaeek5a7myw6n46zrrxdmp5nlkc6diy

func TestIpfs_GetFileHash_FromFile(t *testing.T) {
	t.Skip()
	r, _ := os.Open("test1.txt")
	expectedHash := "bafybeie4zu4wu7lexqty2aubpe36dnpd6edgb5mthhtab5hyhuju7jlcgm"

	res, err := GetFileHash(r)

	assert.Nil(t, err)
	assert.NotNil(t, res)
	assert.Equal(t, expectedHash, res)
}




================================================
FILE: core/keychain/app_token.go
================================================
package keychain

import (
	"errors"

	"github.com/99designs/keyring"
	"github.com/FleekHQ/space-daemon/core/permissions"
)

const AppTokenStoreKey = "appToken"
const MasterAppTokenStoreKey = "masterAppToken"

var ErrMasterTokenAlreadyExists = errors.New("master app token already exists")

func (kc *keychain) StoreAppToken(tok *permissions.AppToken) error {
	ring, err := kc.getKeyRing()
	if err != nil {
		return err
	}

	// Prevent overriding existing master key
	key, _ := kc.st.Get([]byte(getMasterTokenStKey()))
	if key != nil && tok.IsMaster {
		return ErrMasterTokenAlreadyExists
	}

	// Prevents overriding even if user logged out and logged back in (which clears the store)
	_, err = ring.Get(getMasterTokenStKey())
	if err == nil && tok.IsMaster {
		return ErrMasterTokenAlreadyExists
	}

	marshalled, err := permissions.MarshalToken(tok)
	if err != nil {
		return err
	}

	err = ring.Set(keyring.Item{
		Key:   AppTokenStoreKey + "_" + tok.Key,
		Data:  marshalled,
		Label: "Space App - App Token",
	})
	if err != nil {
		return err
	}

	if tok.IsMaster {
		if err := kc.st.Set([]byte(getMasterTokenStKey()), []byte(tok.Key)); err != nil {
			return err
		}

		if err := ring.Set(keyring.Item{
			Key:   getMasterTokenStKey(),
			Data:  marshalled,
			Label: "Space App - Master App Token",
		}); err != nil {
			return err
		}
	}

	return nil
}

func (kc *keychain) GetAppToken(key string) (*permissions.AppToken, error) {
	ring, err := kc.getKeyRing()
	if err != nil {
		return nil, err
	}

	token, err := ring.Get(AppTokenStoreKey + "_" + key)
	if err != nil {
		return nil, err
	}

	return permissions.UnmarshalToken(token.Data)
}

func getMasterTokenStKey() string {
	return AppTokenStoreKey + "_" + MasterAppTokenStoreKey
}


================================================
FILE: core/keychain/keychain.go
================================================
package keychain

import (
	"crypto/ed25519"
	"crypto/sha512"
	"encoding/hex"
	"os"
	"path"
	"strings"

	"golang.org/x/crypto/pbkdf2"

	"errors"

	"github.com/99designs/keyring"
	ri "github.com/FleekHQ/space-daemon/core/keychain/keyring"
	"github.com/FleekHQ/space-daemon/core/permissions"
	"github.com/FleekHQ/space-daemon/core/store"
	"github.com/FleekHQ/space-daemon/log"
	"github.com/libp2p/go-libp2p-core/crypto"
	"github.com/textileio/go-threads/core/thread"
	sym "github.com/textileio/go-threads/crypto/symmetric"
)

const PrivateKeyStoreKey = "key"
const PublicKeyStoreKey = "pub"

const privKeyMnemonicSeparator = "___"

var (
	ErrKeyPairNotFound = errors.New("No key pair found in the local db.")
)

type keychain struct {
	fileDir string
	st      store.Store
	ring    ri.Keyring
	privKey *crypto.PrivKey
}

type Keychain interface {
	GenerateKeyPair() (pub []byte, priv []byte, err error)
	GenerateKeyFromMnemonic(...GenerateKeyFromMnemonicOpts) (mnemonic string, err error)
	GetStoredKeyPairInLibP2PFormat() (crypto.PrivKey, crypto.PubKey, error)
	GetStoredPublicKey() (crypto.PubKey, error)
	GetStoredMnemonic() (string, error)
	GetManagedThreadKey(threadKeyName string) (thread.Key, error)
	GenerateKeyPairWithForce() (pub []byte, priv []byte, err error)
	Sign([]byte) ([]byte, error)
	ImportExistingKeyPair(priv crypto.PrivKey, mnemonic string) error
	DeleteKeypair() error
	StoreAppToken(tok *permissions.AppToken) error
	GetAppToken(key string) (*permissions.AppToken, error)
}

type keychainOptions struct {
	fileDir string
	store   store.Store

	// Don't use kc.ring directly, use getKeyRing() instead
	ring ri.Keyring
}

var defaultKeychainOptions = keychainOptions{
	fileDir: store.DefaultRootDir,
}

// Helper function for setting keychain file path for Windows/Linux
func WithPath(path string) Option {
	return func(o *keychainOptions) {
		if path != "" {
			o.fileDir = path
		}
	}
}

func WithStore(st store.Store) Option {
	return func(o *keychainOptions) {
		if st != nil {
			o.store = st
		}
	}
}

// Used to inject a mock keyring in tests or in case you want to use a custom keyring implementation
func WithKeyring(ring ri.Keyring) Option {
	return func(o *keychainOptions) {
		if ring != nil {
			o.ring = ring
		}
	}
}

type Option func(o *keychainOptions)

func New(opts ...Option) *keychain {
	o := defaultKeychainOptions
	for _, opt := range opts {
		opt(&o)
	}

	if o.store == nil {
		defaultStore := store.New(store.WithPath(o.fileDir))
		o.store = defaultStore
	}

	return &keychain{
		fileDir: o.fileDir,
		st:      o.store,
		ring:    o.ring,
	}
}

// Generates a public/private key pair using ed25519 algorithm.
// It stores it in the local db and returns the key pair key.
// If there's already a key pair stored, it returns an error.
// Use GenerateKeyPairWithForce if you want to override existing keys
func (kc *keychain) GenerateKeyPair() ([]byte, []byte, error) {
	if val, _ := kc.GetStoredPublicKey(); val != nil {
		newErr := errors.New("Error while executing GenerateKeyPair. Key pair already exists. Use GenerateKeyPairWithForce if you want to override it.")
		return nil, nil, newErr
	}

	return kc.generateAndStoreKeyPair(nil, "")
}

// Returns the stored key pair using the same signature than libp2p's GenerateEd25519Key function
func (kc *keychain) GetStoredKeyPairInLibP2PFormat() (crypto.PrivKey, crypto.PubKey, error) {
	var priv []byte
	var err error

	_, err = kc.GetStoredPublicKey()
	if err != nil {
		return nil, nil, err
	}

	if kc.privKey != nil {
		return *kc.privKey, (*kc.privKey).GetPublic(), nil
	}

	if priv, _, err = kc.retrieveKeyPair(); err != nil {
		newErr := ErrKeyPairNotFound
		return nil, nil, newErr
	}

	var unmarshalledPriv crypto.PrivKey

	if unmarshalledPriv, err = crypto.UnmarshalEd25519PrivateKey(priv); err != nil {
		return nil, nil, err
	}

	kc.privKey = &unmarshalledPriv

	unmarshalledPub := unmarshalledPriv.GetPublic()

	return unmarshalledPriv, unmarshalledPub, nil
}

// Generates a public/private key pair using ed25519 algorithm.
// It stores it in the local db and returns the key pair.
// Warning: If there's already a key pair stored, it overrides it.
func (kc *keychain) GenerateKeyPairWithForce() ([]byte, []byte, error) {
	return kc.generateAndStoreKeyPair(nil, "")
}

// Returns the public key currently in use in LibP2P format.
// Returns an error if there's no public key set.
// Unlike GetStoredKeyPairInLibP2PFormat, this method does not access the keychain
func (kc *keychain) GetStoredPublicKey() (crypto.PubKey, error) {
	ring, err := kc.getKeyRing()
	if err != nil {
		return nil, err
	}
	_, err = ring.GetMetadata(PrivateKeyStoreKey)
	if err == keyring.ErrKeyNotFound {
		return nil, ErrKeyPairNotFound
	}

	pubInBytes, err := kc.st.Get([]byte(PublicKeyStoreKey))
	if err != nil {
		return nil, err
	}

	if pubInBytes == nil {
		return nil, ErrKeyPairNotFound
	}

	pub, err := crypto.UnmarshalEd25519PublicKey(pubInBytes)
	if err != nil {
		return nil, err
	}

	return pub, nil
}

func (kc *keychain) GetStoredMnemonic() (string, error) {
	_, mnemonic, err := kc.retrieveKeyPair()
	if err != nil {
		return "", err
	}

	return mnemonic, nil
}

// Stores an existing private key in the keychain
// Warning: If there's already a key pair stored, this will override it.
func (kc *keychain) ImportExistingKeyPair(priv crypto.PrivKey, mnemonic string) error {
	privInBytes, err := priv.Raw()
	if err != nil {
		return err
	}
	pubInBytes, err := priv.GetPublic().Raw()
	if err != nil {
		return err
	}

	// Store the key pair in the db
	if err := kc.storeKeyPair(privInBytes, pubInBytes, mnemonic); err != nil {
		return err
	}

	kc.privKey = &priv

	return nil
}

func (kc *keychain) DeleteKeypair() error {
	ring, err := kc.getKeyRing()
	if err != nil {
		return err
	}

	// Note: currently ignoring error on keychain removal because it's failing randomly.
	// Use GenerateKeyPair with override option instead.
	err = ring.Remove(PrivateKeyStoreKey)

	err = kc.st.Remove([]byte(PublicKeyStoreKey))
	if err != nil {
		return err
	}

	kc.privKey = nil
	return nil
}

func (kc *keychain) generateKeyPair(seed []byte) ([]byte, []byte, error) {
	if seed != nil {
		priv := ed25519.NewKeyFromSeed(seed)
		publicKey := priv.Public()
		pub, ok := publicKey.(ed25519.PublicKey)
		if !ok {
			return nil, nil, errors.New("Error while generating key pair from seed")
		}
		return pub, priv, nil
	}
	// Compute the key from a random seed
	pub, priv, err := ed25519.GenerateKey(nil)
	return pub, priv, err
}

func (kc *keychain) generateAndStoreKeyPair(seed []byte, mnemonic string) ([]byte, []byte, error) {
	// Compute the key from a random seed
	pub, priv, err := kc.generateKeyPair(seed)

	if err != nil {
		return nil, nil, err
	}

	// Store the key pair in the db
	if err := kc.storeKeyPair(priv, pub, mnemonic); err != nil {
		return nil, nil, err
	}

	privkey, err := crypto.UnmarshalEd25519PrivateKey(priv)
	if err != nil {
		log.Warn("Unable to cache priv key")
	}

	kc.privKey = &privkey

	return pub, priv, nil
}

// Signs a message using the stored private key.
// Returns an error if the private key cannot be found.
func (kc *keychain) Sign(message []byte) ([]byte, error) {
	if priv, _, err := kc.retrieveKeyPair(); err != nil {
		return nil, err
	} else {
		signedBytes := ed25519.Sign(priv, message)
		return signedBytes, nil
	}
}

func (kc *keychain) getKeyRing() (ri.Keyring, error) {
	if kc.ring != nil {
		return kc.ring, nil
	}

	ucd, err := os.UserConfigDir()
	if err != nil {
		return nil, err
	}

	return keyring.Open(keyring.Config{
		ServiceName: "space",

		// MacOS keychain
		KeychainTrustApplication:       true,
		KeychainAccessibleWhenUnlocked: true,

		// KDE Wallet
		KWalletAppID:  "space",
		KWalletFolder: "space",

		// Windows
		WinCredPrefix: "space",

		// freedesktop.org's Secret Service
		LibSecretCollectionName: "space",

		// Pass (https://www.passwordstore.org/)
		PassPrefix: "space",
		PassDir:    kc.fileDir + "/kcpw",

		// Fallback encrypted file
		FileDir: path.Join(ucd, "space", "keyring"),
	})
}

func (kc *keychain) storeKeyPair(privKey []byte, pubKey []byte, mnemonic string) error {
	ring, err := kc.getKeyRing()
	if err != nil {
		return err
	}

	privAsHex := hex.EncodeToString(privKey)
	privWithMnemonic := privAsHex + privKeyMnemonicSeparator + mnemonic

	// Store private key together with mnemonic
	// Priv key is stored as 0x1234...890___some mnemonic
	// The idea behind storing them together is that we avoid asking for keychain access twice
	if err := ring.Set(keyring.Item{
		Key:   PrivateKeyStoreKey,
		Data:  []byte(privWithMnemonic),
		Label: "Space App",
	}); err != nil {
		return err
	}

	// Store pub key outside of the key ring for quick access
	if err := kc.st.Set([]byte(PublicKeyStoreKey), pubKey); err != nil {
		return err
	}

	return nil
}

func (kc *keychain) retrieveKeyPair() (privKey []byte, mnemonic string, err error) {
	ring, err := kc.getKeyRing()
	if err != nil {
		return nil, "", err
	}

	privKeyItem, err := ring.Get(PrivateKeyStoreKey)
	if err != nil {
		return nil, "", err
	}

	// Priv key is stored as 0x1234...890___some mnemonic
	// Here we split it to return priv key and mnemonic separately
	privKeyAsStr := string(privKeyItem.Data)
	privKeyParts := strings.Split(privKeyAsStr, privKeyMnemonicSeparator)
	mnemonic = privKeyParts[1]
	privKey, err = hex.DecodeString(privKeyParts[0])
	if err != nil {
		return nil, "", err
	}

	return privKey, mnemonic, nil
}

func (kc *keychain) GetManagedThreadKey(threadKeyName string) (thread.Key, error) {
	// Check if there's a key stored before continuing
	_, err := kc.GetStoredPublicKey()
	if err != nil {
		return thread.Key{}, err
	}

	size := 32

	priv, _, err := kc.GetStoredKeyPairInLibP2PFormat()
	if err != nil {
		return thread.Key{}, err
	}

	privBytes, err := priv.Raw()
	if err != nil {
		return thread.Key{}, err
	}

	num := pbkdf2.Key(privBytes, []byte("threadKey"+threadKeyName), 256, size, sha512.New)
	if err != nil {
		return thread.Key{}, err
	}

	truncated := num[:sym.KeyBytes*2]

	managedKey, err := thread.KeyFromBytes(truncated)
	if err != nil {
		return thread.Key{}, err
	}

	return managedKey, nil
}


================================================
FILE: core/keychain/keyring/keyring.go
================================================
package keyring

import "github.com/99designs/keyring"

type Keyring interface {
	Set(keyring.Item) error
	Get(string) (keyring.Item, error)
	Remove(string) error
	GetMetadata(string) (keyring.Metadata, error)
}


================================================
FILE: core/keychain/mnemonic.go
================================================
package keychain

import (
	"crypto/sha512"
	"errors"

	"github.com/tyler-smith/go-bip39"
	"golang.org/x/crypto/pbkdf2"
)

type generateKeyFromMnemonicOpts struct {
	override bool
	mnemonic string
	password string
}

var defaultMnemonicOpts = generateKeyFromMnemonicOpts{
	override: false,
	mnemonic: "",
	password: "",
}

type GenerateKeyFromMnemonicOpts func(o *generateKeyFromMnemonicOpts)

func WithMnemonic(mnemonic string) GenerateKeyFromMnemonicOpts {
	return func(o *generateKeyFromMnemonicOpts) {
		if mnemonic != "" {
			o.mnemonic = mnemonic
		}
	}
}

func WithPassword(password string) GenerateKeyFromMnemonicOpts {
	return func(o *generateKeyFromMnemonicOpts) {
		if password != "" {
			o.password = password
		}
	}
}

func WithOverride() GenerateKeyFromMnemonicOpts {
	return func(o *generateKeyFromMnemonicOpts) {
		o.override = true
	}
}

// Generates a public/private key pair using ed25519 algorithm.
// It stores it in the local db and returns the mnemonic.
// If Mnemonic is a blank string, it generates a random one.
// If there's already a key pair stored, it overrides it if override is set to true. Returns an error otherwise
func (kc *keychain) GenerateKeyFromMnemonic(opts ...GenerateKeyFromMnemonicOpts) (string, error) {
	o := defaultMnemonicOpts
	for _, opt := range opts {
		opt(&o)
	}
	if val, err := kc.GetStoredPublicKey(); val != nil && o.override == false && err != ErrKeyPairNotFound {
		newErr := errors.New("Error while executing GenerateKeyFromMnemonic. Key pair already exists.")
		return "", newErr
	}

	mnemonic := o.mnemonic

	if mnemonic == "" {
		entropy, err := bip39.NewEntropy(128)
		if err != nil {
			return "", err
		}

		mnemonic, err = bip39.NewMnemonic(entropy)
		if err != nil {
			return "", err
		}
	}

	seed, err := bip39.NewSeedWithErrorChecking(mnemonic, o.password)
	if err != nil {
		return "", err
	}

	// The seed returned by bip39 is fixed to size = 64 bytes.
	// However the seed in ed25519 needs to have size 32.
	// So to fix this we derive a key again based on the previous one, but with the correct size.
	compressedSeed := pbkdf2.Key(seed, []byte("iter2"+o.password), 512, 32, sha512.New)

	_, _, err = kc.generateAndStoreKeyPair(compressedSeed, mnemonic)
	if err != nil {
		return "", err
	}

	return mnemonic, nil
}


================================================
FILE: core/keychain/test/keychain_test.go
================================================
package keychain_test

import (
	"encoding/hex"
	"errors"
	"strings"
	"testing"

	"github.com/99designs/keyring"
	"github.com/FleekHQ/space-daemon/core/keychain"
	"github.com/FleekHQ/space-daemon/core/permissions"
	"github.com/FleekHQ/space-daemon/mocks"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/tyler-smith/go-bip39"
)

var (
	mockStore   *mocks.Store
	mockKeyRing *mocks.Keyring
)

func initTestKeychain(t *testing.T) keychain.Keychain {
	mockStore = new(mocks.Store)
	mockStore.On("IsOpen").Return(true)

	mockKeyRing = new(mocks.Keyring)

	kc := keychain.New(keychain.WithStore(mockStore), keychain.WithKeyring(mockKeyRing))

	return kc
}

func TestKeychain_GenerateAndRestore(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	pub, priv, _ := kc.GenerateKeyPairWithForce()

	privKeyItem := keyring.Item{
		Key:   keychain.PrivateKeyStoreKey,
		Data:  []byte(hex.EncodeToString(priv) + "___"),
		Label: "Space App",
	}

	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(pub, nil)
	mockKeyRing.On("Get", keychain.PrivateKeyStoreKey).Return(privKeyItem, nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, nil)

	libp2pPriv, _, _ := kc.GetStoredKeyPairInLibP2PFormat()

	// Reset mock store for assertions
	kc = initTestKeychain(t)
	mockStore.AssertNotCalled(t, "Set", []byte(keychain.PublicKeyStoreKey), pub)
	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)

	kc.ImportExistingKeyPair(libp2pPriv, "")

	mockStore.AssertCalled(t, "Set", []byte(keychain.PublicKeyStoreKey), pub)
	mockKeyRing.AssertCalled(t, "Set", privKeyItem)
}

func TestKeychain_GenerateMnemonicKey(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, nil)

	val, err := kc.GenerateKeyFromMnemonic()
	words := strings.Split(val, " ")

	assert.Nil(t, err)
	assert.NotNil(t, val)
	assert.Equal(t, 12, len(words))
	mockStore.AssertCalled(t, "Set", []byte(keychain.PublicKeyStoreKey), mock.Anything)
	mockKeyRing.AssertCalled(t, "Set", mock.Anything)
}

func TestKeychain_RestoreMnemonicKey(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, nil)

	mnemonic := "clog chalk blame black uncover frame before decide tuition maple crowd uncle"
	pubFromMnemonic, _ := hex.DecodeString("bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907")
	privAsHex := "6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907"

	val, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))
	assert.Nil(t, err)
	assert.NotNil(t, val)
	assert.Equal(t, mnemonic, val)
	mockStore.AssertCalled(t, "Set", []byte(keychain.PublicKeyStoreKey), pubFromMnemonic)
	mockKeyRing.AssertCalled(t, "Set", keyring.Item{
		Key:   keychain.PrivateKeyStoreKey,
		Data:  []byte(privAsHex + "___" + mnemonic),
		Label: "Space App",
	})
}

func TestKeychain_RestoreMnemonicKeyOnOverrideErr(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, nil)

	mnemonic := "clog chalk blame black uncover frame before decide tuition maple crowd uncle"
	pubFromMnemonic, _ := hex.DecodeString("a29d5030556f55f32d82b71618e97bfe976ebebc713592122b124881b4da6191")

	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(pubFromMnemonic, nil)

	_, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))
	assert.NotNil(t, err)
	assert.Equal(t, errors.New("Error while executing GenerateKeyFromMnemonic. Key pair already exists."), err)
}

func TestKeychain_RestoreMnemonicKeyExistsButNotInKeyring(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, keyring.ErrKeyNotFound)
	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)

	mnemonic := "clog chalk blame black uncover frame before decide tuition maple crowd uncle"
	pubFromMnemonic, _ := hex.DecodeString("bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907")
	privAsHex := "6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907"

	val, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))
	assert.Nil(t, err)
	assert.NotNil(t, val)
	assert.Equal(t, mnemonic, val)
	mockStore.AssertCalled(t, "Set", []byte(keychain.PublicKeyStoreKey), pubFromMnemonic)
	mockKeyRing.AssertCalled(t, "Set", keyring.Item{
		Key:   keychain.PrivateKeyStoreKey,
		Data:  []byte(privAsHex + "___" + mnemonic),
		Label: "Space App",
	})
}

func TestKeychain_RestoreMnemonicKeyMnemonicErr(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(nil, nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, nil)

	mnemonic := "clog chalk blame black uncover frame before decide tuition maple crowd"

	_, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic))
	assert.NotNil(t, err)
	assert.Equal(t, bip39.ErrInvalidMnemonic, err)
}

func TestKeychain_RestoreMnemonicKeyOnOverrideSuccess(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockKeyRing.On("GetMetadata", mock.Anything).Return(keyring.Metadata{}, nil)

	mnemonic := "clog chalk blame black uncover frame before decide tuition maple crowd uncle"
	pubFromMnemonic, _ := hex.DecodeString("bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907")
	privAsHex := "6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907"

	mockStore.On("Get", []byte(keychain.PublicKeyStoreKey)).Return(pubFromMnemonic, nil)

	val, err := kc.GenerateKeyFromMnemonic(keychain.WithMnemonic(mnemonic), keychain.WithOverride())
	assert.Nil(t, err)
	assert.NotNil(t, val)
	assert.Equal(t, mnemonic, val)
	mockStore.AssertCalled(t, "Set", []byte(keychain.PublicKeyStoreKey), pubFromMnemonic)
	mockKeyRing.AssertCalled(t, "Set", keyring.Item{
		Key:   keychain.PrivateKeyStoreKey,
		Data:  []byte(privAsHex + "___" + mnemonic),
		Label: "Space App",
	})
}

func TestKeychain_GetStoredMnemonic(t *testing.T) {
	kc := initTestKeychain(t)

	mnemonic := "clog chalk blame black uncover frame before decide tuition maple crowd uncle"
	privAsHex := "6f0938b7f2beb6f1715aaad71f578a94c51cc8ebd2cb221063e28c8a2efcabb6bbfa792cbf0453dde84947e5733c734b1bc11592190517d579ab589ae8107907"

	mockKeyRing.On("Get", keychain.PrivateKeyStoreKey).Return(keyring.Item{
		Key:   keychain.PrivateKeyStoreKey,
		Data:  []byte(privAsHex + "___" + mnemonic),
		Label: "Space App",
	}, nil)

	mnemonic2, err := kc.GetStoredMnemonic()

	assert.Nil(t, err)
	assert.Equal(t, mnemonic, mnemonic2)
}

func TestKeychain_AppToken_StoreMaster(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Get", []byte(keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey)).Return(nil, nil)
	mockKeyRing.On("Get", keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey).Return(keyring.Item{}, keyring.ErrKeyNotFound)
	mockKeyRing.On("Set", mock.Anything).Return(nil)
	mockStore.On("Set", mock.Anything, mock.Anything).Return(nil)

	tok, err := permissions.GenerateRandomToken(true, []string{})
	assert.NoError(t, err)

	err = kc.StoreAppToken(tok)
	assert.NoError(t, err)

	marshalled, err := permissions.MarshalToken(tok)
	assert.NoError(t, err)

	mockKeyRing.AssertCalled(t, "Set", keyring.Item{
		Key:   keychain.AppTokenStoreKey + "_" + tok.Key,
		Data:  marshalled,
		Label: "Space App - App Token",
	})

	mockKeyRing.AssertCalled(t, "Set", keyring.Item{
		Key:   keychain.AppTokenStoreKey + "_" + keychain.MasterAppTokenStoreKey,
		Data:  marshalled,
		Label: "Space App - Master App Token",
	})

	mockStore.AssertCalled(t, "Set", []byte(keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey), []byte(tok.Key))
}

func TestKeychain_AppToken_StoreNonMaster(t *testing.T) {
	kc := initTestKeychain(t)

	mockStore.On("Get", []byte(keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey)).Return(nil, nil)
	mockKeyRing.On("Get", keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey).Return(keyring.Item{}, keyring.ErrKeyNotFound)
	mockKeyRing.On("Set", mock.Anything).Once().Return(nil)

	tok, err := permissions.GenerateRandomToken(false, []string{})
	assert.NoError(t, err)

	err = kc.StoreAppToken(tok)
	assert.NoError(t, err)

	marshalled, err := permissions.MarshalToken(tok)
	assert.NoError(t, err)

	mockKeyRing.AssertCalled(t, "Set", keyring.Item{
		Key:   keychain.AppTokenStoreKey + "_" + tok.Key,
		Data:  marshalled,
		Label: "Space App - App Token",
	})

	mockKeyRing.AssertNotCalled(t, "Set", keyring.Item{
		Key:   keychain.AppTokenStoreKey + "_" + keychain.MasterAppTokenStoreKey,
		Data:  marshalled,
		Label: "Space App - Master App Token",
	})
}

func TestKeychain_AppToken_StoreMasterOverride1(t *testing.T) {
	kc := initTestKeychain(t)

	tok, err := permissions.GenerateRandomToken(true, []string{})
	assert.NoError(t, err)

	mockStore.On("Get", []byte(keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey)).Return([]byte(tok.Key), nil)

	err = kc.StoreAppToken(tok)
	assert.Error(t, err)
}

func TestKeychain_AppToken_StoreMasterOverride2(t *testing.T) {
	kc := initTestKeychain(t)

	tok, err := permissions.GenerateRandomToken(true, []string{})
	assert.NoError(t, err)

	mockStore.On("Get", []byte(keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey)).Return(nil, nil)
	mockKeyRing.On("Get", keychain.AppTokenStoreKey+"_"+keychain.MasterAppTokenStoreKey).Return(keyring.Item{}, nil)

	err = kc.StoreAppToken(tok)
	assert.Error(t, err)
}

func TestKeychain_AppToken_Get(t *testing.T) {
	kc := initTestKeychain(t)

	tok, err := permissions.GenerateRandomToken(false, []string{})
	assert.NoError(t, err)

	marshalled, err := permissions.MarshalToken(tok)
	assert.NoError(t, err)

	mockKeyRing.On("Get", keychain.AppTokenStoreKey+"_"+tok.Key).Return(keyring.Item{
		Key:   keychain.AppTokenStoreKey + "_" + tok.Key,
		Data:  marshalled,
		Label: "Space App - App Token",
	}, nil)

	tok2, err := kc.GetAppToken(tok.Key)
	assert.NoError(t, err)

	assert.Equal(t, tok, tok2)
}


================================================
FILE: core/libfuse/block_size.go
================================================
package libfuse

// fuseBlockSize is the block size used for calculating number of blocks. This
// is to make du/df work, and does not reflect in any way the internal block
// size (which is variable). 512 is chosen because FUSE seems to assume this
// block size all the time, despite BlockSize is provided in Statfs or Attr
// response or not. Bazil FUSE's documentation verifies this:
// https://github.com/bazil/fuse/blob/371fbbdaa8987b715bdd21d6adc4c9b20155f748/fuse.go#L1320
const fuseBlockSize = 512

func getNumBlocksFromSize(size uint64) uint64 {
	if size == 0 {
		return 0
	}
	return (size-1)/fuseBlockSize + 1
}


================================================
FILE: core/libfuse/directory.go
================================================
//+build !windows

package libfuse

import (
	"context"
	"errors"
	"fmt"
	"path"
	"strings"
	"syscall"

	"github.com/FleekHQ/space-daemon/core/spacefs"
	"github.com/FleekHQ/space-daemon/log"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

var (
	_ fs.Node         = (*VFSDir)(nil)
	_ fs.NodeAccesser = (*VFSDir)(nil)
	_                 = fs.NodeRequestLookuper(&VFSDir{})
	_                 = fs.HandleReadDirAller(&VFSDir{})
	_                 = fs.NodeCreater(&VFSDir{})
	_                 = fs.NodeMkdirer(&VFSDir{})
	_                 = fs.NodeRenamer(&VFSDir{})
	_                 = fs.NodeRemover(&VFSDir{})
)

// VFSDir represents a directory in the Virtual file system
type VFSDir struct {
	vfs    *VFS // pointer to the parent file system
	dirOps spacefs.DirOps
}

func NewVFSDir(vfs *VFS, dirOps spacefs.DirOps) *VFSDir {
	return &VFSDir{
		vfs:    vfs,
		dirOps: dirOps,
	}
}

// Attr returns fuse.Attr for the directory
func (dir *VFSDir) Attr(ctx context.Context, attr *fuse.Attr) error {
	dirAttribute, err := dir.dirOps.Attribute(ctx)
	if err != nil {
		return err
	}

	attr.Mode = dirAttribute.Mode()
	attr.Uid = dirAttribute.Uid()
	attr.Gid = dirAttribute.Gid()

	return nil
}

// ReadDirAll reads all the content of a directory
// In this mirror drive case, we just return items in the mirror path
func (dir *VFSDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	dirList, err := dir.dirOps.ReadDir(ctx)
	if err != nil {
		return nil, err
	}

	var res []fuse.Dirent
	for _, dirEntry := range dirList {
		entryAttribute, err := dirEntry.Attribute(ctx)
		if err != nil {
			return nil, err
		}

		entry := fuse.Dirent{
			Name: entryAttribute.Name(),
		}

		if entryAttribute.IsDir() {
			entry.Type = fuse.DT_Dir
		} else {
			entry.Type = fuse.DT_File
		}

		res = append(res, entry)
	}

	return res, nil
}

// Lookup finds entry Node within a directory
// Seems to be called when not enough information is gotten from the ReadDirAll
func (dir *VFSDir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	//log.Debug("VFSDir.Lookup", "name:"+req.Name)

	path := dir.dirOps.Path() + req.Name
	entry, err := dir.vfs.fsOps.LookupPath(ctx, path)
	if err != nil {
		return nil, err
	}

	entryAttribute, err := entry.Attribute(ctx)
	if err != nil {
		return nil, err
	}

	if entryAttribute.IsDir() {
		dirOps, ok := entry.(spacefs.DirOps)
		if !ok {
			// TODO: Return a better syscall error
			return nil, syscall.ENOENT
		}
		return NewVFSDir(dir.vfs, dirOps), nil
	}

	fileOps, ok := entry.(spacefs.FileOps)
	if !ok {
		// TODO: Return a better syscall error
		return nil, syscall.ENOENT
	}

	return &VFSFile{
		vfs:     dir.vfs,
		fileOps: fileOps,
	}, nil
}

// Create is invoked when a new directory is to be created
// It implements the fs.NodeCreator interface
func (dir *VFSDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	path := dir.dirOps.Path()
	log.Printf("Creating a file/directory: %+v in path: %s", *req, path)
	dirEntry, err := dir.vfs.fsOps.CreateEntry(ctx, spacefs.CreateDirEntry{
		Path: fmt.Sprintf("%s%c%s", strings.TrimSuffix(path, "/"), '/', req.Name),
		Mode: req.Mode,
	})
	if err != nil {
		return nil, nil, err
	}

	if dirOps, ok := dirEntry.(spacefs.DirOps); ok {
		return NewVFSDir(dir.vfs, dirOps), nil, nil
	}

	if fileOps, ok := dirEntry.(spacefs.FileOps); ok {
		vfsFile := NewVFSFile(dir.vfs, fileOps)
		handler, err := NewVFSFileHandler(ctx, vfsFile)
		if err != nil {
			return nil, nil, err
		}

		return vfsFile, handler, nil
	}

	return nil, nil, syscall.EACCES
}

// Mkdir implements the fs.NodeMkdirer interface
func (dir *VFSDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	path := dir.dirOps.Path()
	log.Debug(fmt.Sprintf("Mkdir a file/directory: %+v with name %s, in path: %s", *req, req.Name, path))
	dirEntry, err := dir.vfs.fsOps.CreateEntry(ctx, spacefs.CreateDirEntry{
		Path: fmt.Sprintf("%s%c%s", strings.TrimSuffix(path, "/"), '/', req.Name),
		Mode: req.Mode,
	})
	if err != nil {
		return nil, err
	}

	if dirOps, ok := dirEntry.(spacefs.DirOps); ok {
		return NewVFSDir(dir.vfs, dirOps), nil
	}

	log.Error("should not happen", errors.New("created directory is not a directory"))
	return nil, fuse.ENOTSUP
}

// Rename implements the fs.NodeRenamer
// Rename is only implemented for VFSDir and not VFSFile, because we currently don't support renaming files
// and rename on fsOps should only work empty folders.
func (dir *VFSDir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
	parentPath := dir.dirOps.Path()
	log.Debug("Renaming node", "oldName:"+req.OldName, "newName:"+req.NewName, "parentPath:"+parentPath)

	return dir.vfs.fsOps.RenameEntry(ctx, spacefs.RenameDirEntry{
		OldPath: path.Join(parentPath, req.OldName),
		NewPath: path.Join(parentPath, req.NewName),
	})
}

// Remove implements the fs.NodeRemover
func (dir *VFSDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	parentPath := dir.dirOps.Path()
	return dir.vfs.fsOps.DeleteEntry(ctx, path.Join(parentPath, req.Name))
}

func (dir *VFSDir) Access(ctx context.Context, req *fuse.AccessRequest) error {
	return nil
}


================================================
FILE: core/libfuse/files.go
================================================
//+build !windows

package libfuse

import (
	"context"
	"fmt"
	"os"
	"syscall"

	"github.com/FleekHQ/space-daemon/core/spacefs"
	"github.com/FleekHQ/space-daemon/log"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

var (
	_ fs.Node = (*VFSFile)(nil)
	_         = fs.NodeAccesser(&VFSFile{})
	_         = fs.NodeOpener(&VFSFile{})
	_         = fs.NodeSetattrer(&VFSFile{})
	_         = fs.HandleReader(&VFSFileHandler{})
	_         = fs.HandleWriter(&VFSFileHandler{})
	_         = fs.HandleReleaser(&VFSFileHandler{})
)

// VFSFile represents a file in the Virtual file system
type VFSFile struct {
	vfs     *VFS // pointer to the parent file system
	fileOps spacefs.FileOps
}

func NewVFSFile(vfs *VFS, fileOps spacefs.FileOps) *VFSFile {
	return &VFSFile{
		vfs:     vfs,
		fileOps: fileOps,
	}
}

// Attr returns fuse.Attr for the directory or file
func (vfile *VFSFile) Attr(ctx context.Context, attr *fuse.Attr) error {
	path := vfile.fileOps.Path()
	log.Printf("Getting File Attr %s", path)
	fileAttribute, err := vfile.fileOps.Attribute(ctx)
	if err != nil {
		log.Printf("ERROR Getting Open File Attr %s", err.Error())
		return err
	}

	attr.Size = fileAttribute.Size()
	attr.Blocks = getNumBlocksFromSize(attr.Size)
	attr.Mode = fileAttribute.Mode()
	attr.Mtime = fileAttribute.ModTime()
	attr.Ctime = fileAttribute.Ctime()
	attr.Crtime = fileAttribute.Ctime()
	attr.Uid = fileAttribute.Uid()
	attr.Gid = fileAttribute.Gid()

	log.Printf("Successful File Attr %s : %+v", path, attr)

	return nil
}

// Access implements the fs.NodeAccesser interface for File. This is necessary
// for macOS to correctly identify plaintext files as plaintext. If not
// implemented, bazil-fuse returns a nil error for every call, so when macOS
// checks for executable bit using Access (instead of Attr!), it gets a
// success, which makes it think the file is executable, yielding a "Unix
// executable" UTI.
func (vfile *VFSFile) Access(ctx context.Context, r *fuse.AccessRequest) (err error) {
	if int(r.Uid) != os.Getuid() &&
		// Finder likes to use UID 0 for some operations. osxfuse already allows
		// ACCESS and GETXATTR requests from root to go through. This allows root
		// in ACCESS handler.
		int(r.Uid) != 0 {
		// short path: not accessible by anybody other than root or the current user
		return syscall.EPERM
	}

	if r.Mask&03 == 0 {
		// Since we only check for w and x bits, we can return nil early here.
		return nil
	}

	// check is executable mask enable
	if r.Mask&01 != 0 {
		_, err := vfile.fileOps.Attribute(ctx)
		if err != nil {
			return err
		}
		// for now always return permission error for executable calls
		// we are not supporting executable at the moment
		return syscall.EPERM
	}

	return nil
}

// Setattr implements the set attribute of fs.NodeSetattrer
func (vfile *VFSFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
	path := vfile.fileOps.Path()
	log.Debug("Setattr called", "path:"+path, "req.Valid:"+req.Valid.String(), fmt.Sprintf("req:%v", req))
	valid := req.Valid

	if valid.Size() {
		err := vfile.fileOps.Truncate(ctx, req.Size)
		if err != nil {
			return err
		}
		valid ^= fuse.SetattrSize
	}

	return nil
}

// Open create a handle responsible for reading the file and also closing the file after reading
func (vfile *VFSFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	log.Printf("Opening content of file %s", vfile.fileOps.Path())
	return NewVFSFileHandler(ctx, vfile)
}

// VFSFileHandler manages readings and closing access to a VFSFile
type VFSFileHandler struct {
	path         string
	readWriteOps spacefs.FileHandler
}

func NewVFSFileHandler(ctx context.Context, vfile *VFSFile) (*VFSFileHandler, error) {
	readWriteOps, err := vfile.fileOps.Open(ctx, spacefs.ReadMode)
	if err != nil {
		return nil, err
	}

	return &VFSFileHandler{
		path:         vfile.fileOps.Path(),
		readWriteOps: readWriteOps,
	}, nil
}

// Read reads the content of the reader
// Ideally, decryption of the content of the file should be happening here
func (vfh *VFSFileHandler) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	log.Printf("Reading content of file %s, and size: %d", vfh.path, req.Size)
	buf := make([]byte, req.Size)
	n, err := vfh.readWriteOps.Read(ctx, buf, req.Offset)
	if err != nil {
		log.Printf("Reading error: %s", err.Error())
		return err
	}

	resp.Data = buf[:n]
	return nil
}

// Write writes content from request into the underlying file. Keeping track of offset and all
// Ideally, encryption of the content of the file should be happening here
func (vfh *VFSFileHandler) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	log.Printf("Writing content to file %s", vfh.path)
	n, err := vfh.readWriteOps.Write(ctx, req.Data, req.Offset)
	if err != nil {
		log.Printf("Writing error: %s", err.Error())
		return err
	}

	resp.Size = n
	return nil
}

// Release closes the reader on this file handler
func (vfh *VFSFileHandler) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
	return vfh.readWriteOps.Close(ctx)
}


================================================
FILE: core/libfuse/vfs.go
================================================
//+build !windows

package libfuse

import (
	"context"
	"errors"

	"github.com/FleekHQ/space-daemon/log"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/FleekHQ/space-daemon/core/spacefs"
)

var _ fs.FS = (*VFS)(nil)

var (
	errorNotMounted = errors.New("VFS not mounted yet")
)

// VFS represent Virtual System
type VFS struct {
	ctx             context.Context
	fsOps           spacefs.FSOps
	mountConnection *fuse.Conn
	mountPath       string
}

// NewVFileSystem creates a new Virtual FileSystem object
func NewVFileSystem(ctx context.Context, fsOps spacefs.FSOps) *VFS {
	return &VFS{
		// storing ctx here to be used in the Root request
		// as FUSE doesn't provide one there
		ctx:             ctx,
		fsOps:           fsOps,
		mountConnection: nil,
	}
}

// Mount mounts the file system, if it is not already mounted
func (vfs *VFS) Mount(mountPath, fsName string) error {
	c, err := fuse.Mount(
		mountPath,
		fuse.FSName(fsName),
		fuse.VolumeName(fsName),
		fuse.NoAppleDouble(),
		//fuse.ExclCreate(),
		//fuse.NoAppleXattr(),
		fuse.AsyncRead(),
		fuse.LocalVolume(),
	)
	if err != nil {
		return err
	}

	vfs.mountPath = mountPath
	vfs.mountConnection = c
	return nil
}

// IsMounted returns true if the vfs still has a valid connection to the mounted path
func (vfs *VFS) IsMounted() bool {
	return vfs.mountConnection != nil
}

// Serve start the FUSE server that handles requests from the mounted connection
// This is a blocking operation
func (vfs *VFS) Serve() error {
	if !vfs.IsMounted() {
		return errorNotMounted
	}

	if err := fs.Serve(vfs.mountConnection, vfs); err != nil {
		return err
	}

	// check if the mount process has an error to report
	<-vfs.mountConnection.Ready
	if err := vfs.mountConnection.MountError; err != nil {
		return err
	}

	// reset mount connection
	vfs.mountConnection = nil
	return nil
}

// UnMount closes connection
func (vfs *VFS) Unmount() error {
	if !vfs.IsMounted() {
		return errorNotMounted
	}

	err := vfs.mountConnection.Close()
	if err != nil {
		return err
	}

	err = fuse.Unmount(vfs.mountPath)
	if err != nil {
		return err
	}

	vfs.mountConnection = nil
	return err
}

// Root complies with the Fuse Interface that returns the Root Node of our file system
func (vfs *VFS) Root() (fs.Node, error) {
	rootDirEntry, err := vfs.fsOps.Root(vfs.ctx)
	if err != nil {
		return nil, err
	}

	rootDir, ok := rootDirEntry.(spacefs.DirOps)
	if !ok {
		err = errors.New("root directory is not a spacefs.DirOps")
		log.Error("VFS.Root() error", err)
		return nil, err
	}

	node := &VFSDir{
		vfs:    vfs,
		dirOps: rootDir,
	}
	return node, nil
}

var _ fs.FSStatfser = (*VFS)(nil)

// Statfs implements the fs.FSStatfser interface and reports block and storage information stats about VFS
func (vfs *VFS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error {
	//log.Debug("Request Statfs")
	resp.Bsize = fuseBlockSize
	resp.Namelen = ^uint32(0)
	resp.Frsize = fuseBlockSize

	// Simulate a large amount of free space
	storageSize := uint64(1 << 50) // 2^50 bytes approximately 1PiB
	totalAvailableBlocks := getNumBlocksFromSize(storageSize)
	usedBlockSize := getNumBlocksFromSize(0)

	resp.Blocks = totalAvailableBlocks
	resp.Bavail = totalAvailableBlocks - usedBlockSize
	resp.Bfree = totalAvailableBlocks - usedBlockSize
	return nil
}


================================================
FILE: core/permissions/app_token.go
================================================
package permissions

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"errors"
	"strings"
)

var invalidAppTokenErr = errors.New("app token is invalid")

const tokenKeyLength = 20
const tokenSecretLength = 30

type AppToken struct {
	Key         string   `json:"key"`
	Secret      string   `json:"secret"`
	IsMaster    bool     `json:"isMaster"`
	Permissions []string `json:"permissions"`
}

func UnmarshalToken(marshalledToken []byte) (*AppToken, error) {
	var result AppToken
	err := json.Unmarshal(marshalledToken, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

func MarshalToken(tok *AppToken) ([]byte, error) {
	jsonData, err := json.Marshal(tok)
	if err != nil {
		return nil, err
	}

	return jsonData, nil

}

func GenerateRandomToken(isMaster bool, permissions []string) (*AppToken, error) {
	k := make([]byte, tokenKeyLength)
	_, err := rand.Read(k)
	if err != nil {
		return nil, err
	}

	s := make([]byte, tokenSecretLength)
	_, err = rand.Read(s)
	if err != nil {
		return nil, err
	}

	return &AppToken{
		Key:         base64.RawURLEncoding.EncodeToString(k),
		Secret:      base64.RawURLEncoding.EncodeToString(s),
		IsMaster:    isMaster,
		Permissions: permissions,
	}, nil
}

func (a *AppToken) GetAccessToken() string {
	return a.Key + "." + a.Secret
}

func GetKeyAndSecretFromAccessToken(accessToken string) (key string, secret string, err error) {
	tp := strings.Split(accessToken, ".")
	if len(tp) < 2 {
		return "", "", errors.New("invalid token format")
	}

	key = tp[0]
	secret = tp[1]

	return
}


================================================
FILE: core/permissions/app_token_test.go
================================================
package permissions_test

import (
	"testing"

	"github.com/FleekHQ/space-daemon/core/permissions"
	"github.com/stretchr/testify/assert"
)

func TestPermissions_AppToken_Generation(t *testing.T) {
	tok, err := permissions.GenerateRandomToken(true, []string{})
	assert.NoError(t, err)

	marshalled, err := permissions.MarshalToken(tok)
	assert.NoError(t, err)
	unmarshalled, err := permissions.UnmarshalToken(marshalled)
	assert.NoError(t, err)

	assert.Equal(t, tok, unmarshalled)
}

func TestPermissions_AppToken_GenerationWithPerms(t *testing.T) {
	tok, err := permissions.GenerateRandomToken(false, []string{"OpenFile", "ListDirectories"})
	assert.NoError(t, err)

	marshalled, err := permissions.MarshalToken(tok)
	assert.NoError(t, err)
	unmarshalled, err := permissions.UnmarshalToken(marshalled)
	assert.NoError(t, err)

	assert.Equal(t, tok, unmarshalled)
}


================================================
FILE: core/search/bleve/analyzer.go
================================================
package bleve

import (
	"regexp"

	"github.com/blevesearch/bleve/analysis"
	"github.com/blevesearch/bleve/analysis/analyzer/standard"
	filterregex "github.com/blevesearch/bleve/analysis/char/regexp"
	"github.com/blevesearch/bleve/registry"
)

const CustomerAnalyzerName = "space_search_analyzer"

/// Customer Analyzer extends the standard analyzer by registering a regexp character filter
func CustomAnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) {
	rv, err := standard.AnalyzerConstructor(config, cache)
	if err != nil {
		return nil, err
	}

	// replace . with white space - helps to improve results on filenames
	pattern, err := regexp.Compile("\\.")
	if err != nil {
		return nil, err
	}
	replacement := []byte(" ")
	regexpCharFilter := filterregex.New(pattern, replacement)
	rv.CharFilters = append(rv.CharFilters, regexpCharFilter)

	return rv, nil
}

func init() {
	registry.RegisterAnalyzer(CustomerAnalyzerName, CustomAnalyzerConstructor)
}


================================================
FILE: core/search/bleve/bleve.go
================================================
package bleve

import (
	"context"
	"crypto/sha256"
	"fmt"
	"os/user"
	"path/filepath"

	"github.com/blevesearch/bleve/mapping"

	"github.com/FleekHQ/space-daemon/log"

	"github.com/FleekHQ/space-daemon/core/util"

	"github.com/FleekHQ/space-daemon/core/search"
	"github.com/blevesearch/bleve"
)

const DbFileName = "filesIndex.bleve"

type bleveSearchOption struct {
	dbPath string
}

type Option func(o *bleveSearchOption)

// bleveFilesSearchEngine is a files search engine that is backed by bleve
type bleveFilesSearchEngine struct {
	opts bleveSearchOption
	idx  bleve.Index
}

// Creates a new Bleve backed search engine for files and folders
func NewSearchEngine(opts ...Option) *bleveFilesSearchEngine {
	usr, _ := user.Current()

	searchOptions := bleveSearchOption{
		dbPath: filepath.Join(usr.HomeDir, ".fleek-space"),
	}

	for _, opt := range opts {
		opt(&searchOptions)
	}

	return &bleveFilesSearchEngine{
		opts: searchOptions,
	}
}

func (b *bleveFilesSearchEngine) Start() error {
	if b.idx != nil {
		log.Warn("Trying to open already opened search index")
		return nil
	}

	path := filepath.Join(b.opts.dbPath, DbFileName)

	var (
		idx bleve.Index
		err error
	)

	if util.DirEntryExists(path) {
		log.Debug("Opening existing search index")
		idx, err = bleve.Open(path)
	} else {
		log.Debug("Creating and opening new search index")
		indexMapping, err := getSearchIndexMapping()

		if err != nil {
			return err
		}

		idx, err = bleve.New(path, indexMapping)
	}

	if err != nil {
		return err
	}

	b.idx = idx

	return nil
}

func getSearchIndexMapping() (*mapping.IndexMappingImpl, error) {
	indexMapping := bleve.NewIndexMapping()
	indexMapping.DefaultAnalyzer = CustomerAnalyzerName

	filesMapping := bleve.NewDocumentMapping()

	// index the following fields
	nameFm := bleve.NewTextFieldMapping()
	filesMapping.AddFieldMappingsAt("ItemName", nameFm)
	extFm := bleve.NewTextFieldMapping()
	filesMapping.AddFieldMappingsAt("ItemExtension", extFm)
	pathFm := bleve.NewTextFieldMapping()
	filesMapping.AddFieldMappingsAt("ItemPath", pathFm)

	// ignore indexing the following fields of IndexRecord
	idFm := bleve.NewTextFieldMapping()
	idFm.Index = false
	filesMapping.AddFieldMappingsAt("Id", idFm)

	bucketFm := bleve.NewTextFieldMapping()
	bucketFm.Index = false
	filesMapping.AddFieldMappingsAt("BucketSlug", bucketFm)

	dbIdFm := bleve.NewTextFieldMapping()
	dbIdFm.Index = false
	filesMapping.AddFieldMappingsAt("DbId", dbIdFm)

	itemTypeFm := bleve.NewTextFieldMapping()
	itemTypeFm.Index = false
	filesMapping.AddFieldMappingsAt("ItemType", itemTypeFm)

	indexMapping.AddDocumentMapping("files", filesMapping)
	indexMapping.DefaultType = "files"

	return indexMapping, nil
}

func (b *bleveFilesSearchEngine) InsertFileData(
	ctx context.Context,
	data *search.InsertIndexRecord,
) (*search.IndexRecord, error) {
	indexId := generateIndexId(data.ItemName, data.ItemPath, data.BucketSlug, data.DbId)
	record := search.IndexRecord{
		Id:            indexId,
		ItemName:      data.ItemName,
		ItemExtension: data.ItemExtension,
		ItemPath:      data.ItemPath,
		ItemType:      data.ItemType,
		BucketSlug:    data.BucketSlug,
		DbId:          data.DbId,
	}

	if err := b.idx.Index(indexId, record); err != nil {
		return nil, err
	}

	return &record, nil
}

func (b *bleveFilesSearchEngine) DeleteFileData(
	ctx context.Context,
	data *search.DeleteIndexRecord,
) error {
	indexId := generateIndexId(data.ItemName, data.ItemPath, data.BucketSlug, data.DbId)
	return b.idx.Delete(indexId)
}

func (b *bleveFilesSearchEngine) QueryFileData(
	ctx context.Context,
	query string,
	limit int,
) ([]*search.IndexRecord, error) {
	matchQuery := bleve.NewMatchQuery(query)
	matchQuery.Fuzziness = 2

	prefixQuery := bleve.NewPrefixQuery(query)
	infixRegexQuery := bleve.NewRegexpQuery(fmt.Sprintf(".*%s.*", query)) // TODO: think of escaping invalid regex in query

	searchQuery := bleve.NewDisjunctionQuery(matchQuery, prefixQuery, infixRegexQuery)
	searchRequest := bleve.NewSearchRequest(searchQuery)
	searchRequest.Size = limit
	searchRequest.Fields = []string{"*"}

	searchResults, err := b.idx.Search(searchRequest)
	if err != nil {
		return nil, err
	}

	records := make([]*search.IndexRecord, len(searchResults.Hits))
	for i, hit := range searchResults.Hits {
		records[i] = &search.IndexRecord{
			Id:            hit.Fields["Id"].(string),
			ItemName:      hit.Fields["ItemName"].(string),
			ItemExtension: hit.Fields["ItemExtension"].(string),
			ItemPath:      hit.Fields["ItemPath"].(string),
			ItemType:      hit.Fields["ItemType"].(string),
			BucketSlug:    hit.Fields["BucketSlug"].(string),
			DbId:          hit.Fields["DbId"].(string),
		}
	}

	return records, nil
}

func (b *bleveFilesSearchEngine) Shutdown() error {
	if b.idx == nil {
		return nil
	}

	err := b.idx.Close()
	if err != nil {
		return err
	}

	b.idx = nil
	return nil
}

func generateIndexId(name, path, bucketSlug, dbId string) string {
	bytes := sha256.Sum256([]byte(name + path + bucketSlug + dbId))
	return fmt.Sprintf("%x", bytes)
}


================================================
FILE: core/search/bleve/bleve_test.go
================================================
package bleve

import (
	"context"
	"io/ioutil"
	"os"
	"testing"

	"github.com/FleekHQ/space-daemon/core/search"
	"gotest.tools/assert"
)

func setupEngine(t *testing.T) (*bleveFilesSearchEngine, context.Context) {
	dbPath, err := ioutil.TempDir("", "testDb-*")
	assert.NilError(t, err, "failed to create db path")

	engine := NewSearchEngine(WithDBPath(dbPath))
	assert.NilError(t, engine.Start(), "database failed to initialize")

	cleanup := func() {
		_ = engine.Shutdown()
		_ = os.RemoveAll(dbPath)
	}

	t.Cleanup(cleanup)

	return engine, context.Background()
}

func TestEngineStartAndShutdown(t *testing.T) {
	dbPath, err := ioutil.TempDir("", "testDb-*")
	assert.NilError(t, err, "failed to create db path")

	engine := NewSearchEngine(WithDBPath(dbPath))
	assert.NilError(t, engine.Start(), "database failed to initialize")
	assert.NilError(t, engine.Shutdown(), "search engine failed to shutdown")

	// try re-opening the same engine once more
	engine = NewSearchEngine(WithDBPath(dbPath))
	assert.NilError(t, engine.Start(), "failed to re-open existing search index")
	assert.NilError(t, engine.Shutdown(), "failed to shutdown existing search index")
}

func TestFilesSearchEngine_Insert_And_Query(t *testing.T) {
	engine, ctx := setupEngine(t)
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "second-content.txt",
		ItemExtension: "txt",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	queryResult, err := engine.QueryFileData(ctx, "pdf", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 1, len(queryResult), "not enough results returned from query")

	assert.Equal(t, "new content.pdf", queryResult[0].ItemName, "search query result incorrect")
}

func TestInserting_DuplicateRecords_Count_As_Single(t *testing.T) {
	engine, ctx := setupEngine(t)
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	// try inserting duplicate records
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	// validate only a single record exists
	queryResult, err := engine.QueryFileData(ctx, "new content.pdf", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 1, len(queryResult), "only single result should be returned")

	assert.Equal(t, "new content.pdf", queryResult[0].ItemName, "search query result incorrect")
}

func TestFilesSearchEngine_Delete_And_Query(t *testing.T) {
	engine, ctx := setupEngine(t)
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "second-content.txt",
		ItemExtension: "txt",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	err := engine.DeleteFileData(ctx, &search.DeleteIndexRecord{
		ItemName:   "new content.pdf",
		ItemPath:   "/new",
		BucketSlug: "personal",
	})
	assert.NilError(t, err, "deleting file data failed")

	queryResult, err := engine.QueryFileData(ctx, "content", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 1, len(queryResult), "expected only single result")

	// only second content should exist in search engine
	assert.Equal(t, "second-content.txt", queryResult[0].ItemName, "search query result incorrect")
}

func TestPrefixFileSearchWorks(t *testing.T) {
	engine, ctx := setupEngine(t)

	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "hello1.txt",
		ItemExtension: "txt",
		ItemPath:      "/",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "hello2.txt",
		ItemExtension: "txt",
		ItemPath:      "/",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	queryResult, err := engine.QueryFileData(ctx, "he", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 2, len(queryResult), "query result not expected length")

}

func TestInfixFileSearchWorks(t *testing.T) {
	engine, ctx := setupEngine(t)

	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "hello1.txt",
		ItemExtension: "txt",
		ItemPath:      "/",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "hello2.txt",
		ItemExtension: "txt",
		ItemPath:      "/",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	queryResult, err := engine.QueryFileData(ctx, "el", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 2, len(queryResult), "query result not expected length")

}

func insertRecord(
	t *testing.T,
	ctx context.Context,
	engine search.FilesSearchEngine,
	record *search.InsertIndexRecord,
) {
	_, err := engine.InsertFileData(ctx, record)
	assert.NilError(t, err, "failed to insert file data")
}


================================================
FILE: core/search/bleve/options.go
================================================
package bleve

func WithDBPath(path string) Option {
	return func(o *bleveSearchOption) {
		o.dbPath = path
	}
}


================================================
FILE: core/search/engines.go
================================================
package search

import (
	"context"
)

// Represents Search Engines for File and Folders
// Can be used for indexing and querying of File/Folders
type FilesSearchEngine interface {
	Start() error
	InsertFileData(ctx context.Context, data *InsertIndexRecord) (*IndexRecord, error)
	DeleteFileData(ctx context.Context, data *DeleteIndexRecord) error
	QueryFileData(ctx context.Context, query string, limit int) ([]*IndexRecord, error)
}


================================================
FILE: core/search/model.go
================================================
package search

type IndexRecord struct {
	Id            string
	ItemName      string
	ItemExtension string
	ItemPath      string
	ItemType      string
	// Metadata here
	BucketSlug string
	DbId       string
}

type InsertIndexRecord struct {
	ItemName      string
	ItemExtension string
	ItemPath      string
	ItemType      string
	BucketSlug    string
	DbId          string
}

type DeleteIndexRecord struct {
	ItemName   string
	ItemPath   string
	BucketSlug string
	DbId       string // DbId is only required for shared content
}


================================================
FILE: core/search/sqlite/model.go
================================================
package sqlite

import "gorm.io/gorm"

type SearchIndexRecord struct {
	gorm.Model
	ItemName      string `gorm:"index:idx_name_path_bucket,unique"`
	ItemExtension string `gorm:"size:10"`
	ItemPath      string `gorm:"index:idx_name_path_bucket,unique"`
	ItemType      string
	BucketSlug    string `gorm:"index:idx_name_path_bucket,unique"`
	DbId          string `gorm:"index"`
}


================================================
FILE: core/search/sqlite/options.go
================================================
package sqlite

import "gorm.io/gorm/logger"

func WithDBPath(path string) Option {
	return func(o *sqliteSearchOption) {
		o.dbPath = path
	}
}

func WithLogLevel(level logger.LogLevel) Option {
	return func(o *sqliteSearchOption) {
		o.logLevel = level
	}
}


================================================
FILE: core/search/sqlite/sqlite.go
================================================
package sqlite

import (
	"context"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"

	"gorm.io/gorm/logger"

	"github.com/FleekHQ/space-daemon/core/search"

	"github.com/pkg/errors"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

const DbFileName = "filesIndex.db"

type sqliteSearchOption struct {
	dbPath   string
	logLevel logger.LogLevel
}

type Option func(o *sqliteSearchOption)

// sqliteFilesSearchEngine is a files search engine that is backed by sqlite
type sqliteFilesSearchEngine struct {
	db   *gorm.DB
	opts sqliteSearchOption
}

// Creates a new SQLite backed search engine for files and folders
func NewSearchEngine(opts ...Option) *sqliteFilesSearchEngine {
	usr, _ := user.Current()

	searchOptions := sqliteSearchOption{
		dbPath: filepath.Join(usr.HomeDir, ".fleek-space"),
	}

	for _, opt := range opts {
		opt(&searchOptions)
	}

	return &sqliteFilesSearchEngine{
		db:   nil,
		opts: searchOptions,
	}
}

func (s *sqliteFilesSearchEngine) Start() error {
	dsn := filepath.Join(s.opts.dbPath, DbFileName)

	if db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(s.opts.logLevel),
	}); err != nil {
		return errors.Wrap(err, "failed to open database")
	} else {
		s.db = db
	}

	return s.db.AutoMigrate(&SearchIndexRecord{})
}

func (s *sqliteFilesSearchEngine) InsertFileData(ctx context.Context, data *search.InsertIndexRecord) (*search.IndexRecord, error) {
	record := SearchIndexRecord{
		ItemName:      data.ItemName,
		ItemExtension: data.ItemExtension,
		ItemPath:      data.ItemPath,
		ItemType:      data.ItemPath,
		BucketSlug:    data.BucketSlug,
		DbId:          data.DbId,
	}
	result := s.db.Create(&record)

	if result.Error != nil {
		if strings.Contains(result.Error.Error(), "UNIQUE constraint failed") {
			return nil, errors.New("a similar file has already been inserted")
		}
		return nil, result.Error
	}

	return modelToIndexRecord(&record), nil
}

func (s *sqliteFilesSearchEngine) DeleteFileData(ctx context.Context, data *search.DeleteIndexRecord) error {
	stmt := s.db.Where(
		"item_name = ? AND item_path = ? AND bucket_slug = ?",
		data.ItemName,
		data.ItemPath,
		data.BucketSlug,
	)
	if data.DbId != "" {
		stmt = stmt.Where("dbId = ?", data.DbId)
	}

	result := stmt.Delete(&SearchIndexRecord{})

	return result.Error
}

func (s *sqliteFilesSearchEngine) QueryFileData(ctx context.Context, query string, limit int) ([]*search.IndexRecord, error) {
	var records []*SearchIndexRecord
	result := s.db.Where(
		"LOWER(item_name) LIKE ? OR LOWER(item_extension) = ?",
		"%"+strings.ToLower(query)+"%",
		strings.ToLower(query),
	).Limit(limit).Find(&records)

	if result.Error != nil {
		return nil, result.Error
	}

	searchResults := make([]*search.IndexRecord, len(records))
	for i, record := range records {
		searchResults[i] = modelToIndexRecord(record)
	}

	return searchResults, nil
}

func (s *sqliteFilesSearchEngine) Shutdown() error {
	db, err := s.db.DB()
	if err != nil {
		return err
	}

	return db.Close()
}

func modelToIndexRecord(model *SearchIndexRecord) *search.IndexRecord {
	return &search.IndexRecord{
		Id:            strconv.Itoa(int(model.ID)),
		ItemName:      model.ItemName,
		ItemExtension: model.ItemExtension,
		ItemPath:      model.ItemPath,
		ItemType:      model.ItemType,
		BucketSlug:    model.BucketSlug,
		DbId:          model.DbId,
	}
}


================================================
FILE: core/search/sqlite/sqlite_test.go
================================================
package sqlite

import (
	"context"
	"io/ioutil"
	"os"
	"testing"

	"github.com/FleekHQ/space-daemon/core/search"

	"gotest.tools/assert"
)

func setupEngine(t *testing.T) (*sqliteFilesSearchEngine, context.Context) {
	dbPath, err := ioutil.TempDir("", "testDb-*")
	assert.NilError(t, err, "failed to create db path")

	engine := NewSearchEngine(WithDBPath(dbPath))
	assert.NilError(t, engine.Start(), "database failed to initialize")

	cleanup := func() {
		_ = engine.Shutdown()
		_ = os.RemoveAll(dbPath)
	}

	t.Cleanup(cleanup)

	return engine, context.Background()
}

func TestSqliteFilesSearchEngine_Insert_And_Query(t *testing.T) {
	engine, ctx := setupEngine(t)
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "second-content.txt",
		ItemExtension: "txt",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	queryResult, err := engine.QueryFileData(ctx, "pdf", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 1, len(queryResult), "not enough results returned from query")

	assert.Equal(t, "new content.pdf", queryResult[0].ItemName, "search query result incorrect")
}

func TestInserting_DuplicateRecords_Fail(t *testing.T) {
	engine, ctx := setupEngine(t)
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})
	// try inserting duplicate records should fail
	_, err := engine.InsertFileData(ctx, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})
	assert.Error(t, err, "a similar file has already been inserted")
}

func TestSqliteFilesSearchEngine_Delete_And_Query(t *testing.T) {
	engine, ctx := setupEngine(t)
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "new content.pdf",
		ItemExtension: "pdf",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})
	insertRecord(t, ctx, engine, &search.InsertIndexRecord{
		ItemName:      "second-content.txt",
		ItemExtension: "txt",
		ItemPath:      "/new",
		ItemType:      "FILE",
		BucketSlug:    "personal",
		DbId:          "",
	})

	err := engine.DeleteFileData(ctx, &search.DeleteIndexRecord{
		ItemName:   "new content.pdf",
		ItemPath:   "/new",
		BucketSlug: "personal",
	})
	assert.NilError(t, err, "deleting file data failed")

	queryResult, err := engine.QueryFileData(ctx, "content", 20)
	assert.NilError(t, err, "failed to query file data")
	assert.Equal(t, 1, len(queryResult), "too much result returned")

	// only second content should exist in search engine
	assert.Equal(t, "second-content.txt", queryResult[0].ItemName, "search query result incorrect")
}

func insertRecord(
	t *testing.T,
	ctx context.Context,
	engine search.FilesSearchEngine,
	record *search.InsertIndexRecord,
) {
	_, err := engine.InsertFileData(ctx, record)
	assert.NilError(t, err, "failed to insert file data")
}


================================================
FILE: core/space/domain/domain.go
================================================
package domain

import "fmt"

type AppConfig struct {
	Port                 int
	AppPath              string
	TextileHubTarget     string
	TextileThreadsTarget string
}

type DirEntry struct {
	Path          string
	IsDir         bool
	Name          string
	SizeInBytes   string
	Created       string
	Updated       string
	FileExtension string
	Members       []Member
}

type ThreadInfo struct {
	Addresses []string
	Key       string
}

type FileInfo struct {
	DirEntry
	IpfsHash          string
	BackedUp          bool
	LocallyAvailable  bool
	BackupInProgress  bool
	RestoreInProgress bool
}

type OpenFileInfo struct {
	Location string
}

type KeyPair struct {
	PublicKey  string
	PrivateKey string
}

type AddItemResult struct {
	SourcePath string
	BucketPath string
	Bytes      int64
	Error      error
}

type AddItemsResponse struct {
	TotalFiles int64
	TotalBytes int64
	Error      error
}

type Member struct {
	Address   string `json:"address"`
	PublicKey string `json:"publicKey"`
}

type AddWatchFile struct {
	DbId       string `json:"dbId"`
	LocalPath  string `json:"local_path"`
	BucketPath string `json:"bucket_path"`
	BucketKey  string `json:"bucket_key"`
	BucketSlug string `json:"bucket_slug"`
	IsRemote   bool   `json:"isRemote"`
	Cid        string `json:"cid"`
}

type Identity struct {
	Address   string `json:"address"`
	PublicKey string `json:"publicKey"`
	Username  string `json:"username"`
}

type APIError struct {
	Message string `json:"message"`
}

type FileSharingInfo struct {
	Bucket            string
	SharedFileCid     string
	SharedFileKey     string
	SpaceDownloadLink string
}

type NotificationTypes int

const (
	UNKNOWN NotificationTypes = iota
	INVITATION
	USAGEALERT
	INVITATION_REPLY
	REVOKED_INVITATION
)

type FullPath struct {
	DbId      string `json:"dbId"`
	BucketKey string `json:"bucketKey"`
	Bucket    string `json:"bucket"`
	Path      string `json:"path"`
}

type InvitationStatus int

const (
	PENDING  InvitationStatus = 0
	ACCEPTED InvitationStatus = 1
	REJECTED InvitationStatus = 2
)

type Invitation struct {
	InviterPublicKey string           `json:"inviterPublicKey"`
	InviteePublicKey string           `json:"inviteePublicKey"`
	InvitationID     string           `json:"invitationID"`
	Status           InvitationStatus `json:"status"`
	ItemPaths        []FullPath       `json:"itemPaths"`
	Keys             [][]byte         `json:"keys"`
}

type InvitationReply struct {
	InvitationID string `json:"invitationID"`
}

// Represents when an inviter unshared access to previously shared files in ItemPaths
type RevokedInvitation struct {
	InviterPublicKey string     `json:"inviterPublicKey"`
	InviteePublicKey string     `json:"inviteePublicKey"`
	ItemPaths        []FullPath `json:"itemPaths"`
	Keys             [][]byte   `json:"keys"`
}

type UsageAlert struct {
	Used    int64  `json:"used"`
	Limit   int64  `json:"limit"`
	Message string `json:"message"`
}

type MessageBody struct {
	Type NotificationTypes `json:"type"`
	Body []byte            `json:"body"`
}

type Notification struct {
	ID               string            `json:"id"`
	Subject          string            `json:"subject"`
	Body             string            `json:"body"`
	NotificationType NotificationTypes `json:"notificationType"`
	CreatedAt        int64             `json:"createdAt"`
	ReadAt           int64             `json:"readAt"`
	// QUESTION: is there a way to enforce that only one of the below is present
	InvitationValue        Invitation        `json:"invitationValue"`
	UsageAlertValue        UsageAlert        `json:"usageAlertValue"`
	InvitationAcceptValue  InvitationReply   `json:"invitationAcceptValue"`
	RevokedInvitationValue RevokedInvitation `json:"revokedInvitationValue"`
	RelatedObject          interface{}       `json:"relatedObject"`
}

type APISessionTokens struct {
	HubToken      string
	ServicesToken string
}

type MirrorFile struct {
	Path              string
	BucketSlug        string
	Backup            bool
	Shared            bool
	BackupInProgress  bool
	RestoreInProgress bool
}

type SharedDirEntry struct {
	DbID         string
	Bucket       string
	IsPublicLink bool
	FileInfo
	Members  []Member // XXX: it is duplicated from FileInfo
	SharedBy string
}

type SearchFileEntry struct {
	FileInfo
	Bucket string
	DbID   string
}

type KeyBackupType int

const (
	PASSWORD KeyBackupType = 0
	GOOGLE   KeyBackupType = 1
	TWITTER  KeyBackupType = 2
	EMAIL    KeyBackupType = 3
)

func (b KeyBackupType) String() string {
	switch b {
	case 0:
		return "password"
	case 1:
		return "google"
	case 2:
		return "twitter"
	case 3:
		return "email"
	default:
		return fmt.Sprintf("%d", int(b))
	}
}

// SharedFilesRoleAction represents action to be performed on the role
type SharedFilesRoleAction int

const (
	DeleteRoleAction SharedFilesRoleAction = iota
	ReadWriteRoleAction
)


================================================
FILE: core/space/fuse/controller.go
================================================
package fuse

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/FleekHQ/space-daemon/core/space/fuse/installer"

	"github.com/FleekHQ/space-daemon/core/spacefs"

	"github.com/FleekHQ/space-daemon/config"
	"github.com/FleekHQ/space-daemon/core/store"
	"github.com/FleekHQ/space-daemon/log"
)

// Controller is the space domain controller for managing the VFS.
// It is used by the grpc server and app/daemon generally
type Controller struct {
	cfg       config.Config
	vfs       VFS
	store     store.Store
	install   installer.FuseInstaller
	isServed  bool
	mountLock sync.RWMutex
	mountPath string
}

var DefaultFuseDriveName = "Space"

func NewController(
	ctx context.Context,
	cfg config.Config,
	store store.Store,
	sfs *spacefs.SpaceFS,
	install installer.FuseInstaller,
) *Controller {
	vfs := initVFS(ctx, sfs)

	return &Controller{
		cfg:       cfg,
		store:     store,
		vfs:       vfs,
		install:   install,
		isServed:  false,
		mountLock: sync.RWMutex{},
	}
}

// ShouldMount check the store and config to determine if the VFS drive was previously mounted
func (s *Controller) ShouldMount() bool {
	if s.cfg.GetString(config.MountFuseDrive, "false") == "true" {
		return true
	}

	mountFuseDrive, err := s.store.Get([]byte(config.MountFuseDrive))
	if err == nil {
		log.Debug("Persisted mountFuseDrive", fmt.Sprintf("state=%s", string(mountFuseDrive)))
		return string(mountFuseDrive) == "true"
	} else {
		log.Debug("No persisted mountFuseDrive state found")
	}

	return false
}

// Mount mounts the vfs drive and immediately serves the handler.
// It starts the Fuse Server in the background
func (s *Controller) Mount() error {
	s.mountLock.Lock()
	defer s.mountLock.Unlock()

	if s.vfs.IsMounted() {
		return nil
	}

	mountPath, err := getMountPath(s.cfg)
	if err != nil {
		return err
	}

	s.mountPath = mountPath

	err = s.vfs.Mount(
		mountPath,
		s.cfg.GetString(config.FuseDriveName, DefaultFuseDriveName),
	)

	if err != nil {
		if !strings.Contains(err.Error(), "exit status 64") {
			return err
		}

		// a drive mount error, so we try unmounting first and retry mounting
		_ = s.vfs.Unmount()
		s.removeMountedPath()
		err = s.vfs.Mount(
			mountPath,
			s.cfg.GetString(config.FuseDriveName, DefaultFuseDriveName),
		)
		if err != nil {
			return err
		}
	}

	// persist mount state to store to trigger remount on restart
	if err := s.store.Set([]byte(config.MountFuseDrive), []byte("true")); err != nil {
		return err
	}

	s.serve()
	return nil
}

func (s *Controller) GetMountPath() string {
	if !s.IsMounted() {
		return ""
	}

	path, _ := getMountPath(s.cfg)
	return path
}

func (s *Controller) serve() {
	if s.isServed {
		return
	}

	go func() {
		s.isServed = true
		defer func() {
			s.isServed = false
		}()

		// this blocks and unblocks when vfs.Unmount() is called
		// or some external thing happens like user unmounting the drive
		err := s.vfs.Serve()
		if err != nil {
			log.Error("error ending fuse server", err)
		}
		log.Info("FUSE Controller server ended")
	}()
}

func (s *Controller) IsMounted() bool {
	s.mountLock.RLock()
	defer s.mountLock.RUnlock()
	return s.vfs.IsMounted()
}

func (s *Controller) Unmount() error {
	s.mountLock.Lock()
	defer s.mountLock.Unlock()
	if !s.vfs.IsMounted() {
		return nil
	}

	// persist unmount state to store to prevent remount on restart
	if err := s.store.Set([]byte(config.MountFuseDrive), []byte("false")); err != nil {
		return err
	}

	err := s.vfs.Unmount()

	return err
}

func (s *Controller) removeMountedPath() {
	if s.mountPath != "" {
		// try unmounting via os
		err := exec.Command("umount", s.mountPath).Run()
		log.Error("Failed to run unmount command", err)
		err = os.RemoveAll(s.mountPath)
		log.Error("Failed to delete mount directory on unmount", err)
	}
}

func (s *Controller) Shutdown() error {
	return s.Unmount()
}


================================================
FILE: core/space/fuse/fs.go
================================================
package fuse

// VFS represents the handler for virtually mounted drives.
// it is implemented using FUSE for linux and macOS
// and will use dokany for windows
type VFS interface {
	Mount(mountPath, fsName string) error
	IsMounted() bool
	// Serve should be a blocking call and return only on unmount or shutdown
	Serve() error
	Unmount() error
}


================================================
FILE: core/space/fuse/installer/installer_darwin.go
================================================
package installer

import (
	"context"
	"os/exec"

	"github.com/pkg/errors"

	"github.com/FleekHQ/space-daemon/log"
	"github.com/keybase/go-kext"
)

type State int64

const (
	Default State = iota
	Downloading
	Installing
	Error
)

type macFuseInstaller struct {
	state State
}

func NewFuseInstaller() *macFuseInstaller {
	return &macFuseInstaller{
		state: Default,
	}
}

func (d *macFuseInstaller) IsInstalled(ctx context.Context) (bool, error) {
	info, err := kext.LoadInfo("com.github.osxfuse.filesystems.osxfuse")
	if err != nil {
		log.Error("unable to determine state of extension", err)
		return false, err
	}

	return info != nil, nil
}

// Install assumes that the Fuse .pkg installer exists in a particular directory
func (d *macFuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {
	// ideally, this should download the fuse pkg and call the installer

	// first starting with providing a path for it, will change to download as this is a security risk
	d.state = Installing
	path, ok := args["path"].(string)
	if !ok {
		return errors.New("'path' is missing from install arguments")
	}

	installerPath, err := exec.LookPath("installer")
	if err != nil {
		return errors.Wrap(err, "pkg installer not present")
	}

	cmd := exec.Command(installerPath, "-pkg", path, "-target", "/")
	out, err := cmd.CombinedOutput()
	log.Debug("Install command output: " + string(out))
	if err != nil {
		return err
	}

	// load the kernel extension
	return d.loadKernel()
}

func (d *macFuseInstaller) loadKernel() error {
	log.Debug("Loading OSXFUSE Kernel")
	cmd := exec.Command("/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse")
	output, err := cmd.CombinedOutput()
	log.Debug("Kernel Loading Output: " + string(output))
	return err
}


================================================
FILE: core/space/fuse/installer/installer_darwin_test.go
================================================
package installer

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
)

// NOTE: This is more of an integration test and is commented out by default till functional test-suite is ready
func TestMacFuseInstaller(t *testing.T) {
	ctx := context.Background()
	installer := NewFuseInstaller()

	installed, err := installer.IsInstalled(ctx)
	assert.NoError(t, err)
	assert.Equal(t, false, installed, "fuse should not be installed by default")
}


================================================
FILE: core/space/fuse/installer/installer_linux.go
================================================
package installer

import (
	"context"
	"errors"
)

type linuxFuseInstaller struct {
}

func NewFuseInstaller() *linuxFuseInstaller {
	return &linuxFuseInstaller{}
}

func (d *linuxFuseInstaller) IsInstalled(ctx context.Context) (bool, error) {
	return true, nil // assume fuse is installed on recent linux builds
}

func (d *linuxFuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {
	return errors.New("not supported")
}


================================================
FILE: core/space/fuse/installer/installer_windows.go
================================================
package installer

import (
	"context"
	"errors"
)

type windowsFuseInstaller struct {
}

func NewFuseInstaller() *windowsFuseInstaller {
	return &windowsFuseInstaller{}
}

func (d *windowsFuseInstaller) IsInstalled(ctx context.Context) (bool, error) {
	return false, nil
}

func (d *windowsFuseInstaller) Install(ctx context.Context, args map[string]interface{}) error {
	return errors.New("not supported")
}


================================================
FILE: core/space/fuse/installer/interface.go
================================================
package installer

import "context"

type FuseInstaller interface {
	IsInstalled(ctx context.Context) (bool, error)
	Install(ctx context.Context, args map[string]interface{}) error
	// TODO: UnInstall(ctx context.Context)
}


================================================
FILE: core/space/fuse/mount.go
================================================
//+build !windows

package fuse

import (
	"context"
	"fmt"
	"os"
	s "strings"

	"github.com/FleekHQ/space-daemon/core/libfuse"

	"github.com/FleekHQ/space-daemon/core/spacefs"

	"github.com/FleekHQ/space-daemon/config"
	"github.com/mitchellh/go-homedir"
)

func pathExists(path string) bool {
	_, err := os.Stat(path)
	return os.IsExist(err)
}

func getMountPath(cfg config.Config) (string, error) {
	mountPath := cfg.GetString(config.FuseMountPath, "~/"+DefaultFuseDriveName)
	if home, err := homedir.Dir(); err == nil {
		// If the mount directory contains ~, we replace it with the actual home directory
		mountPath = s.TrimRight(
			s.Replace(mountPath, "~", home, -1),
			"/",
		)
	}

	// checks to ensure we are not mounting on an already existing path
	if pathExists(mountPath) {
		// loop through 10 suffixes till we find on that exists
		for i := 0; i < 10; i++ {
			newPath := fmt.Sprintf("%s%d", mountPath, i)
			if !pathExists(newPath) {
				mountPath = newPath
				break
			}
		}
	}

	return mountPath, nil
}

func initVFS(ctx context.Context, sfs spacefs.FSOps) VFS {
	return libfuse.NewVFileSystem(ctx, sfs)
}


================================================
FILE: core/space/fuse/mount_windows.go
================================================
package fuse

import (
	"context"
	"errors"

	"github.com/FleekHQ/space-daemon/config"
	"github.com/FleekHQ/space-daemon/core/spacefs"
)

var errNotImplemented = errors.New("fuse not implemented for windows")

func pathExists(path string) bool {
	return false
}

func getMountPath(cfg config.Config) (string, error) {
	return "", errNotImplemented
}

func initVFS(ctx context.Context, sfs spacefs.FSOps) VFS {
	return &dummyVFS{}
}

// dummyVFS acts a placeholder vfs for windows pending the actual implementation
type dummyVFS struct{}

func (d dummyVFS) Mount(mountPath, fsName string) error {
	return errNotImplemented
}

func (d dummyVFS) IsMounted() bool {
	return false
}

func (d dummyVFS) Serve() error {
	return errNotImplemented
}

func (d dummyVFS) Unmount() error {
	return errNotImplemented
}


================================================
FILE: core/space/fuse/state.go
================================================
package fuse

import (
	"context"
	"runtime"

	"github.com/FleekHQ/space-daemon/log"
)

type State string

const (
	UNSUPPORTED   State = "UNSUPPORTED"
	NOT_INSTALLED State = "NOT_INSTALLED"
	UNMOUNTED     State = "UNMOUNTED"
	MOUNTED       State = "MOUNTED"
	ERROR         State = "ERROR"
)

var supportedOs = map[string]bool{
	"linux":  true,
	"darwin": true,
}

func (s *Controller) GetFuseState(ctx context.Context) (State, error) {
	if !supportedOs[runtime.GOOS] {
		return UNSUPPORTED, nil
	}

	if s.IsMounted() {
		return MOUNTED, nil
	}

	// try and get if it is installed
	installed, err := s.install.IsInstalled(ctx)
	if err != nil {
		log.Error("unable to determine state of extension", err)
		return ERROR, err
	}

	if !installed {
		return NOT_INSTALLED, err
	}

	return UNMOUNTED, nil
}


================================================
FILE: core/space/fuse/state_test.go
================================================
// +build linux darwin

package fuse

import (
	"context"
	"testing"

	"github.com/stretchr/testify/mock"

	"github.com/stretchr/testify/assert"

	"github.com/FleekHQ/space-daemon/core/spacefs"
	"github.com/FleekHQ/space-daemon/mocks"
	fusemocks "github.com/FleekHQ/space-daemon/mocks/fuse"
)

type testCtx struct {
	cfg       *mocks.Config
	st        *mocks.Store
	fsds      *fusemocks.FSDataSource
	installer *fusemocks.FuseInstaller
}

func initTestCtx() (context.Context, *testCtx, *Controller) {
	tctx := &testCtx{
		cfg:       new(mocks.Config),
		st:        new(mocks.Store),
		fsds:      new(fusemocks.FSDataSource),
		installer: new(fusemocks.FuseInstaller),
	}

	ctx := context.Background()
	fs := spacefs.New(tctx.fsds)

	controller := NewController(ctx, tctx.cfg, tctx.st, fs, tctx.installer)
	return ctx, tctx, controller
}

func TestController_GetFuseState_ShouldDefaultTo_Not_Installed(t *testing.T) {
	ctx, test, controller := initTestCtx()

	test.installer.On("IsInstalled", mock.Anything).Return(false, nil)

	state, err := controller.GetFuseState(ctx)
	assert.NoError(t, err, "error on GetFuseState()")

	assert.Equal(t, NOT_INSTALLED, state, "unexpected state gotten")
}

// Note: This is more of an integration test than unit test, but should run cleanly across multiple threads
func TestController_GetFuseState_ShouldBe_Unmounted_When_Installed(t *testing.T) {
	ctx, test, controller := initTestCtx()

	test.installer.On("IsInstalled", mock.Anything).Return(true, nil)

	state, err := controller.GetFuseState(ctx)
	assert.NoError(t, err, "error on GetFuseState()")

	assert.Equal(t, UNMOUNTED, state, "unexpected state gotten")
}


================================================
FILE: core/space/services/fs_utils.go
================================================
package services

import (
	"io"
	"os"

	"github.com/FleekHQ/space-daemon/log"
)

func PathExists(path string) bool {
	if _, err := os.Stat(path); err == nil {
		return true
	}

	return false
}

func IsPathDir(path string) bool {
	fi, err := os.Stat(path)
	if err != nil {
		log.Error("path error check isPathDir", err)
		return false
	}
	mode := fi.Mode()

	return mode.IsDir()
}

func RemoveDuplicates(elements []string) []string {
	// Use map to record duplicates as we find them.
	encountered := map[string]bool{}
	result := []string{}

	for v := range elements {
		if encountered[elements[v]] == true {
			// Do not add duplicate.
		} else {
			// Record this element as an encountered element.
			encountered[elements[v]] = true
			// Append to result slice.
			result = append(result, elements[v])
		}
	}
	// Return the new slice.
	return result
}

// Reader that also counts the amount of Bytes read from the wrappeed reader
type CountingReader struct {
	reader    io.Reader
	BytesRead int64
}

func NewCountingReader(reader io.Reader) *CountingReader {
	return &CountingReader{
		reader:    reader,
		BytesRead: 0,
	}
}

func (r *CountingReader) Read(b []byte) (int, error) {
	n, err := r.reader.Read(b)
	r.BytesRead += int64(n)
	return n, err
}


================================================
FILE: core/space/services/services.go
================================================
package services

import (
	"context"
	"errors"
	"time"

	"github.com/FleekHQ/space-daemon/core/textile/hub"
	"github.com/FleekHQ/space-daemon/core/vault"
	"golang.org/x/sync/errgroup"

	"github.com/FleekHQ/space-daemon/config"
	"github.com/FleekHQ/space-daemon/core/env"
	node "github.com/FleekHQ/space-daemon/core/ipfs/node"
	"github.com/FleekHQ/space-daemon/core/keychain"
	"github.com/FleekHQ/space-daemon/core/space/domain"
	"github.com/FleekHQ/space-daemon/core/store"
	"github.com/FleekHQ/space-daemon/core/textile"
)

// Implementation for space.Service
type Space struct {
	store    store.Store
	cfg      config.Config
	env      env.SpaceEnv
	tc       textile.Client
	sync     Syncer
	keychain keychain.Keychain
	vault    vault.Vault
	hub      hub.HubAuth
	ipfsNode *node.IpfsNode
	buckd    textile.Buckd
	aeg      *errgroup.Group
}

type Syncer interface {
	AddFileWatch(addFileInfo domain.AddWatchFile) error
	GetOpenFilePath(bucketSlug, bucketPath, dbID, cid string) (string, bool)
}

type AddFileWatchFunc = func(addFileInfo domain.AddWatchFile) error

func (s *Space) RegisterSyncer(sync Syncer) {
	s.sync = sync
}

func (s *Space) GetConfig(ctx context.Context) domain.AppConfig {
	return domain.AppConfig{
		Port:                 s.cfg.GetInt(config.SpaceServerPort, "-1"),
		AppPath:              s.env.WorkingFolder(),
		TextileHubTarget:     s.cfg.GetString(config.TextileHubTarget, ""),
		TextileThreadsTarget: s.cfg.GetString(config.TextileThreadsTarget, ""),
	}

}

func NewSpace(
	st store.Store,
	tc textile.Client,
	syncer Syncer,
	cfg config.Config,
	env env.SpaceEnv,
	kc keychain.Keychain,
	v vault.Vault,
	h hub.HubAuth,
) *Space {
	return &Space{
		store:    st,
		cfg:      cfg,
		env:      env,
		tc:       tc,
		sync:     syncer,
		keychain: kc,
		vault:    v,
		hub:      h,
	}
}

var textileClientInitTimeout = time.Second * 60
var textileClientHubTimeout = time.Second * 60 * 3

// Waits for textile client to be initialized before returning.
func (s *Space) waitForTextileInit(ctx context.Context) error {
	if s.tc.IsInitialized() {
		return nil
	}

	select {
	case <-time.After(textileClientInitTimeout):
		return errors.New("textile client not initialized in expected time")
	case <-s.tc.WaitForInitialized():
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

// Waits for textile client to be healthy (initialized and connected to hub) before returning.
// If it exceeds the max amount of retries, it returns an error.
func (s *Space) waitForTextileHub(ctx context.Context) error {
	if s.tc.IsHealthy() {
		return nil
	}

	select {
	case err := <-s.tc.WaitForHealthy():
		// This returns error if there were 3 failed attempts to connect
		if err != nil {
			return err
		}
		return nil
	case <-time.After(textileClientHubTimeout):
		return errors.New("textile client not initialized in expected time")
	case <-ctx.Done():
		return ctx.Err()
	}

}


================================================
FILE: core/space/services/services_app_token.go
================================================
package services

import (
	"context"

	"github.com/FleekHQ/space-daemon/core/permissions"
)

func (s *Space) InitializeMasterAppToken(ctx context.Context) (*permissions.AppToken, error) {
	newAppToken, err := permissions.GenerateRandomToken(true, []string{})
	if err != nil {
		return nil, err
	}

	return newAppToken, s.keychain.StoreAppToken(newAppToken)
}


================================================
FILE: core/space/services/services_central_server.go
================================================
package services

import (
	"context"

	"github.com/FleekHQ/space-daemon/core/space/domain"
)

// Return session token for central services authenticated access
func (s *Space) GetAPISessionTokens(ctx context.Context) (*domain.APISessionTokens, error) {
	tokens, err := s.hub.GetTokensWithCache(ctx)
	if err != nil {
		return nil, err
	}

	return &domain.APISessionTokens{
		HubToken:      tokens.HubToken,
		ServicesToken: tokens.AppToken,
	}, nil
}


================================================
FILE: core/space/services/services_fs.go
================================================
package services

import (
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"

	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/FleekHQ/space-daemon/core/space/domain"
	"github.com/FleekHQ/space-daemon/core/textile"
	"github.com/FleekHQ/space-daemon/core/textile/utils"
	"github.com/FleekHQ/space-daemon/log"
)

var bucketNotFoundErr = errors.New("Could not find bucket")

// Creates a bucket
func (s *Space) CreateBucket(ctx context.Context, slug string) (textile.Bucket, error) {
	err := s.waitForTextileInit(ctx)
	if err != nil {
		return nil, err
	}

	b, err := s.tc.CreateBucket(ctx, slug)
	if err != nil {
		return nil, err
	}

	return b, nil
}

// Returns a list of buckets the current user has access to
func (s *Space) ListBuckets(ctx context.Context) ([]textile.Bucket, error) {
	err := s.waitForTextileInit(ctx)
	if err != nil {
		return nil, err
	}

	buckets, err := s.tc.ListBuckets(ctx)
	if err != nil {
		return nil, err
	}

	return buckets, nil
}

func (s *Space) ShareBucket(ctx context.Context, slug string) (*domain.ThreadInfo, error) {
	err := s.waitForTextileHub(ctx)
	if err != nil {
		return nil, err
	}

	r, err := s.tc.ShareBucket(ctx, slug)
	if err != nil {
		return nil, err
	}

	addrs := make([]string, 0)

	for _, addr := range r.Addrs {
		addrs = append(addrs, addr.String())
	}

	ti := &domain.ThreadInfo{
		Addresses: addrs,
		Key:       r.Key.String(),
	}

	return ti, nil
}

func (s *Space) JoinBucket(ctx context.Context, slug string, threadinfo *domain.ThreadInfo) (bool, error) {
	err := s.waitForTextileHub(ctx)
	if err != nil {
		return false, err
	}

	r, err := s.tc.JoinBucket(ctx, slug, threadinfo)
	if err != nil {
		return false, err
	}

	return r, nil
}

func (s *Space) ToggleBucketBackup(ctx context.Context, bucketSlug string, bucketBackup bool) error {
	err := s.waitForTextileHub(ctx)
	if err != nil {
		return err
	}

	_, err = s.tc.ToggleBucketBackup(ctx, bucketSlug, bucketBackup)
	if err != nil {
		return err
	}

	_, err = s.tc.GetBucket(ctx, bucketSlug, nil)
	if err != nil {
		return err
	}

	return nil
}

func (s *Space) BucketBackupRestore(ctx context.Context, bucketSlug string) error {
	if err := s.waitForTextileHub(ctx); err != nil {
		return err
	}
	if err := s.tc.BucketBackupRestore(ctx, bucketSlug); err != nil {
		return err
	}

	return nil
}

func (s *Space) getBucketForRemoteFile(ctx context.Context, bucketName, dbID, path string) (textile.Bucket, error) {
	input := &textile.GetBucketForRemoteFileInput{
		Bucket: bucketName,
		DbID:   dbID,
		Path:   path,
	}
	b, err := s.tc.GetBucket(ctx, bucketName, input)
	if err != nil {
		return nil, err
	}

	if b == nil {
		return nil, bucketNotFoundErr
	}

	return b, nil
}

// Returns the bucket given the name, and if the name is "" returns the default bucket
func (s *Space) getBucketWithFallback(ctx context.Context, bucketName string) (textile.Bucket, error) {
	var b textile.Bucket
	var err error

	if bucketName == "" {
		b, err = s.tc.GetDefaultBucket(ctx)
	} else {
		b, err = s.tc.GetBucket(ctx, bucketName, nil)
	}

	if err != nil {
		return nil, err
	}

	if b == nil {
		return nil, bucketNotFoundErr
	}

	return b, nil
}

func (s *Space) listDirAtPath(
	ctx context.Context,
	b textile.Bucket,
	path string,
	listSubfolderContent bool,
	listMembers bool,
) ([]domain.FileInfo, error) {
	dir, err := b.ListDirectory(ctx, path)
	if err != nil {
		log.Error("Error in ListDir", err)
		return nil, err
	}

	relPathRegex := regexp.MustCompile(`\/ip(f|n)s\/[^\/]*(?P<relPath>\/.*)`)

	mirrorfilepaths := make([]string, 0)
	for _, item := range dir.Item.Items {
		mirrorfilepaths = append(mirrorfilepaths, item.Path)
	}

	mirror_files, err := s.tc.GetModel().FindMirrorFileByPaths(ctx, mirrorfilepaths)
	if err != nil {
		log.Error("Error fetching mirror files", err)
		return nil, err
	}

	entries := make([]domain.FileInfo, 0)
	for _, item := range dir.Item.Items {
		if utils.IsMetaFileName(item.Name) {
			continue
		}

		paths := relPathRegex.FindStringSubmatch(item.Path)
		var relPath string
		if len(paths) > 2 {
			relPath = relPathRegex.FindStringSubmatch(item.Path)[2]
		} else {
			relPath = item.Path
		}

		members := []domain.Member{}

		if listMembers {
			members, err = s.tc.GetPathAccessRoles(ctx, b, item.Path)
			if err != nil {
				return nil, err
			}
		}

		backedup := false
		backupInProgress := false
		restoreInProgress := false
		if mirror_files[item.Path] != nil {
			backedup = mirror_files[item.Path].Backup
			backupInProgress = mirror_files[item.Path].BackupInProgress
			restoreInProgress = mirror_files[item.Path].RestoreInProgress
		}

		locallyAvailable := false
		if item.IsDir {
			locallyAvailable = true
		} else if e, _ := b.FileExists(ctx, item.Path); e == true {
			locallyAvailable = true
		}

		entry := domain.FileInfo{
			DirEntry: domain.DirEntry{
				Path:          relPath,
				IsDir:         item.IsDir,
				Name:          item.Name,
				SizeInBytes:   strconv.FormatInt(item.Size, 10),
				FileExtension: strings.Replace(filepath.Ext(item.Name), ".", "", -1),
				// FIXME: real created at needed
				Created: time.Unix(0, item.Metadata.UpdatedAt).Format(time.RFC3339),
				Updated: time.Unix(0, item.Metadata.UpdatedAt).Format(time.RFC3339),
				Members: members,
			},
			IpfsHash:          item.Cid,
			BackedUp:          backedup,
			LocallyAvailable:  locallyAvail
Download .txt
gitextract_hiosi7jg/

├── .github/
│   └── workflows/
│       ├── release.yml
│       └── test.yml
├── .gitignore
├── .goreleaser.yml
├── .vscode/
│   └── launch.json
├── LICENSE
├── Makefile
├── README.md
├── app/
│   └── app.go
├── ci/
│   ├── add-osx-cert.sh
│   └── gon.hcl
├── cmd/
│   └── space-daemon/
│       └── main.go
├── config/
│   ├── config.go
│   ├── json_config.go
│   └── map_config.go
├── core/
│   ├── backup/
│   │   └── backup.go
│   ├── component.go
│   ├── env/
│   │   ├── env.go
│   │   └── file_env.go
│   ├── events/
│   │   └── events.go
│   ├── fsds/
│   │   ├── config.go
│   │   ├── data_source.go
│   │   ├── dir_entry.go
│   │   ├── files_ds.go
│   │   ├── read_write_wrapper.go
│   │   ├── shared_with_me_ds.go
│   │   ├── spacefs.go
│   │   └── utils.go
│   ├── ipfs/
│   │   ├── dag.go
│   │   ├── ipfs.go
│   │   ├── node/
│   │   │   └── node.go
│   │   ├── utils.go
│   │   └── utils_test.go
│   ├── keychain/
│   │   ├── app_token.go
│   │   ├── keychain.go
│   │   ├── keyring/
│   │   │   └── keyring.go
│   │   ├── mnemonic.go
│   │   └── test/
│   │       └── keychain_test.go
│   ├── libfuse/
│   │   ├── block_size.go
│   │   ├── directory.go
│   │   ├── files.go
│   │   └── vfs.go
│   ├── permissions/
│   │   ├── app_token.go
│   │   └── app_token_test.go
│   ├── search/
│   │   ├── bleve/
│   │   │   ├── analyzer.go
│   │   │   ├── bleve.go
│   │   │   ├── bleve_test.go
│   │   │   └── options.go
│   │   ├── engines.go
│   │   ├── model.go
│   │   └── sqlite/
│   │       ├── model.go
│   │       ├── options.go
│   │       ├── sqlite.go
│   │       └── sqlite_test.go
│   ├── space/
│   │   ├── domain/
│   │   │   └── domain.go
│   │   ├── fuse/
│   │   │   ├── controller.go
│   │   │   ├── fs.go
│   │   │   ├── installer/
│   │   │   │   ├── installer_darwin.go
│   │   │   │   ├── installer_darwin_test.go
│   │   │   │   ├── installer_linux.go
│   │   │   │   ├── installer_windows.go
│   │   │   │   └── interface.go
│   │   │   ├── mount.go
│   │   │   ├── mount_windows.go
│   │   │   ├── state.go
│   │   │   └── state_test.go
│   │   ├── services/
│   │   │   ├── fs_utils.go
│   │   │   ├── services.go
│   │   │   ├── services_app_token.go
│   │   │   ├── services_central_server.go
│   │   │   ├── services_fs.go
│   │   │   ├── services_identity.go
│   │   │   ├── services_keypair.go
│   │   │   ├── services_notifs.go
│   │   │   ├── services_search.go
│   │   │   ├── services_sharing.go
│   │   │   ├── services_vault.go
│   │   │   └── sharing_utils.go
│   │   ├── space.go
│   │   └── space_test.go
│   ├── spacefs/
│   │   ├── fs.go
│   │   ├── fs_test.go
│   │   └── interfaces.go
│   ├── store/
│   │   └── store.go
│   ├── sync/
│   │   ├── fs.go
│   │   ├── notifier_default.go
│   │   ├── sync.go
│   │   ├── textile.go
│   │   └── textile_test.go
│   ├── textile/
│   │   ├── README.md
│   │   ├── account.go
│   │   ├── buckd.go
│   │   ├── bucket/
│   │   │   ├── bucket.go
│   │   │   ├── bucket_dir.go
│   │   │   ├── bucket_file.go
│   │   │   └── crypto/
│   │   │       ├── crypto.go
│   │   │       ├── crypto_test.go
│   │   │       ├── decrypter.go
│   │   │       └── encrypter.go
│   │   ├── bucket_factory.go
│   │   ├── client.go
│   │   ├── common/
│   │   │   └── common.go
│   │   ├── event_handler.go
│   │   ├── hub/
│   │   │   ├── hmacTestKey
│   │   │   ├── hub_auth.go
│   │   │   └── hub_auth_test.go
│   │   ├── listener.go
│   │   ├── mailbox.go
│   │   ├── mailbox_test.go
│   │   ├── mirror.go
│   │   ├── model/
│   │   │   ├── buckets.go
│   │   │   ├── mirror_file.go
│   │   │   ├── model.go
│   │   │   ├── received_file.go
│   │   │   ├── received_file_test.go
│   │   │   ├── search.go
│   │   │   ├── sent_file.go
│   │   │   └── shared_public_key.go
│   │   ├── notifier/
│   │   │   └── notifier.go
│   │   ├── public.go
│   │   ├── search.go
│   │   ├── secure_bucket_client.go
│   │   ├── sharing.go
│   │   ├── sync/
│   │   │   ├── mirror.go
│   │   │   ├── pinning.go
│   │   │   ├── queue.go
│   │   │   ├── restore.go
│   │   │   ├── sync.go
│   │   │   ├── sync_test.go
│   │   │   ├── synchronizer.go
│   │   │   ├── task-executors.go
│   │   │   ├── task.go
│   │   │   └── threads.go
│   │   ├── textile.go
│   │   └── utils/
│   │       ├── utils.go
│   │       └── utils_test.go
│   ├── util/
│   │   ├── address/
│   │   │   ├── PROTOCOL.md
│   │   │   └── address.go
│   │   ├── paths.go
│   │   └── rlimit/
│   │       ├── rlimit_unix.go
│   │       └── rlimit_windows.go
│   ├── vault/
│   │   ├── vault.go
│   │   └── vault_test.go
│   └── watcher/
│       ├── blacklist.go
│       ├── blacklist_windows.go
│       ├── handler.go
│       ├── options.go
│       ├── watcher.go
│       └── watcher_test.go
├── coverage/
│   └── .gitkeep
├── devtools/
│   └── googleapis/
│       ├── LICENSE
│       ├── README.grpc-gateway
│       └── google/
│           ├── api/
│           │   ├── annotations.proto
│           │   ├── http.proto
│           │   └── httpbody.proto
│           └── rpc/
│               ├── code.proto
│               ├── error_details.proto
│               └── status.proto
├── docs/
│   ├── crypto/
│   │   └── vault.md
│   └── sharing/
│       └── types-of-sharing.md
├── examples/
│   ├── ipfsLite/
│   │   └── ipfsLite.go
│   └── textileBucketsClient/
│       ├── README.md
│       ├── bucket-sync/
│       │   └── bucket-sync.go
│       ├── buckets.go
│       ├── create-thread-with-key/
│       │   └── create-thread-with-key.go
│       ├── join-thread/
│       │   └── join-thread.go
│       ├── local-buck/
│       │   └── local-buck.go
│       ├── open-share-file/
│       │   └── open-share-file.go
│       ├── set-envs
│       └── sync-test/
│           └── sync-test.go
├── go.mod
├── go.sum
├── grpc/
│   ├── auth/
│   │   ├── app_token_auth/
│   │   │   ├── app_token_auth.go
│   │   │   └── auth_from_md.go
│   │   └── middleware/
│   │       └── grpc_auth.go
│   ├── grpc.go
│   ├── handlers.go
│   ├── handlers_account.go
│   ├── handlers_app_token.go
│   ├── handlers_backup.go
│   ├── handlers_central_services.go
│   ├── handlers_fuse.go
│   ├── handlers_key_pair.go
│   ├── handlers_notif.go
│   ├── handlers_search.go
│   ├── handlers_sharing.go
│   ├── handlers_textile.go
│   ├── handlers_vault.go
│   ├── pb/
│   │   ├── space.pb.go
│   │   └── space.pb.gw.go
│   └── proto/
│       └── space.proto
├── integration_tests/
│   ├── README.md
│   ├── fixtures/
│   │   ├── app.go
│   │   ├── client.go
│   │   ├── configs.go
│   │   └── directories.go
│   ├── helpers/
│   │   ├── assertions.go
│   │   ├── directories.go
│   │   └── initialize.go
│   ├── integration_tests_suite_test.go
│   ├── sharing_test.go
│   └── uploads_test.go
├── log/
│   └── logger.go
├── mocks/
│   ├── Bucket.go
│   ├── Client.go
│   ├── FilesSearchEngine.go
│   ├── HubAuth.go
│   ├── Keychain.go
│   ├── Keyring.go
│   ├── Mailbox.go
│   ├── Model.go
│   ├── Store.go
│   ├── Syncer.go
│   ├── Vault.go
│   ├── fuse/
│   │   ├── FSDataSource.go
│   │   └── FuseInstaller.go
│   ├── mock.go
│   ├── mock_config.go
│   ├── mock_env.go
│   ├── mock_textile_handler.go
│   └── mock_textile_users_client.go
├── scripts/
│   └── windows.bat
├── swagger/
│   └── ui/
│       └── space.swagger.json
└── tracing/
    └── tracing.go
Download .txt
Showing preview only (241K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2505 symbols across 190 files)

FILE: app/app.go
  type App (line 41) | type App struct
    method Start (line 69) | func (a *App) Start() error {
    method Run (line 208) | func (a *App) Run(name string, component core.Component) {
    method RunAsync (line 218) | func (a *App) RunAsync(name string, component core.AsyncComponent, fn ...
    method Shutdown (line 251) | func (a *App) Shutdown() error {
  type componentMap (line 49) | type componentMap struct
  function New (line 54) | func New(cfg config.Config, env env.SpaceEnv) *App {

FILE: cmd/space-daemon/main.go
  function main (line 49) | func main() {
  function runCpuProfiler (line 134) | func runCpuProfiler(outputFilePath string) func() {
  function runMemProfiler (line 154) | func runMemProfiler(outputFilePath string) func() {

FILE: config/config.go
  constant JsonConfigFileName (line 8) | JsonConfigFileName       = "space.json"
  constant SpaceServerPort (line 9) | SpaceServerPort          = "space/rpcPort"
  constant SpaceProxyServerPort (line 10) | SpaceProxyServerPort     = "space/rpcProxyPort"
  constant SpaceRestProxyServerPort (line 11) | SpaceRestProxyServerPort = "space/restProxyPort"
  constant SpaceStorageSiteUrl (line 12) | SpaceStorageSiteUrl      = "space/storageSiteUrl"
  constant SpaceStorePath (line 13) | SpaceStorePath           = "space/storePath"
  constant TextileHubTarget (line 14) | TextileHubTarget         = "space/textileHubTarget"
  constant TextileHubMa (line 15) | TextileHubMa             = "space/textileHubMa"
  constant TextileThreadsTarget (line 16) | TextileThreadsTarget     = "space/textileThreadsTarget"
  constant TextileHubGatewayUrl (line 17) | TextileHubGatewayUrl     = "space/TextileHubGatewayUrl"
  constant TextileUserKey (line 18) | TextileUserKey           = "space/textileUserKey"
  constant TextileUserSecret (line 19) | TextileUserSecret        = "space/textileUserSecret"
  constant MountFuseDrive (line 20) | MountFuseDrive           = "space/mountFuseDrive"
  constant FuseMountPath (line 21) | FuseMountPath            = "space/fuseMountPath"
  constant FuseDriveName (line 22) | FuseDriveName            = "space/fuseDriveName"
  constant SpaceServicesAPIURL (line 23) | SpaceServicesAPIURL      = "space/servicesApiUrl"
  constant SpaceVaultAPIURL (line 24) | SpaceVaultAPIURL         = "space/vaultApiUrl"
  constant SpaceVaultSaltSecret (line 25) | SpaceVaultSaltSecret     = "space/vaultSaltSecret"
  constant SpaceServicesHubAuthURL (line 26) | SpaceServicesHubAuthURL  = "space/servicesHubAuthUrl"
  constant Ipfsaddr (line 27) | Ipfsaddr                 = "space/ipfsAddr"
  constant Ipfsnode (line 28) | Ipfsnode                 = "space/ipfsNode"
  constant Ipfsnodeaddr (line 29) | Ipfsnodeaddr             = "space/ipfsNodeAddr"
  constant Ipfsnodepath (line 30) | Ipfsnodepath             = "space/ipfsNodePath"
  constant MinThreadsConnection (line 31) | MinThreadsConnection     = "space/minThreadsConn"
  constant MaxThreadsConnection (line 32) | MaxThreadsConnection     = "space/maxThreadsConn"
  constant BuckdPath (line 33) | BuckdPath                = "space/BuckdPath"
  constant BuckdApiMaAddr (line 34) | BuckdApiMaAddr           = "space/BuckdApiMaAddr"
  constant BuckdApiProxyMaAddr (line 35) | BuckdApiProxyMaAddr      = "space/BuckdApiProxyMaAddr"
  constant BuckdThreadsHostMaAddr (line 36) | BuckdThreadsHostMaAddr   = "Space/BuckdThreadsHostMaAddr"
  constant BuckdGatewayPort (line 37) | BuckdGatewayPort         = "Space/BuckdGatewayPort"
  constant LogLevel (line 38) | LogLevel                 = "Space/LogLevel"
  type Flags (line 45) | type Flags struct
  type Config (line 75) | type Config interface

FILE: config/json_config.go
  type jsonConfig (line 17) | type jsonConfig struct
    method GetString (line 56) | func (c jsonConfig) GetString(key string, defaultValue interface{}) st...
    method GetInt (line 72) | func (c jsonConfig) GetInt(key string, defaultValue interface{}) int {
    method GetBool (line 87) | func (c jsonConfig) GetBool(key string, defaultValue interface{}) bool {
  type defaultSpaceJson (line 21) | type defaultSpaceJson struct
  type defaultJson (line 28) | type defaultJson struct
  function NewJson (line 33) | func NewJson(env env.SpaceEnv) Config {
  function CreateConfigJson (line 100) | func CreateConfigJson() error {

FILE: config/map_config.go
  type mapConfig (line 11) | type mapConfig struct
    method GetString (line 112) | func (m mapConfig) GetString(key string, defaultValue interface{}) str...
    method GetInt (line 124) | func (m mapConfig) GetInt(key string, defaultValue interface{}) int {
    method GetBool (line 136) | func (m mapConfig) GetBool(key string, defaultValue interface{}) bool {
  function NewMap (line 17) | func NewMap(flags *Flags) Config {

FILE: core/backup/backup.go
  type Backup (line 13) | type Backup struct
  function obfuscate (line 20) | func obfuscate(data []byte) ([]byte, error) {
  function deobfuscate (line 40) | func deobfuscate(ciphertext []byte) ([]byte, error) {
  function MarshalBackup (line 63) | func MarshalBackup(path string, b *Backup) error {
  function UnmarshalBackup (line 79) | func UnmarshalBackup(path string) (*Backup, error) {

FILE: core/component.go
  type Component (line 5) | type Component interface
  type AsyncComponent (line 11) | type AsyncComponent interface

FILE: core/env/env.go
  constant SpaceWorkingDir (line 10) | SpaceWorkingDir      = "SPACE_APP_DIR"
  constant LogLevel (line 11) | LogLevel             = "LOG_LEVEL"
  constant IpfsAddr (line 12) | IpfsAddr             = "IPFS_ADDR"
  constant IpfsNode (line 13) | IpfsNode             = "IPFS_NODE"
  constant IpfsNodeAddr (line 14) | IpfsNodeAddr         = "IPFS_NODE_ADDR"
  constant IpfsNodePath (line 15) | IpfsNodePath         = "IPFS_NODE_PATH"
  constant ServicesAPIURL (line 16) | ServicesAPIURL       = "SERVICES_API_URL"
  constant VaultAPIURL (line 17) | VaultAPIURL          = "VAULT_API_URL"
  constant VaultSaltSecret (line 18) | VaultSaltSecret      = "VAULT_SALT_SECRET"
  constant ServicesHubAuthURL (line 19) | ServicesHubAuthURL   = "SERVICES_HUB_AUTH_URL"
  constant SpaceStorageSiteUrl (line 20) | SpaceStorageSiteUrl  = "SPACE_STORAGE_SITE_URL"
  constant TextileHubTarget (line 21) | TextileHubTarget     = "TXL_HUB_TARGET"
  constant TextileHubMa (line 22) | TextileHubMa         = "TXL_HUB_MA"
  constant TextileThreadsTarget (line 23) | TextileThreadsTarget = "TXL_THREADS_TARGET"
  constant TextileHubGatewayUrl (line 24) | TextileHubGatewayUrl = "TXL_HUB_GATEWAY_URL"
  constant TextileUserKey (line 25) | TextileUserKey       = "TXL_USER_KEY"
  constant TextileUserSecret (line 26) | TextileUserSecret    = "TXL_USER_SECRET"
  type SpaceEnv (line 29) | type SpaceEnv interface
  type defaultEnv (line 35) | type defaultEnv struct
    method CurrentFolder (line 38) | func (d defaultEnv) CurrentFolder() (string, error) {
    method WorkingFolder (line 50) | func (d defaultEnv) WorkingFolder() string {
    method LogLevel (line 59) | func (d defaultEnv) LogLevel() string {
  function NewDefault (line 64) | func NewDefault() SpaceEnv {

FILE: core/env/file_env.go
  type spaceEnv (line 11) | type spaceEnv struct
    method CurrentFolder (line 24) | func (s spaceEnv) CurrentFolder() (string, error) {
    method WorkingFolder (line 36) | func (s spaceEnv) WorkingFolder() string {
    method LogLevel (line 51) | func (s spaceEnv) LogLevel() string {
  function New (line 15) | func New() SpaceEnv {

FILE: core/events/events.go
  type FileEventType (line 7) | type FileEventType
  constant FileAdded (line 10) | FileAdded            FileEventType = "FileAdded"
  constant FileDeleted (line 11) | FileDeleted          FileEventType = "FileDeleted"
  constant FileUpdated (line 12) | FileUpdated          FileEventType = "FileUpdated"
  constant FileBackupInProgress (line 13) | FileBackupInProgress FileEventType = "FileBackupInProgress"
  constant FileBackupReady (line 14) | FileBackupReady      FileEventType = "FileBackupReady"
  constant FileRestored (line 16) | FileRestored  FileEventType = "FileRestored"
  constant FileRestoring (line 17) | FileRestoring FileEventType = "FileRestoring"
  constant FolderAdded (line 19) | FolderAdded   FileEventType = "FolderAdded"
  constant FolderDeleted (line 20) | FolderDeleted FileEventType = "FolderDeleted"
  constant FolderUpdated (line 22) | FolderUpdated FileEventType = "FolderUpdated"
  type FileEvent (line 25) | type FileEvent struct
  function NewFileEvent (line 32) | func NewFileEvent(info domain.FileInfo, eventType FileEventType, bucket,...
  type TextileEvent (line 41) | type TextileEvent struct
  function NewTextileEvent (line 45) | func NewTextileEvent(bucketname string) TextileEvent {
  type InvitationStatus (line 51) | type InvitationStatus
  constant Pending (line 54) | Pending InvitationStatus = 0
  constant Accepted (line 55) | Accepted
  constant Rejected (line 56) | Rejected
  type NotificationType (line 59) | type NotificationType
  constant InvitationType (line 62) | InvitationType NotificationType = 0
  type Invitation (line 65) | type Invitation struct
  type NotificationEvent (line 72) | type NotificationEvent struct

FILE: core/fsds/config.go
  type dataSourceConfig (line 12) | type dataSourceConfig struct
  type FSDataSourceConfig (line 16) | type FSDataSourceConfig
  function WithTLFDataSource (line 18) | func WithTLFDataSource(source *TLFDataSource) FSDataSourceConfig {
  function WithFilesDataSources (line 25) | func WithFilesDataSources(service space.Service) FSDataSourceConfig {
  function WithSharedWithMeDataSources (line 35) | func WithSharedWithMeDataSources(service space.Service) FSDataSourceConf...

FILE: core/fsds/data_source.go
  type FileReadWriterCloser (line 11) | type FileReadWriterCloser interface
  type FSDataSource (line 22) | type FSDataSource interface
  type TLFDataSource (line 39) | type TLFDataSource struct
    method ChildPath (line 46) | func (t *TLFDataSource) ChildPath(path string) string {
    method ParentPath (line 51) | func (t *TLFDataSource) ParentPath(path string) string {

FILE: core/fsds/dir_entry.go
  type DirEntry (line 21) | type DirEntry struct
    method Path (line 54) | func (d *DirEntry) Path() string {
    method IsDir (line 68) | func (d *DirEntry) IsDir() bool {
    method Name (line 73) | func (d *DirEntry) Name() string {
    method Size (line 78) | func (d *DirEntry) Size() uint64 {
    method Mode (line 91) | func (d *DirEntry) Mode() os.FileMode {
    method Uid (line 103) | func (d *DirEntry) Uid() uint32 {
    method Gid (line 108) | func (d *DirEntry) Gid() uint32 {
    method Ctime (line 114) | func (d *DirEntry) Ctime() time.Time {
    method ModTime (line 126) | func (d *DirEntry) ModTime() time.Time {
  function NewDirEntry (line 27) | func NewDirEntry(entry domain.DirEntry) *DirEntry {
  function NewDirEntryFromFileInfo (line 31) | func NewDirEntryFromFileInfo(info os.FileInfo, path string) *DirEntry {
  function NewDirEntryWithMode (line 47) | func NewDirEntryWithMode(entry domain.DirEntry, mode os.FileMode) *DirEn...

FILE: core/fsds/files_ds.go
  type filesDataSource (line 20) | type filesDataSource struct
    method Get (line 25) | func (f *filesDataSource) Get(ctx context.Context, path string) (*DirE...
    method GetChildren (line 87) | func (f *filesDataSource) GetChildren(ctx context.Context, path string...
    method Open (line 102) | func (f *filesDataSource) Open(ctx context.Context, path string) (File...
    method CreateEntry (line 114) | func (f *filesDataSource) CreateEntry(ctx context.Context, path string...
    method RenameEntry (line 172) | func (f *filesDataSource) RenameEntry(ctx context.Context, oldPath, ne...
    method DeleteEntry (line 215) | func (f *filesDataSource) DeleteEntry(ctx context.Context, path string...
  function areAllEntriesHidden (line 205) | func areAllEntriesHidden(entries []*DirEntry) bool {

FILE: core/fsds/read_write_wrapper.go
  type SpaceFilesHandler (line 16) | type SpaceFilesHandler struct
    method Read (line 45) | func (s *SpaceFilesHandler) Read(ctx context.Context, b []byte, offset...
    method Write (line 61) | func (s *SpaceFilesHandler) Write(ctx context.Context, b []byte, offse...
    method Close (line 82) | func (s *SpaceFilesHandler) Close(ctx context.Context) error {
    method Stats (line 114) | func (s *SpaceFilesHandler) Stats(ctx context.Context) (*DirEntry, err...
    method Truncate (line 124) | func (s *SpaceFilesHandler) Truncate(ctx context.Context, size uint64)...
    method openLocalFile (line 129) | func (s *SpaceFilesHandler) openLocalFile() {
  type SyncService (line 25) | type SyncService interface
  function OpenSpaceFilesHandler (line 29) | func OpenSpaceFilesHandler(

FILE: core/fsds/shared_with_me_ds.go
  type sharedFileEntry (line 17) | type sharedFileEntry struct
  type sharedWithMeDataSource (line 25) | type sharedWithMeDataSource struct
    method Get (line 32) | func (f *sharedWithMeDataSource) Get(ctx context.Context, path string)...
    method GetChildren (line 74) | func (f *sharedWithMeDataSource) GetChildren(ctx context.Context, path...
    method Open (line 97) | func (f *sharedWithMeDataSource) Open(ctx context.Context, path string...
    method CreateEntry (line 113) | func (f *sharedWithMeDataSource) CreateEntry(ctx context.Context, path...
    method RenameEntry (line 118) | func (f *sharedWithMeDataSource) RenameEntry(ctx context.Context, oldP...
    method DeleteEntry (line 123) | func (f *sharedWithMeDataSource) DeleteEntry(ctx context.Context, path...
    method cacheResults (line 128) | func (f *sharedWithMeDataSource) cacheResults(items []*domain.SharedDi...

FILE: core/fsds/spacefs.go
  type SpaceFSDataSource (line 28) | type SpaceFSDataSource struct
    method Get (line 50) | func (d *SpaceFSDataSource) Get(ctx context.Context, path string) (*Di...
    method findTLFDataSource (line 83) | func (d *SpaceFSDataSource) findTLFDataSource(path string) *TLFDataSou...
    method GetChildren (line 94) | func (d *SpaceFSDataSource) GetChildren(ctx context.Context, path stri...
    method Open (line 123) | func (d *SpaceFSDataSource) Open(ctx context.Context, path string) (Fi...
    method CreateEntry (line 134) | func (d *SpaceFSDataSource) CreateEntry(ctx context.Context, path stri...
    method RenameEntry (line 149) | func (d *SpaceFSDataSource) RenameEntry(ctx context.Context, oldPath, ...
    method DeleteEntry (line 166) | func (d *SpaceFSDataSource) DeleteEntry(ctx context.Context, path stri...
    method getTopLevelDirectories (line 174) | func (d *SpaceFSDataSource) getTopLevelDirectories() []*DirEntry {
  function NewSpaceFSDataSource (line 36) | func NewSpaceFSDataSource(service space.Service, configOptions ...FSData...

FILE: core/fsds/utils.go
  function isBaseDirectory (line 9) | func isBaseDirectory(path string) bool {
  function isDirPath (line 13) | func isDirPath(path string) bool {
  function isNotExistError (line 17) | func isNotExistError(err error) bool {

FILE: core/ipfs/dag.go
  type mapBasedDag (line 15) | type mapBasedDag struct
    method Get (line 24) | func (d *mapBasedDag) Get(ctx context.Context, cid cid.Cid) (ipld.Node...
    method GetMany (line 33) | func (d *mapBasedDag) GetMany(ctx context.Context, cids []cid.Cid) <-c...
    method Add (line 48) | func (d *mapBasedDag) Add(ctx context.Context, node ipld.Node) error {
    method AddMany (line 55) | func (d *mapBasedDag) AddMany(ctx context.Context, nodes []ipld.Node) ...
    method Remove (line 64) | func (d *mapBasedDag) Remove(ctx context.Context, c cid.Cid) error {
    method RemoveMany (line 71) | func (d *mapBasedDag) RemoveMany(ctx context.Context, cids []cid.Cid) ...
  function NewDagService (line 20) | func NewDagService() *mapBasedDag {

FILE: core/ipfs/ipfs.go
  type AddItemResult (line 22) | type AddItemResult struct
  type LinkNodesInput (line 27) | type LinkNodesInput struct
  type LinkNodesResult (line 33) | type LinkNodesResult struct
  type Client (line 37) | type Client interface
  type SpaceIpfsClient (line 45) | type SpaceIpfsClient struct
    method AddItems (line 67) | func (s *SpaceIpfsClient) AddItems(ctx context.Context, items []io.Rea...
    method AddItem (line 90) | func (s *SpaceIpfsClient) AddItem(ctx context.Context, item io.Reader)...
    method LinkNodes (line 95) | func (s *SpaceIpfsClient) LinkNodes(ctx context.Context, nodes []LinkN...
    method PullItem (line 117) | func (s *SpaceIpfsClient) PullItem(ctx context.Context, cid cid.Cid) (...
  function NewSpaceIpfsClient (line 49) | func NewSpaceIpfsClient(cfg config.Config) (*SpaceIpfsClient, error) {

FILE: core/ipfs/node/node.go
  type IpfsNode (line 32) | type IpfsNode struct
    method Start (line 49) | func (node *IpfsNode) Start(ctx context.Context) error {
    method WaitForReady (line 65) | func (node *IpfsNode) WaitForReady() chan bool {
    method Stop (line 69) | func (node *IpfsNode) Stop() error {
    method Shutdown (line 73) | func (node *IpfsNode) Shutdown() error {
    method start (line 78) | func (node *IpfsNode) start() error {
    method stop (line 170) | func (node *IpfsNode) stop() error {
  function NewIpsNode (line 42) | func NewIpsNode(cfg config.Config) *IpfsNode {
  function connectToPeers (line 183) | func connectToPeers(ctx context.Context, ipfs icore.CoreAPI, peers []str...
  function setupPlugins (line 218) | func setupPlugins(externalPluginsPath string) error {
  function cmdCtx (line 237) | func cmdCtx(node *core.IpfsNode, repoPath string) commands.Context {

FILE: core/ipfs/utils.go
  function GetFileHash (line 21) | func GetFileHash(r io.Reader) (string, error) {
  function DownloadIpfsItemViaGateway (line 70) | func DownloadIpfsItemViaGateway(ctx context.Context, gatewayUrl string, ...
  function DownloadIpfsItem (line 91) | func DownloadIpfsItem(ctx context.Context, nodeUrl string, cid cid.Cid) ...

FILE: core/ipfs/utils_test.go
  function TestIpfs_GetFileHash_FromStringReader (line 13) | func TestIpfs_GetFileHash_FromStringReader(t *testing.T) {
  function TestIpfs_GetFileHash_FromFile (line 27) | func TestIpfs_GetFileHash_FromFile(t *testing.T) {

FILE: core/keychain/app_token.go
  constant AppTokenStoreKey (line 10) | AppTokenStoreKey = "appToken"
  constant MasterAppTokenStoreKey (line 11) | MasterAppTokenStoreKey = "masterAppToken"
  method StoreAppToken (line 15) | func (kc *keychain) StoreAppToken(tok *permissions.AppToken) error {
  method GetAppToken (line 64) | func (kc *keychain) GetAppToken(key string) (*permissions.AppToken, erro...
  function getMasterTokenStKey (line 78) | func getMasterTokenStKey() string {

FILE: core/keychain/keychain.go
  constant PrivateKeyStoreKey (line 25) | PrivateKeyStoreKey = "key"
  constant PublicKeyStoreKey (line 26) | PublicKeyStoreKey = "pub"
  constant privKeyMnemonicSeparator (line 28) | privKeyMnemonicSeparator = "___"
  type keychain (line 34) | type keychain struct
    method GenerateKeyPair (line 118) | func (kc *keychain) GenerateKeyPair() ([]byte, []byte, error) {
    method GetStoredKeyPairInLibP2PFormat (line 128) | func (kc *keychain) GetStoredKeyPairInLibP2PFormat() (crypto.PrivKey, ...
    method GenerateKeyPairWithForce (line 162) | func (kc *keychain) GenerateKeyPairWithForce() ([]byte, []byte, error) {
    method GetStoredPublicKey (line 169) | func (kc *keychain) GetStoredPublicKey() (crypto.PubKey, error) {
    method GetStoredMnemonic (line 196) | func (kc *keychain) GetStoredMnemonic() (string, error) {
    method ImportExistingKeyPair (line 207) | func (kc *keychain) ImportExistingKeyPair(priv crypto.PrivKey, mnemoni...
    method DeleteKeypair (line 227) | func (kc *keychain) DeleteKeypair() error {
    method generateKeyPair (line 246) | func (kc *keychain) generateKeyPair(seed []byte) ([]byte, []byte, erro...
    method generateAndStoreKeyPair (line 261) | func (kc *keychain) generateAndStoreKeyPair(seed []byte, mnemonic stri...
    method Sign (line 286) | func (kc *keychain) Sign(message []byte) ([]byte, error) {
    method getKeyRing (line 295) | func (kc *keychain) getKeyRing() (ri.Keyring, error) {
    method storeKeyPair (line 331) | func (kc *keychain) storeKeyPair(privKey []byte, pubKey []byte, mnemon...
    method retrieveKeyPair (line 359) | func (kc *keychain) retrieveKeyPair() (privKey []byte, mnemonic string...
    method GetManagedThreadKey (line 383) | func (kc *keychain) GetManagedThreadKey(threadKeyName string) (thread....
  type Keychain (line 41) | type Keychain interface
  type keychainOptions (line 56) | type keychainOptions struct
  function WithPath (line 69) | func WithPath(path string) Option {
  function WithStore (line 77) | func WithStore(st store.Store) Option {
  function WithKeyring (line 86) | func WithKeyring(ring ri.Keyring) Option {
  type Option (line 94) | type Option
  function New (line 96) | func New(opts ...Option) *keychain {

FILE: core/keychain/keyring/keyring.go
  type Keyring (line 5) | type Keyring interface

FILE: core/keychain/mnemonic.go
  type generateKeyFromMnemonicOpts (line 11) | type generateKeyFromMnemonicOpts struct
  type GenerateKeyFromMnemonicOpts (line 23) | type GenerateKeyFromMnemonicOpts
  function WithMnemonic (line 25) | func WithMnemonic(mnemonic string) GenerateKeyFromMnemonicOpts {
  function WithPassword (line 33) | func WithPassword(password string) GenerateKeyFromMnemonicOpts {
  function WithOverride (line 41) | func WithOverride() GenerateKeyFromMnemonicOpts {
  method GenerateKeyFromMnemonic (line 51) | func (kc *keychain) GenerateKeyFromMnemonic(opts ...GenerateKeyFromMnemo...

FILE: core/keychain/test/keychain_test.go
  function initTestKeychain (line 23) | func initTestKeychain(t *testing.T) keychain.Keychain {
  function TestKeychain_GenerateAndRestore (line 34) | func TestKeychain_GenerateAndRestore(t *testing.T) {
  function TestKeychain_GenerateMnemonicKey (line 65) | func TestKeychain_GenerateMnemonicKey(t *testing.T) {
  function TestKeychain_RestoreMnemonicKey (line 83) | func TestKeychain_RestoreMnemonicKey(t *testing.T) {
  function TestKeychain_RestoreMnemonicKeyOnOverrideErr (line 107) | func TestKeychain_RestoreMnemonicKeyOnOverrideErr(t *testing.T) {
  function TestKeychain_RestoreMnemonicKeyExistsButNotInKeyring (line 124) | func TestKeychain_RestoreMnemonicKeyExistsButNotInKeyring(t *testing.T) {
  function TestKeychain_RestoreMnemonicKeyMnemonicErr (line 148) | func TestKeychain_RestoreMnemonicKeyMnemonicErr(t *testing.T) {
  function TestKeychain_RestoreMnemonicKeyOnOverrideSuccess (line 163) | func TestKeychain_RestoreMnemonicKeyOnOverrideSuccess(t *testing.T) {
  function TestKeychain_GetStoredMnemonic (line 188) | func TestKeychain_GetStoredMnemonic(t *testing.T) {
  function TestKeychain_AppToken_StoreMaster (line 206) | func TestKeychain_AppToken_StoreMaster(t *testing.T) {
  function TestKeychain_AppToken_StoreNonMaster (line 238) | func TestKeychain_AppToken_StoreNonMaster(t *testing.T) {
  function TestKeychain_AppToken_StoreMasterOverride1 (line 267) | func TestKeychain_AppToken_StoreMasterOverride1(t *testing.T) {
  function TestKeychain_AppToken_StoreMasterOverride2 (line 279) | func TestKeychain_AppToken_StoreMasterOverride2(t *testing.T) {
  function TestKeychain_AppToken_Get (line 292) | func TestKeychain_AppToken_Get(t *testing.T) {

FILE: core/libfuse/block_size.go
  constant fuseBlockSize (line 9) | fuseBlockSize = 512
  function getNumBlocksFromSize (line 11) | func getNumBlocksFromSize(size uint64) uint64 {

FILE: core/libfuse/directory.go
  type VFSDir (line 32) | type VFSDir struct
    method Attr (line 45) | func (dir *VFSDir) Attr(ctx context.Context, attr *fuse.Attr) error {
    method ReadDirAll (line 60) | func (dir *VFSDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, err...
    method Lookup (line 91) | func (dir *VFSDir) Lookup(ctx context.Context, req *fuse.LookupRequest...
    method Create (line 128) | func (dir *VFSDir) Create(ctx context.Context, req *fuse.CreateRequest...
    method Mkdir (line 157) | func (dir *VFSDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) ...
    method Rename (line 179) | func (dir *VFSDir) Rename(ctx context.Context, req *fuse.RenameRequest...
    method Remove (line 190) | func (dir *VFSDir) Remove(ctx context.Context, req *fuse.RemoveRequest...
    method Access (line 195) | func (dir *VFSDir) Access(ctx context.Context, req *fuse.AccessRequest...
  function NewVFSDir (line 37) | func NewVFSDir(vfs *VFS, dirOps spacefs.DirOps) *VFSDir {

FILE: core/libfuse/files.go
  type VFSFile (line 29) | type VFSFile struct
    method Attr (line 42) | func (vfile *VFSFile) Attr(ctx context.Context, attr *fuse.Attr) error {
    method Access (line 71) | func (vfile *VFSFile) Access(ctx context.Context, r *fuse.AccessReques...
    method Setattr (line 101) | func (vfile *VFSFile) Setattr(ctx context.Context, req *fuse.SetattrRe...
    method Open (line 118) | func (vfile *VFSFile) Open(ctx context.Context, req *fuse.OpenRequest,...
  function NewVFSFile (line 34) | func NewVFSFile(vfs *VFS, fileOps spacefs.FileOps) *VFSFile {
  type VFSFileHandler (line 124) | type VFSFileHandler struct
    method Read (line 143) | func (vfh *VFSFileHandler) Read(ctx context.Context, req *fuse.ReadReq...
    method Write (line 158) | func (vfh *VFSFileHandler) Write(ctx context.Context, req *fuse.WriteR...
    method Release (line 171) | func (vfh *VFSFileHandler) Release(ctx context.Context, req *fuse.Rele...
  function NewVFSFileHandler (line 129) | func NewVFSFileHandler(ctx context.Context, vfile *VFSFile) (*VFSFileHan...

FILE: core/libfuse/vfs.go
  type VFS (line 23) | type VFS struct
    method Mount (line 42) | func (vfs *VFS) Mount(mountPath, fsName string) error {
    method IsMounted (line 63) | func (vfs *VFS) IsMounted() bool {
    method Serve (line 69) | func (vfs *VFS) Serve() error {
    method Unmount (line 90) | func (vfs *VFS) Unmount() error {
    method Root (line 110) | func (vfs *VFS) Root() (fs.Node, error) {
    method Statfs (line 133) | func (vfs *VFS) Statfs(ctx context.Context, req *fuse.StatfsRequest, r...
  function NewVFileSystem (line 31) | func NewVFileSystem(ctx context.Context, fsOps spacefs.FSOps) *VFS {

FILE: core/permissions/app_token.go
  constant tokenKeyLength (line 13) | tokenKeyLength = 20
  constant tokenSecretLength (line 14) | tokenSecretLength = 30
  type AppToken (line 16) | type AppToken struct
    method GetAccessToken (line 64) | func (a *AppToken) GetAccessToken() string {
  function UnmarshalToken (line 23) | func UnmarshalToken(marshalledToken []byte) (*AppToken, error) {
  function MarshalToken (line 33) | func MarshalToken(tok *AppToken) ([]byte, error) {
  function GenerateRandomToken (line 43) | func GenerateRandomToken(isMaster bool, permissions []string) (*AppToken...
  function GetKeyAndSecretFromAccessToken (line 68) | func GetKeyAndSecretFromAccessToken(accessToken string) (key string, sec...

FILE: core/permissions/app_token_test.go
  function TestPermissions_AppToken_Generation (line 10) | func TestPermissions_AppToken_Generation(t *testing.T) {
  function TestPermissions_AppToken_GenerationWithPerms (line 22) | func TestPermissions_AppToken_GenerationWithPerms(t *testing.T) {

FILE: core/search/bleve/analyzer.go
  constant CustomerAnalyzerName (line 12) | CustomerAnalyzerName = "space_search_analyzer"
  function CustomAnalyzerConstructor (line 15) | func CustomAnalyzerConstructor(config map[string]interface{}, cache *reg...
  function init (line 33) | func init() {

FILE: core/search/bleve/bleve.go
  constant DbFileName (line 20) | DbFileName = "filesIndex.bleve"
  type bleveSearchOption (line 22) | type bleveSearchOption struct
  type Option (line 26) | type Option
  type bleveFilesSearchEngine (line 29) | type bleveFilesSearchEngine struct
    method Start (line 51) | func (b *bleveFilesSearchEngine) Start() error {
    method InsertFileData (line 124) | func (b *bleveFilesSearchEngine) InsertFileData(
    method DeleteFileData (line 146) | func (b *bleveFilesSearchEngine) DeleteFileData(
    method QueryFileData (line 154) | func (b *bleveFilesSearchEngine) QueryFileData(
    method Shutdown (line 191) | func (b *bleveFilesSearchEngine) Shutdown() error {
  function NewSearchEngine (line 35) | func NewSearchEngine(opts ...Option) *bleveFilesSearchEngine {
  function getSearchIndexMapping (line 87) | func getSearchIndexMapping() (*mapping.IndexMappingImpl, error) {
  function generateIndexId (line 205) | func generateIndexId(name, path, bucketSlug, dbId string) string {

FILE: core/search/bleve/bleve_test.go
  function setupEngine (line 13) | func setupEngine(t *testing.T) (*bleveFilesSearchEngine, context.Context) {
  function TestEngineStartAndShutdown (line 30) | func TestEngineStartAndShutdown(t *testing.T) {
  function TestFilesSearchEngine_Insert_And_Query (line 44) | func TestFilesSearchEngine_Insert_And_Query(t *testing.T) {
  function TestInserting_DuplicateRecords_Count_As_Single (line 70) | func TestInserting_DuplicateRecords_Count_As_Single(t *testing.T) {
  function TestFilesSearchEngine_Delete_And_Query (line 99) | func TestFilesSearchEngine_Delete_And_Query(t *testing.T) {
  function TestPrefixFileSearchWorks (line 133) | func TestPrefixFileSearchWorks(t *testing.T) {
  function TestInfixFileSearchWorks (line 160) | func TestInfixFileSearchWorks(t *testing.T) {
  function insertRecord (line 187) | func insertRecord(

FILE: core/search/bleve/options.go
  function WithDBPath (line 3) | func WithDBPath(path string) Option {

FILE: core/search/engines.go
  type FilesSearchEngine (line 9) | type FilesSearchEngine interface

FILE: core/search/model.go
  type IndexRecord (line 3) | type IndexRecord struct
  type InsertIndexRecord (line 14) | type InsertIndexRecord struct
  type DeleteIndexRecord (line 23) | type DeleteIndexRecord struct

FILE: core/search/sqlite/model.go
  type SearchIndexRecord (line 5) | type SearchIndexRecord struct

FILE: core/search/sqlite/options.go
  function WithDBPath (line 5) | func WithDBPath(path string) Option {
  function WithLogLevel (line 11) | func WithLogLevel(level logger.LogLevel) Option {

FILE: core/search/sqlite/sqlite.go
  constant DbFileName (line 19) | DbFileName = "filesIndex.db"
  type sqliteSearchOption (line 21) | type sqliteSearchOption struct
  type Option (line 26) | type Option
  type sqliteFilesSearchEngine (line 29) | type sqliteFilesSearchEngine struct
    method Start (line 52) | func (s *sqliteFilesSearchEngine) Start() error {
    method InsertFileData (line 66) | func (s *sqliteFilesSearchEngine) InsertFileData(ctx context.Context, ...
    method DeleteFileData (line 87) | func (s *sqliteFilesSearchEngine) DeleteFileData(ctx context.Context, ...
    method QueryFileData (line 103) | func (s *sqliteFilesSearchEngine) QueryFileData(ctx context.Context, q...
    method Shutdown (line 123) | func (s *sqliteFilesSearchEngine) Shutdown() error {
  function NewSearchEngine (line 35) | func NewSearchEngine(opts ...Option) *sqliteFilesSearchEngine {
  function modelToIndexRecord (line 132) | func modelToIndexRecord(model *SearchIndexRecord) *search.IndexRecord {

FILE: core/search/sqlite/sqlite_test.go
  function setupEngine (line 14) | func setupEngine(t *testing.T) (*sqliteFilesSearchEngine, context.Contex...
  function TestSqliteFilesSearchEngine_Insert_And_Query (line 31) | func TestSqliteFilesSearchEngine_Insert_And_Query(t *testing.T) {
  function TestInserting_DuplicateRecords_Fail (line 57) | func TestInserting_DuplicateRecords_Fail(t *testing.T) {
  function TestSqliteFilesSearchEngine_Delete_And_Query (line 79) | func TestSqliteFilesSearchEngine_Delete_And_Query(t *testing.T) {
  function insertRecord (line 113) | func insertRecord(

FILE: core/space/domain/domain.go
  type AppConfig (line 5) | type AppConfig struct
  type DirEntry (line 12) | type DirEntry struct
  type ThreadInfo (line 23) | type ThreadInfo struct
  type FileInfo (line 28) | type FileInfo struct
  type OpenFileInfo (line 37) | type OpenFileInfo struct
  type KeyPair (line 41) | type KeyPair struct
  type AddItemResult (line 46) | type AddItemResult struct
  type AddItemsResponse (line 53) | type AddItemsResponse struct
  type Member (line 59) | type Member struct
  type AddWatchFile (line 64) | type AddWatchFile struct
  type Identity (line 74) | type Identity struct
  type APIError (line 80) | type APIError struct
  type FileSharingInfo (line 84) | type FileSharingInfo struct
  type NotificationTypes (line 91) | type NotificationTypes
  constant UNKNOWN (line 94) | UNKNOWN NotificationTypes = iota
  constant INVITATION (line 95) | INVITATION
  constant USAGEALERT (line 96) | USAGEALERT
  constant INVITATION_REPLY (line 97) | INVITATION_REPLY
  constant REVOKED_INVITATION (line 98) | REVOKED_INVITATION
  type FullPath (line 101) | type FullPath struct
  type InvitationStatus (line 108) | type InvitationStatus
  constant PENDING (line 111) | PENDING  InvitationStatus = 0
  constant ACCEPTED (line 112) | ACCEPTED InvitationStatus = 1
  constant REJECTED (line 113) | REJECTED InvitationStatus = 2
  type Invitation (line 116) | type Invitation struct
  type InvitationReply (line 125) | type InvitationReply struct
  type RevokedInvitation (line 130) | type RevokedInvitation struct
  type UsageAlert (line 137) | type UsageAlert struct
  type MessageBody (line 143) | type MessageBody struct
  type Notification (line 148) | type Notification struct
  type APISessionTokens (line 163) | type APISessionTokens struct
  type MirrorFile (line 168) | type MirrorFile struct
  type SharedDirEntry (line 177) | type SharedDirEntry struct
  type SearchFileEntry (line 186) | type SearchFileEntry struct
  type KeyBackupType (line 192) | type KeyBackupType
    method String (line 201) | func (b KeyBackupType) String() string {
  constant PASSWORD (line 195) | PASSWORD KeyBackupType = 0
  constant GOOGLE (line 196) | GOOGLE   KeyBackupType = 1
  constant TWITTER (line 197) | TWITTER  KeyBackupType = 2
  constant EMAIL (line 198) | EMAIL    KeyBackupType = 3
  type SharedFilesRoleAction (line 217) | type SharedFilesRoleAction
  constant DeleteRoleAction (line 220) | DeleteRoleAction SharedFilesRoleAction = iota
  constant ReadWriteRoleAction (line 221) | ReadWriteRoleAction

FILE: core/space/fuse/controller.go
  type Controller (line 22) | type Controller struct
    method ShouldMount (line 54) | func (s *Controller) ShouldMount() bool {
    method Mount (line 72) | func (s *Controller) Mount() error {
    method GetMountPath (line 118) | func (s *Controller) GetMountPath() string {
    method serve (line 127) | func (s *Controller) serve() {
    method IsMounted (line 148) | func (s *Controller) IsMounted() bool {
    method Unmount (line 154) | func (s *Controller) Unmount() error {
    method removeMountedPath (line 171) | func (s *Controller) removeMountedPath() {
    method Shutdown (line 181) | func (s *Controller) Shutdown() error {
  function NewController (line 34) | func NewController(

FILE: core/space/fuse/fs.go
  type VFS (line 6) | type VFS interface

FILE: core/space/fuse/installer/installer_darwin.go
  type State (line 13) | type State
  constant Default (line 16) | Default State = iota
  constant Downloading (line 17) | Downloading
  constant Installing (line 18) | Installing
  constant Error (line 19) | Error
  type macFuseInstaller (line 22) | type macFuseInstaller struct
    method IsInstalled (line 32) | func (d *macFuseInstaller) IsInstalled(ctx context.Context) (bool, err...
    method Install (line 43) | func (d *macFuseInstaller) Install(ctx context.Context, args map[strin...
    method loadKernel (line 69) | func (d *macFuseInstaller) loadKernel() error {
  function NewFuseInstaller (line 26) | func NewFuseInstaller() *macFuseInstaller {

FILE: core/space/fuse/installer/installer_darwin_test.go
  function TestMacFuseInstaller (line 11) | func TestMacFuseInstaller(t *testing.T) {

FILE: core/space/fuse/installer/installer_linux.go
  type linuxFuseInstaller (line 8) | type linuxFuseInstaller struct
    method IsInstalled (line 15) | func (d *linuxFuseInstaller) IsInstalled(ctx context.Context) (bool, e...
    method Install (line 19) | func (d *linuxFuseInstaller) Install(ctx context.Context, args map[str...
  function NewFuseInstaller (line 11) | func NewFuseInstaller() *linuxFuseInstaller {

FILE: core/space/fuse/installer/installer_windows.go
  type windowsFuseInstaller (line 8) | type windowsFuseInstaller struct
    method IsInstalled (line 15) | func (d *windowsFuseInstaller) IsInstalled(ctx context.Context) (bool,...
    method Install (line 19) | func (d *windowsFuseInstaller) Install(ctx context.Context, args map[s...
  function NewFuseInstaller (line 11) | func NewFuseInstaller() *windowsFuseInstaller {

FILE: core/space/fuse/installer/interface.go
  type FuseInstaller (line 5) | type FuseInstaller interface

FILE: core/space/fuse/mount.go
  function pathExists (line 19) | func pathExists(path string) bool {
  function getMountPath (line 24) | func getMountPath(cfg config.Config) (string, error) {
  function initVFS (line 49) | func initVFS(ctx context.Context, sfs spacefs.FSOps) VFS {

FILE: core/space/fuse/mount_windows.go
  function pathExists (line 13) | func pathExists(path string) bool {
  function getMountPath (line 17) | func getMountPath(cfg config.Config) (string, error) {
  function initVFS (line 21) | func initVFS(ctx context.Context, sfs spacefs.FSOps) VFS {
  type dummyVFS (line 26) | type dummyVFS struct
    method Mount (line 28) | func (d dummyVFS) Mount(mountPath, fsName string) error {
    method IsMounted (line 32) | func (d dummyVFS) IsMounted() bool {
    method Serve (line 36) | func (d dummyVFS) Serve() error {
    method Unmount (line 40) | func (d dummyVFS) Unmount() error {

FILE: core/space/fuse/state.go
  type State (line 10) | type State
  constant UNSUPPORTED (line 13) | UNSUPPORTED   State = "UNSUPPORTED"
  constant NOT_INSTALLED (line 14) | NOT_INSTALLED State = "NOT_INSTALLED"
  constant UNMOUNTED (line 15) | UNMOUNTED     State = "UNMOUNTED"
  constant MOUNTED (line 16) | MOUNTED       State = "MOUNTED"
  constant ERROR (line 17) | ERROR         State = "ERROR"
  method GetFuseState (line 25) | func (s *Controller) GetFuseState(ctx context.Context) (State, error) {

FILE: core/space/fuse/state_test.go
  type testCtx (line 18) | type testCtx struct
  function initTestCtx (line 25) | func initTestCtx() (context.Context, *testCtx, *Controller) {
  function TestController_GetFuseState_ShouldDefaultTo_Not_Installed (line 40) | func TestController_GetFuseState_ShouldDefaultTo_Not_Installed(t *testin...
  function TestController_GetFuseState_ShouldBe_Unmounted_When_Installed (line 52) | func TestController_GetFuseState_ShouldBe_Unmounted_When_Installed(t *te...

FILE: core/space/services/fs_utils.go
  function PathExists (line 10) | func PathExists(path string) bool {
  function IsPathDir (line 18) | func IsPathDir(path string) bool {
  function RemoveDuplicates (line 29) | func RemoveDuplicates(elements []string) []string {
  type CountingReader (line 49) | type CountingReader struct
    method Read (line 61) | func (r *CountingReader) Read(b []byte) (int, error) {
  function NewCountingReader (line 54) | func NewCountingReader(reader io.Reader) *CountingReader {

FILE: core/space/services/services.go
  type Space (line 22) | type Space struct
    method RegisterSyncer (line 43) | func (s *Space) RegisterSyncer(sync Syncer) {
    method GetConfig (line 47) | func (s *Space) GetConfig(ctx context.Context) domain.AppConfig {
    method waitForTextileInit (line 83) | func (s *Space) waitForTextileInit(ctx context.Context) error {
    method waitForTextileHub (line 100) | func (s *Space) waitForTextileHub(ctx context.Context) error {
  type Syncer (line 36) | type Syncer interface
  function NewSpace (line 57) | func NewSpace(

FILE: core/space/services/services_app_token.go
  method InitializeMasterAppToken (line 9) | func (s *Space) InitializeMasterAppToken(ctx context.Context) (*permissi...

FILE: core/space/services/services_central_server.go
  method GetAPISessionTokens (line 10) | func (s *Space) GetAPISessionTokens(ctx context.Context) (*domain.APISes...

FILE: core/space/services/services_fs.go
  method CreateBucket (line 27) | func (s *Space) CreateBucket(ctx context.Context, slug string) (textile....
  method ListBuckets (line 42) | func (s *Space) ListBuckets(ctx context.Context) ([]textile.Bucket, erro...
  method ShareBucket (line 56) | func (s *Space) ShareBucket(ctx context.Context, slug string) (*domain.T...
  method JoinBucket (line 81) | func (s *Space) JoinBucket(ctx context.Context, slug string, threadinfo ...
  method ToggleBucketBackup (line 95) | func (s *Space) ToggleBucketBackup(ctx context.Context, bucketSlug strin...
  method BucketBackupRestore (line 114) | func (s *Space) BucketBackupRestore(ctx context.Context, bucketSlug stri...
  method getBucketForRemoteFile (line 125) | func (s *Space) getBucketForRemoteFile(ctx context.Context, bucketName, ...
  method getBucketWithFallback (line 144) | func (s *Space) getBucketWithFallback(ctx context.Context, bucketName st...
  method listDirAtPath (line 165) | func (s *Space) listDirAtPath(
  method ListDir (line 263) | func (s *Space) ListDir(ctx context.Context, path string, bucketName str...
  method ListDirs (line 283) | func (s *Space) ListDirs(ctx context.Context, path string, bucketName st...
  method OpenFile (line 299) | func (s *Space) OpenFile(ctx context.Context, path, bucketName, dbID str...
  method TruncateData (line 345) | func (s *Space) TruncateData(ctx context.Context) error {
  method openFileOnFs (line 359) | func (s *Space) openFileOnFs(ctx context.Context, path string, b textile...
  method createTempFileForPath (line 397) | func (s *Space) createTempFileForPath(ctx context.Context, path string) ...
  method CreateFolder (line 404) | func (s *Space) CreateFolder(ctx context.Context, path string, bucketNam...
  method createFolder (line 422) | func (s *Space) createFolder(ctx context.Context, path string, b textile...
  method AddItems (line 434) | func (s *Space) AddItems(ctx context.Context, sourcePaths []string, targ...
  method AddItemWithReader (line 468) | func (s *Space) AddItemWithReader(
  function getTotals (line 496) | func getTotals(sourcePaths []string) (domain.AddItemsResponse, error) {
  method addItems (line 587) | func (s *Space) addItems(ctx context.Context, sourcePaths []string, targ...
  method handleAddItemFolder (line 614) | func (s *Space) handleAddItemFolder(ctx context.Context, sourcePath stri...
  method addFolderRec (line 641) | func (s *Space) addFolderRec(sourcePath string, targetPath string, ctx c...
  method addFile (line 664) | func (s *Space) addFile(ctx context.Context, sourcePath string, targetPa...
  method RemoveDirOrFile (line 704) | func (s *Space) RemoveDirOrFile(ctx context.Context, path, bucketName st...

FILE: core/space/services/services_identity.go
  type createIdentityRequest (line 16) | type createIdentityRequest struct
  function parseIdentity (line 21) | func parseIdentity(resp *http.Response) (*domain.Identity, error) {
  method CreateIdentity (line 52) | func (s *Space) CreateIdentity(ctx context.Context, username string) (*d...
  method GetIdentityByUsername (line 88) | func (s *Space) GetIdentityByUsername(ctx context.Context, username stri...

FILE: core/space/services/services_keypair.go
  method GenerateKeyPair (line 12) | func (s *Space) GenerateKeyPair(ctx context.Context, useForce bool) (str...
  method RestoreKeyPairFromMnemonic (line 27) | func (s *Space) RestoreKeyPairFromMnemonic(ctx context.Context, mnemonic...
  method GetPublicKey (line 41) | func (s *Space) GetPublicKey(ctx context.Context) (string, error) {
  method GetHubAuthToken (line 57) | func (s *Space) GetHubAuthToken(ctx context.Context) (string, error) {
  method GetMnemonic (line 66) | func (s *Space) GetMnemonic(ctx context.Context) (string, error) {
  method DeleteKeypair (line 79) | func (s *Space) DeleteKeypair(ctx context.Context) error {

FILE: core/space/services/services_notifs.go
  constant notificationsLastSeenAtStoreKey (line 10) | notificationsLastSeenAtStoreKey = "notificationsLastSeenAt"
  method GetNotifications (line 12) | func (s *Space) GetNotifications(ctx context.Context, seek string, limit...
  method SetNotificationsLastSeenAt (line 25) | func (s *Space) SetNotificationsLastSeenAt(timestamp int64) error {
  method GetNotificationsLastSeenAt (line 34) | func (s *Space) GetNotificationsLastSeenAt() (int64, error) {

FILE: core/space/services/services_search.go
  method SearchFiles (line 14) | func (s *Space) SearchFiles(ctx context.Context, query string) ([]domain...

FILE: core/space/services/services_sharing.go
  method GenerateFileSharingLink (line 30) | func (s *Space) GenerateFileSharingLink(
  method encryptBucketFile (line 74) | func (s *Space) encryptBucketFile(
  method uploadSharedFileToIpfs (line 118) | func (s *Space) uploadSharedFileToIpfs(
  method GenerateFilesSharingLink (line 158) | func (s *Space) GenerateFilesSharingLink(
  method OpenSharedFile (line 255) | func (s *Space) OpenSharedFile(ctx context.Context, hash, password, file...
  method ShareFilesViaPublicKey (line 308) | func (s *Space) ShareFilesViaPublicKey(ctx context.Context, paths []doma...
  method resolveFullPaths (line 377) | func (s *Space) resolveFullPaths(ctx context.Context, paths []domain.Ful...
  method UnshareFilesViaPublicKey (line 434) | func (s *Space) UnshareFilesViaPublicKey(ctx context.Context, paths []do...
  method sendPathsRevokedInvitation (line 453) | func (s *Space) sendPathsRevokedInvitation(
  method HandleSharedFilesInvitation (line 509) | func (s *Space) HandleSharedFilesInvitation(ctx context.Context, invitat...
  method AddRecentlySharedPublicKeys (line 571) | func (s *Space) AddRecentlySharedPublicKeys(ctx context.Context, pubkeys...
  method RecentlySharedPublicKeys (line 597) | func (s *Space) RecentlySharedPublicKeys(ctx context.Context) ([]crypto....
  method GetSharedWithMeFiles (line 627) | func (s *Space) GetSharedWithMeFiles(ctx context.Context, seek string, l...
  method GetSharedByMeFiles (line 639) | func (s *Space) GetSharedByMeFiles(ctx context.Context, seek string, lim...

FILE: core/space/services/services_vault.go
  constant separator (line 15) | separator = "___"
  method CreateLocalKeysBackup (line 18) | func (s *Space) CreateLocalKeysBackup(ctx context.Context, path string) ...
  method RecoverKeysByLocalBackup (line 42) | func (s *Space) RecoverKeysByLocalBackup(ctx context.Context, path strin...
  method RecoverKeysByPassphrase (line 71) | func (s *Space) RecoverKeysByPassphrase(ctx context.Context, uuid string...
  method BackupKeysByPassphrase (line 105) | func (s *Space) BackupKeysByPassphrase(ctx context.Context, uuid string,...
  method TestPassphrase (line 142) | func (s *Space) TestPassphrase(ctx context.Context, uuid string, pass st...

FILE: core/space/services/sharing_utils.go
  function generateFilesSharingZip (line 13) | func generateFilesSharingZip() string {
  function extractInvitation (line 18) | func extractInvitation(notification *domain.Notification) (domain.Invita...
  function decodePublicKey (line 28) | func decodePublicKey(err error, pkString string) (crypto.PubKey, error) {

FILE: core/space/space.go
  type Service (line 23) | type Service interface
  type serviceOptions (line 71) | type serviceOptions struct
  type ServiceOption (line 78) | type ServiceOption
  function NewService (line 80) | func NewService(
  function WithEnv (line 106) | func WithEnv(env env.SpaceEnv) ServiceOption {

FILE: core/space/space_test.go
  type TearDown (line 55) | type TearDown
  type GetTestDir (line 57) | type GetTestDir
  function closeAndDelete (line 59) | func closeAndDelete(f *os.File) {
  type testDir (line 64) | type testDir struct
  function initTestService (line 69) | func initTestService(t *testing.T) (*services.Space, GetTestDir, TearDow...
  function TestNewService (line 131) | func TestNewService(t *testing.T) {
  function TestService_CreateBucket (line 138) | func TestService_CreateBucket(t *testing.T) {
  function TestService_ListDirs (line 175) | func TestService_ListDirs(t *testing.T) {
  function TestService_OpenFile (line 322) | func TestService_OpenFile(t *testing.T) {
  function TestService_AddItems_FilesOnly (line 394) | func TestService_AddItems_FilesOnly(t *testing.T) {
  function TestService_AddItems_Folder (line 448) | func TestService_AddItems_Folder(t *testing.T) {
  function TestService_AddItems_OnError (line 513) | func TestService_AddItems_OnError(t *testing.T) {
  function TestService_CreateIdentity (line 560) | func TestService_CreateIdentity(t *testing.T) {
  function TestService_CreateIdentity_OnError (line 598) | func TestService_CreateIdentity_OnError(t *testing.T) {
  function TestService_GetIdentityByUsername (line 636) | func TestService_GetIdentityByUsername(t *testing.T) {
  function TestService_GetIdentityByUsername_OnError (line 671) | func TestService_GetIdentityByUsername_OnError(t *testing.T) {
  function TestService_GetPublicKey (line 705) | func TestService_GetPublicKey(t *testing.T) {
  function TestService_BackupAndRestore (line 720) | func TestService_BackupAndRestore(t *testing.T) {
  function TestService_VaultBackup (line 750) | func TestService_VaultBackup(t *testing.T) {
  function TestService_VaultRestore (line 781) | func TestService_VaultRestore(t *testing.T) {
  function TestService_UnshareFilesViaPublicKey_Works (line 808) | func TestService_UnshareFilesViaPublicKey_Works(t *testing.T) {
  function TestService_UnshareFilesViaPublicKey_Fails_IFTextileIsNotInitialized (line 828) | func TestService_UnshareFilesViaPublicKey_Fails_IFTextileIsNotInitialize...
  function TestService_HandleSharedFilesInvitation_FailIfInvitationNotFound (line 843) | func TestService_HandleSharedFilesInvitation_FailIfInvitationNotFound(t ...
  function TestService_HandleSharedFilesInvitation_Accepts_Correctly (line 856) | func TestService_HandleSharedFilesInvitation_Accepts_Correctly(t *testin...
  function TestService_HandleSharedFilesInvitation_Rejects_Correctly (line 896) | func TestService_HandleSharedFilesInvitation_Rejects_Correctly(t *testin...
  function TestService_OpenSharedFile_ShouldFail_When_PasswordCannotBeFetched (line 936) | func TestService_OpenSharedFile_ShouldFail_When_PasswordCannotBeFetched(...
  function TestService_OpenSharedFile_Should_AddOpenedFileToSharedWithMeList (line 957) | func TestService_OpenSharedFile_Should_AddOpenedFileToSharedWithMeList(t...
  function encryptString (line 986) | func encryptString(content, password string) io.ReadCloser {

FILE: core/spacefs/fs.go
  type SpaceFS (line 13) | type SpaceFS struct
    method Root (line 28) | func (fs *SpaceFS) Root(ctx context.Context) (DirEntryOps, error) {
    method LookupPath (line 42) | func (fs *SpaceFS) LookupPath(ctx context.Context, path string) (DirEn...
    method CreateEntry (line 61) | func (fs *SpaceFS) CreateEntry(ctx context.Context, req CreateDirEntry...
    method RenameEntry (line 81) | func (fs *SpaceFS) RenameEntry(ctx context.Context, req RenameDirEntry...
    method DeleteEntry (line 86) | func (fs *SpaceFS) DeleteEntry(ctx context.Context, path string) error {
    method Open (line 91) | func (fs *SpaceFS) Open(ctx context.Context, path string, mode FileHan...
  function New (line 20) | func New(store fsds.FSDataSource) *SpaceFS {
  type SpaceDirectory (line 97) | type SpaceDirectory struct
    method Path (line 106) | func (dir *SpaceDirectory) Path() string {
    method Attribute (line 111) | func (dir *SpaceDirectory) Attribute(ctx context.Context) (DirEntryAtt...
    method ReadDir (line 116) | func (dir *SpaceDirectory) ReadDir(ctx context.Context) ([]DirEntryOps...
  type SpaceFile (line 141) | type SpaceFile struct
    method Path (line 149) | func (f *SpaceFile) Path() string {
    method Attribute (line 154) | func (f *SpaceFile) Attribute(ctx context.Context) (DirEntryAttribute,...
    method Open (line 170) | func (f *SpaceFile) Open(ctx context.Context, mode FileHandlerMode) (F...
    method Truncate (line 175) | func (f *SpaceFile) Truncate(ctx context.Context, size uint64) error {

FILE: core/spacefs/fs_test.go
  function TestSpaceFS_LookupPath (line 10) | func TestSpaceFS_LookupPath(t *testing.T) {

FILE: core/spacefs/interfaces.go
  type FileHandlerMode (line 9) | type FileHandlerMode
  constant ReadMode (line 12) | ReadMode = FileHandlerMode(0)
  constant WriteMode (line 13) | WriteMode
  type DirEntryAttribute (line 17) | type DirEntryAttribute interface
  type DirEntryOps (line 31) | type DirEntryOps interface
  type DirOps (line 40) | type DirOps interface
  type FileHandler (line 47) | type FileHandler interface
  type FileOps (line 54) | type FileOps interface
  type CreateDirEntry (line 60) | type CreateDirEntry struct
  type RenameDirEntry (line 65) | type RenameDirEntry struct
  type FSOps (line 71) | type FSOps interface

FILE: core/store/store.go
  constant DefaultRootDir (line 19) | DefaultRootDir = "~/.fleek-space"
  constant BadgerFileName (line 20) | BadgerFileName = "db"
  type store (line 22) | type store struct
    method Open (line 70) | func (store *store) Open() error {
    method IsOpen (line 101) | func (store store) IsOpen() bool {
    method Close (line 105) | func (store *store) Close() error {
    method hotInit (line 121) | func (store *store) hotInit() {
    method getDb (line 144) | func (store *store) getDb() (*badger.DB, error) {
    method Set (line 153) | func (store *store) Set(key []byte, value []byte) error {
    method Remove (line 174) | func (store *store) Remove(key []byte) error {
    method SetString (line 193) | func (store *store) SetString(key string, value string) error {
    method Get (line 198) | func (store *store) Get(key []byte) ([]byte, error) {
    method KeysWithPrefix (line 235) | func (store store) KeysWithPrefix(prefix string) ([]string, error) {
    method Shutdown (line 259) | func (store store) Shutdown() error {
    method DropAll (line 263) | func (store store) DropAll() error {
  type Store (line 30) | type Store interface
  type storeOptions (line 42) | type storeOptions struct
  type Option (line 52) | type Option
  function New (line 54) | func New(opts ...Option) *store {
  function WithPath (line 136) | func WithPath(path string) Option {

FILE: core/sync/fs.go
  method OnCreate (line 14) | func (h *watcherHandler) OnCreate(ctx context.Context, path string, file...
  method OnRemove (line 96) | func (h *watcherHandler) OnRemove(ctx context.Context, path string, file...
  method OnWrite (line 131) | func (h *watcherHandler) OnWrite(ctx context.Context, path string, fileI...
  method OnRename (line 178) | func (h *watcherHandler) OnRename(ctx context.Context, path string, file...
  method OnMove (line 189) | func (h *watcherHandler) OnMove(ctx context.Context, path string, fileIn...

FILE: core/sync/notifier_default.go
  type defaultNotifier (line 7) | type defaultNotifier struct
    method SendFileEvent (line 9) | func (d defaultNotifier) SendFileEvent(event events.FileEvent) {
    method SendTextileEvent (line 13) | func (d defaultNotifier) SendTextileEvent(event events.TextileEvent) {

FILE: core/sync/sync.go
  constant OpenFilesKeyPrefix (line 25) | OpenFilesKeyPrefix        = "openFiles#"
  constant ReverseOpenFilesKeyPrefix (line 26) | ReverseOpenFilesKeyPrefix = "reverseOpenFiles#"
  type GrpcNotifier (line 29) | type GrpcNotifier interface
  type BucketSynchronizer (line 34) | type BucketSynchronizer interface
  type TextileNotifier (line 43) | type TextileNotifier interface
  type watcherHandler (line 48) | type watcherHandler struct
  type textileHandler (line 54) | type textileHandler struct
  type bucketSynchronizer (line 59) | type bucketSynchronizer struct
    method Start (line 89) | func (bs *bucketSynchronizer) Start(ctx context.Context) error {
    method WaitForReady (line 139) | func (bs *bucketSynchronizer) WaitForReady() chan bool {
    method Shutdown (line 143) | func (bs *bucketSynchronizer) Shutdown() error {
    method RegisterNotifier (line 153) | func (bs *bucketSynchronizer) RegisterNotifier(notifier GrpcNotifier) {
    method AddFileWatch (line 159) | func (bs *bucketSynchronizer) AddFileWatch(addFileInfo domain.AddWatch...
    method GetOpenFilePath (line 184) | func (bs *bucketSynchronizer) GetOpenFilePath(bucketSlug, bucketPath, ...
    method getOpenFileBucketSlugAndPath (line 208) | func (bs *bucketSynchronizer) getOpenFileBucketSlugAndPath(localPath s...
    method addFileInfoToStore (line 223) | func (bs *bucketSynchronizer) addFileInfoToStore(addFileInfo domain.Ad...
    method removeFileInfo (line 239) | func (bs *bucketSynchronizer) removeFileInfo(addFileInfo domain.AddWat...
    method getOpenFileInfo (line 251) | func (bs *bucketSynchronizer) getOpenFileInfo(key string) (domain.AddW...
  function New (line 70) | func New(
  function getOpenFileKey (line 200) | func getOpenFileKey(localPath string) string {
  function getOpenFileReverseKey (line 204) | func getOpenFileReverseKey(bucketSlug, bucketPath, dbID, cid string) str...

FILE: core/sync/textile.go
  method OnCreate (line 13) | func (h *textileHandler) OnCreate(bucketData *bucket.BucketData, listenE...
  method OnRemove (line 23) | func (h *textileHandler) OnRemove(bucketData *bucket.BucketData, listenE...
  method OnSave (line 33) | func (h *textileHandler) OnSave(bucketData *bucket.BucketData, listenEve...

FILE: core/sync/textile_test.go
  function TestTextileHandler_OnCreate (line 13) | func TestTextileHandler_OnCreate(t *testing.T) {
  function TestTextileHandler_OnRemove (line 38) | func TestTextileHandler_OnRemove(t *testing.T) {
  function TestTextileHandler_OnSave (line 63) | func TestTextileHandler_OnSave(t *testing.T) {

FILE: core/textile/account.go
  method DeleteAccount (line 9) | func (tc *textileClient) DeleteAccount(ctx context.Context) error {

FILE: core/textile/buckd.go
  type TextileBuckd (line 21) | type TextileBuckd struct
    method Start (line 35) | func (tb *TextileBuckd) Start(ctx context.Context) error {
    method WaitForReady (line 94) | func (tb *TextileBuckd) WaitForReady() chan bool {
    method Stop (line 98) | func (tb *TextileBuckd) Stop() error {
    method Shutdown (line 107) | func (tb *TextileBuckd) Shutdown() error {
  function NewBuckd (line 28) | func NewBuckd(cfg config.Config) *TextileBuckd {

FILE: core/textile/bucket/bucket.go
  type BucketData (line 15) | type BucketData struct
  type DirEntries (line 25) | type DirEntries
  type BucketsClient (line 27) | type BucketsClient interface
  type BucketInterface (line 38) | type BucketInterface interface
  type Notifier (line 88) | type Notifier interface
  type Bucket (line 95) | type Bucket struct
    method Slug (line 103) | func (b *Bucket) Slug() string {
    method Key (line 122) | func (b *Bucket) Key() string {
    method GetData (line 126) | func (b *Bucket) GetData() BucketData {
    method GetContext (line 137) | func (b *Bucket) GetContext(ctx context.Context) (context.Context, *th...
    method GetClient (line 141) | func (b *Bucket) GetClient() BucketsClient {
    method GetThreadID (line 145) | func (b *Bucket) GetThreadID(ctx context.Context) (*thread.ID, error) {
    method AttachNotifier (line 154) | func (b *Bucket) AttachNotifier(n Notifier) {
  type GetBucketContextFn (line 107) | type GetBucketContextFn
  function New (line 109) | func New(

FILE: core/textile/bucket/bucket_dir.go
  method DirExists (line 17) | func (b *Bucket) DirExists(ctx context.Context, path string) (bool, erro...
  method CreateDirectory (line 42) | func (b *Bucket) CreateDirectory(ctx context.Context, path string) (resu...
  method ListDirectory (line 56) | func (b *Bucket) ListDirectory(ctx context.Context, path string) (*DirEn...
  method DeleteDirOrFile (line 73) | func (b *Bucket) DeleteDirOrFile(ctx context.Context, path string) (path...
  method ItemsCount (line 86) | func (b *Bucket) ItemsCount(ctx context.Context, path string, withRecurs...
  method Each (line 120) | func (b *Bucket) Each(ctx context.Context, path string, iterator EachFun...

FILE: core/textile/bucket/bucket_file.go
  method FileExists (line 15) | func (b *Bucket) FileExists(ctx context.Context, pth string) (bool, erro...
  method UpdatedAt (line 46) | func (b *Bucket) UpdatedAt(ctx context.Context, pth string) (int64, erro...
  method UploadFile (line 63) | func (b *Bucket) UploadFile(
  method DownloadFile (line 91) | func (b *Bucket) DownloadFile(ctx context.Context, path string, reader i...
  method GetFile (line 111) | func (b *Bucket) GetFile(ctx context.Context, path string, w io.Writer) ...

FILE: core/textile/bucket/crypto/crypto.go
  function parseKeys (line 12) | func parseKeys(key []byte) (aesKey, iv, hmacKey []byte, err error) {
  function EncryptPathItems (line 26) | func EncryptPathItems(key []byte, path string, plainReader io.Reader) (s...
  function DecryptPathItems (line 86) | func DecryptPathItems(key []byte, path string, encryptedReader io.Reader...
  function readBufferString (line 144) | func readBufferString(buf io.Reader) (string, error) {
  function readAsBase64Strings (line 154) | func readAsBase64Strings(buf io.Reader) (string, error) {
  function bytesFromBase64Strings (line 164) | func bytesFromBase64Strings(data string) ([]byte, error) {

FILE: core/textile/bucket/crypto/crypto_test.go
  function Test_EncryptPathItems_Fails_For_InvalidKeys (line 14) | func Test_EncryptPathItems_Fails_For_InvalidKeys(t *testing.T) {
  function Test_DecryptPathItems_Fails_For_InvalidKeys (line 24) | func Test_DecryptPathItems_Fails_For_InvalidKeys(t *testing.T) {
  function Test_EncryptPathItems_Works_With_DecryptPathItems (line 34) | func Test_EncryptPathItems_Works_With_DecryptPathItems(t *testing.T) {
  function Test_EncryptPathItems_And_DecryptPathItems_Work_With_TopLevel_Files (line 54) | func Test_EncryptPathItems_And_DecryptPathItems_Work_With_TopLevel_Files...

FILE: core/textile/bucket/crypto/decrypter.go
  constant _16KB (line 15) | _16KB = 16 * 1024
  function NewDecryptReader (line 21) | func NewDecryptReader(r io.Reader, aesKey, iv, hmacKey []byte) (io.ReadC...
  function newDecryptReader (line 25) | func newDecryptReader(r io.Reader, aesKey []byte, iv []byte, hmacKey []b...
  type decryptReader (line 85) | type decryptReader struct
    method Read (line 91) | func (d *decryptReader) Read(dst []byte) (int, error) {
    method Close (line 96) | func (d *decryptReader) Close() error {

FILE: core/textile/bucket/crypto/encrypter.go
  constant aesKeySize (line 15) | aesKeySize  = 32
  constant ivKeySize (line 16) | ivKeySize   = 16
  constant hmacKeySize (line 17) | hmacKeySize = 32
  constant hmacSize (line 18) | hmacSize    = 64
  type hashReadWriter (line 25) | type hashReadWriter struct
    method Write (line 32) | func (h *hashReadWriter) Write(p []byte) (int, error) {
    method Read (line 40) | func (h *hashReadWriter) Read(p []byte) (int, error) {
  function NewEncryptReader (line 49) | func NewEncryptReader(r io.Reader, aesKey, iv, hmacKey []byte) (io.Reade...
  function newEncryptReader (line 65) | func newEncryptReader(r io.Reader, aesKey, iv, hmacKey []byte) (io.Reade...

FILE: core/textile/bucket_factory.go
  function NotFound (line 26) | func NotFound(slug string) error {
  type GetBucketForRemoteFileInput (line 30) | type GetBucketForRemoteFileInput struct
  method GetBucket (line 38) | func (tc *textileClient) GetBucket(ctx context.Context, slug string, rem...
  method getBucket (line 48) | func (tc *textileClient) getBucket(ctx context.Context, slug string, rem...
  method getBucketForMirror (line 79) | func (tc *textileClient) getBucketForMirror(ctx context.Context, slug st...
  method GetDefaultBucket (line 94) | func (tc *textileClient) GetDefaultBucket(ctx context.Context) (Bucket, ...
  method getBucketContext (line 98) | func (tc *textileClient) getBucketContext(ctx context.Context, sDbID str...
  method getOrCreateBucketContext (line 116) | func (tc *textileClient) getOrCreateBucketContext(ctx context.Context, b...
  method ListBuckets (line 163) | func (tc *textileClient) ListBuckets(ctx context.Context) ([]Bucket, err...
  method listBuckets (line 171) | func (tc *textileClient) listBuckets(ctx context.Context) ([]Bucket, err...
  method getBucketRootFromReceivedFile (line 193) | func (tc *textileClient) getBucketRootFromReceivedFile(ctx context.Conte...
  method getBucketRootForMirror (line 223) | func (tc *textileClient) getBucketRootForMirror(ctx context.Context, slu...
  method getBucketRootFromSlug (line 253) | func (tc *textileClient) getBucketRootFromSlug(ctx context.Context, slug...
  method CreateBucket (line 274) | func (tc *textileClient) CreateBucket(ctx context.Context, bucketSlug st...
  method createBucket (line 282) | func (tc *textileClient) createBucket(ctx context.Context, bucketSlug st...
  method ShareBucket (line 323) | func (tc *textileClient) ShareBucket(ctx context.Context, bucketSlug str...
  method joinBucketViaAddress (line 347) | func (tc *textileClient) joinBucketViaAddress(ctx context.Context, addre...
  method JoinBucket (line 398) | func (tc *textileClient) JoinBucket(ctx context.Context, slug string, ti...
  method ToggleBucketBackup (line 431) | func (tc *textileClient) ToggleBucketBackup(ctx context.Context, bucketS...
  method BucketBackupRestore (line 446) | func (tc *textileClient) BucketBackupRestore(ctx context.Context, bucket...
  method IsBucketBackup (line 452) | func (tc *textileClient) IsBucketBackup(ctx context.Context, bucketSlug ...
  function GetDefaultBucketSlug (line 461) | func GetDefaultBucketSlug() string {
  function GetDefaultMirrorBucketSlug (line 465) | func GetDefaultMirrorBucketSlug() string {
  method restoreBuckets (line 471) | func (tc *textileClient) restoreBuckets(ctx context.Context) error {
  function getBucketThreadManagedKey (line 555) | func getBucketThreadManagedKey(bucketSlug string) string {

FILE: core/textile/client.go
  constant healthcheckFailuresBeforeUnhealthy (line 42) | healthcheckFailuresBeforeUnhealthy = 3
  type textileClient (line 46) | type textileClient struct
    method WaitForReady (line 122) | func (tc *textileClient) WaitForReady() chan bool {
    method WaitForInitialized (line 126) | func (tc *textileClient) WaitForInitialized() chan bool {
    method WaitForHealthy (line 131) | func (tc *textileClient) WaitForHealthy() chan error {
    method IsInitialized (line 135) | func (tc *textileClient) IsInitialized() bool {
    method IsHealthy (line 140) | func (tc *textileClient) IsHealthy() bool {
    method requiresRunning (line 144) | func (tc *textileClient) requiresRunning() error {
    method getHubCtx (line 151) | func (tc *textileClient) getHubCtx(ctx context.Context) (context.Conte...
    method initializeSync (line 160) | func (tc *textileClient) initializeSync(ctx context.Context) {
    method start (line 195) | func (tc *textileClient) start(ctx context.Context, cfg config.Config)...
    method checkHubConnection (line 293) | func (tc *textileClient) checkHubConnection(ctx context.Context) error {
    method initialize (line 389) | func (tc *textileClient) initialize(ctx context.Context) error {
    method Start (line 449) | func (tc *textileClient) Start(ctx context.Context, cfg config.Config)...
    method DisableSync (line 456) | func (tc *textileClient) DisableSync() {
    method Shutdown (line 461) | func (tc *textileClient) Shutdown() error {
    method GetThreadsConnection (line 494) | func (tc *textileClient) GetThreadsConnection() (*threadsClient.Client...
    method IsRunning (line 502) | func (tc *textileClient) IsRunning() bool {
    method GetFailedHealthchecks (line 506) | func (tc *textileClient) GetFailedHealthchecks() int {
    method healthcheck (line 511) | func (tc *textileClient) healthcheck(ctx context.Context) {
    method RemoveKeys (line 563) | func (tc *textileClient) RemoveKeys(ctx context.Context) error {
    method GetModel (line 589) | func (tc *textileClient) GetModel() model.Model {
    method getSecureBucketsClient (line 604) | func (tc *textileClient) getSecureBucketsClient(baseClient *bucketsCli...
    method requiresHubConnection (line 609) | func (tc *textileClient) requiresHubConnection() error {
    method AttachSynchronizerNotifier (line 620) | func (tc *textileClient) AttachSynchronizerNotifier(notif synchronizer...
    method RestoreDB (line 625) | func (tc *textileClient) RestoreDB(ctx context.Context) error {
  function NewClient (line 81) | func NewClient(
  function getHubTargetOpts (line 332) | func getHubTargetOpts(host string) []grpc.DialOption {
  function CreateUserClient (line 348) | func CreateUserClient(host string) UsersClient {
  function getHubThreadsClient (line 358) | func getHubThreadsClient(host string) *threadsClient.Client {
  function getHubNetworkClient (line 368) | func getHubNetworkClient(host string) *nc.Client {
  function getHubBucketClient (line 379) | func getHubBucketClient(host string) *bucketsClient.Client {

FILE: core/textile/common/common.go
  function NewBucketEncryptionKeyContext (line 7) | func NewBucketEncryptionKeyContext(ctx context.Context, key []byte) cont...
  function BucketEncryptionKeyFromContext (line 15) | func BucketEncryptionKeyFromContext(ctx context.Context) ([]byte, bool) {

FILE: core/textile/event_handler.go
  type EventHandler (line 13) | type EventHandler interface
  type defaultListenerHandler (line 20) | type defaultListenerHandler struct
    method OnCreate (line 22) | func (h *defaultListenerHandler) OnCreate(bucketData *bucket.BucketDat...
    method OnRemove (line 26) | func (h *defaultListenerHandler) OnRemove(bucketData *bucket.BucketDat...
    method OnSave (line 30) | func (h *defaultListenerHandler) OnSave(bucketData *bucket.BucketData,...
  type restorerListenerHandler (line 34) | type restorerListenerHandler struct
    method OnCreate (line 48) | func (h *restorerListenerHandler) OnCreate(bucketData *bucket.BucketDa...
    method OnRemove (line 53) | func (h *restorerListenerHandler) OnRemove(bucketData *bucket.BucketDa...
    method OnSave (line 58) | func (h *restorerListenerHandler) OnSave(bucketData *bucket.BucketData...
  function newRestorerListenerHandler (line 40) | func newRestorerListenerHandler(synchronizer sync.Synchronizer, st store...

FILE: core/textile/hub/hub_auth.go
  type sentMessageData (line 23) | type sentMessageData struct
  type outMessage (line 28) | type outMessage struct
  type inMessageChallengeValue (line 33) | type inMessageChallengeValue struct
  type inMessageChallenge (line 38) | type inMessageChallenge struct
  type inMessageTokenValue (line 43) | type inMessageTokenValue struct
  type inMessageToken (line 51) | type inMessageToken struct
  type AuthTokens (line 56) | type AuthTokens struct
  type HubAuth (line 64) | type HubAuth interface
  type hub (line 70) | type hub struct
    method retrieveTokens (line 116) | func (h *hub) retrieveTokens() (*inMessageTokenValue, error) {
    method storeTokens (line 137) | func (h *hub) storeTokens(tokens *inMessageTokenValue) error {
    method ClearCache (line 151) | func (h *hub) ClearCache() error {
    method getTokensThroughChallenge (line 155) | func (h *hub) getTokensThroughChallenge(ctx context.Context) (*inMessa...
    method GetTokensWithCache (line 234) | func (h *hub) GetTokensWithCache(ctx context.Context) (*AuthTokens, er...
    method GetHubContext (line 265) | func (h *hub) GetHubContext(ctx context.Context) (context.Context, err...
  function New (line 77) | func New(st store.Store, kc keychain.Keychain, cfg config.Config) *hub {
  constant tokensStoreKey (line 86) | tokensStoreKey = "hubTokens"
  function isTokenExpired (line 88) | func isTokenExpired(t string) bool {

FILE: core/textile/hub/hub_auth_test.go
  function TestHubAuth_isTokenExpiredTrue (line 14) | func TestHubAuth_isTokenExpiredTrue(t *testing.T) {
  function TestHubAuth_isTokenExpiredFalse (line 26) | func TestHubAuth_isTokenExpiredFalse(t *testing.T) {

FILE: core/textile/listener.go
  method Listen (line 12) | func (tc *textileClient) Listen(ctx context.Context, dbID, threadName st...
  method addListener (line 26) | func (tc *textileClient) addListener(ctx context.Context, bucketSlug str...
  method DeleteListeners (line 46) | func (tc *textileClient) DeleteListeners(ctx context.Context) {
  method initializeListeners (line 52) | func (tc *textileClient) initializeListeners(ctx context.Context) error {
  method closeListeners (line 71) | func (tc *textileClient) closeListeners() {
  type listener (line 79) | type listener struct
    method Listen (line 97) | func (l *listener) Listen(ctx context.Context) error {
    method Close (line 149) | func (l *listener) Close() {
  function NewListener (line 87) | func NewListener(client Client, bucketSlug string, handlers []EventHandl...

FILE: core/textile/mailbox.go
  type GrpcMailboxNotifier (line 22) | type GrpcMailboxNotifier interface
  constant mailboxSetupFlagStoreKey (line 26) | mailboxSetupFlagStoreKey = "mailboxSetupFlag"
  type UsersClient (line 28) | type UsersClient interface
  type Mailbox (line 34) | type Mailbox interface
  method parseMessage (line 41) | func (tc *textileClient) parseMessage(ctx context.Context, msgs []client...
  method SendMessage (line 148) | func (tc *textileClient) SendMessage(ctx context.Context, recipient cryp...
  method GetMailAsNotifications (line 166) | func (tc *textileClient) GetMailAsNotifications(ctx context.Context, see...
  type handleMessage (line 191) | type handleMessage
  method listenForMessages (line 193) | func (tc *textileClient) listenForMessages(ctx context.Context) error {
  method AttachMailboxNotifier (line 253) | func (tc *textileClient) AttachMailboxNotifier(notif GrpcMailboxNotifier) {
  method createMailBox (line 257) | func (tc *textileClient) createMailBox(ctx context.Context, maillib *mai...
  method getMailboxPath (line 279) | func (tc *textileClient) getMailboxPath() string {
  method setupOrCreateMailBox (line 289) | func (tc *textileClient) setupOrCreateMailBox(ctx context.Context) (*mai...
  method clearLocalMailbox (line 314) | func (tc *textileClient) clearLocalMailbox() error {

FILE: core/textile/mailbox_test.go
  type TearDown (line 24) | type TearDown
  function initTestMailbox (line 26) | func initTestMailbox(t *testing.T) (tc.Client, TearDown) {
  function TestSendMessage (line 53) | func TestSendMessage(t *testing.T) {
  function TestSendMessageFailureOnHub (line 107) | func TestSendMessageFailureOnHub(t *testing.T) {

FILE: core/textile/mirror.go
  constant mirrorThreadKeyName (line 10) | mirrorThreadKeyName = "mirrorV1"
  method IsMirrorFile (line 12) | func (tc *textileClient) IsMirrorFile(ctx context.Context, path, bucketS...
  method isMirrorBackupFile (line 24) | func (tc *textileClient) isMirrorBackupFile(ctx context.Context, path, b...

FILE: core/textile/model/buckets.go
  type BucketSchema (line 16) | type BucketSchema struct
  constant bucketModelName (line 25) | bucketModelName = "BucketMetadata"
  constant BucketEncryptionKeyLength (line 28) | BucketEncryptionKeyLength = 32 + 16 + 32
  method CreateBucket (line 32) | func (m *model) CreateBucket(ctx context.Context, bucketSlug, dbID strin...
  method UpsertBucket (line 88) | func (m *model) UpsertBucket(ctx context.Context, bucketSlug, dbID strin...
  method BucketBackupToggle (line 104) | func (m *model) BucketBackupToggle(ctx context.Context, bucketSlug strin...
  method FindBucket (line 127) | func (m *model) FindBucket(ctx context.Context, bucketSlug string) (*Buc...
  method ListBuckets (line 150) | func (m *model) ListBuckets(ctx context.Context) ([]*BucketSchema, error) {
  method initBucketModel (line 164) | func (m *model) initBucketModel(ctx context.Context) (context.Context, *...
  function GetBucketCollectionConfig (line 175) | func GetBucketCollectionConfig() db.CollectionConfig {

FILE: core/textile/model/mirror_file.go
  type MirrorFileSchema (line 18) | type MirrorFileSchema struct
  type MirrorBucketSchema (line 29) | type MirrorBucketSchema struct
  constant mirrorFileModelName (line 36) | mirrorFileModelName = "MirrorFile"
  method CreateMirrorBucket (line 41) | func (m *model) CreateMirrorBucket(ctx context.Context, bucketSlug strin...
  method FindMirrorFileByPaths (line 67) | func (m *model) FindMirrorFileByPaths(ctx context.Context, paths []strin...
  method FindMirrorFileByPathAndBucketSlug (line 105) | func (m *model) FindMirrorFileByPathAndBucketSlug(ctx context.Context, p...
  method CreateMirrorFile (line 130) | func (m *model) CreateMirrorFile(ctx context.Context, mirrorFile *domain...
  method UpdateMirrorFile (line 174) | func (m *model) UpdateMirrorFile(ctx context.Context, mirrorFile *Mirror...
  method initMirrorFileModel (line 200) | func (m *model) initMirrorFileModel(ctx context.Context) (context.Contex...
  function GetMirrorFileCollectionConfig (line 217) | func GetMirrorFileCollectionConfig() db.CollectionConfig {

FILE: core/textile/model/model.go
  constant metaThreadName (line 20) | metaThreadName = "metathreadV1"
  type model (line 22) | type model struct
    method findOrCreateMetaThreadID (line 115) | func (m *model) findOrCreateMetaThreadID(ctx context.Context) (*thread...
    method getMetaThreadContext (line 132) | func (m *model) getMetaThreadContext(ctx context.Context) (context.Con...
  type Model (line 35) | type Model interface
  function New (line 89) | func New(
  function GetAllCollectionConfigs (line 148) | func GetAllCollectionConfigs() []db.CollectionConfig {

FILE: core/textile/model/received_file.go
  type ReceivedFileViaPublicLinkSchema (line 17) | type ReceivedFileViaPublicLinkSchema struct
  type ReceivedFileViaInvitationSchema (line 24) | type ReceivedFileViaInvitationSchema struct
  type ReceivedFileSchema (line 36) | type ReceivedFileSchema struct
    method IsPublicLinkReceived (line 44) | func (r ReceivedFileSchema) IsPublicLinkReceived() bool {
  constant receivedFileModelName (line 48) | receivedFileModelName = "ReceivedFile"
  method CreateReceivedFileViaInvitation (line 53) | func (m *model) CreateReceivedFileViaInvitation(
  method CreateReceivedFileViaPublicLink (line 85) | func (m *model) CreateReceivedFileViaPublicLink(
  method createReceivedFile (line 120) | func (m *model) createReceivedFile(ctx context.Context, instance *Receiv...
  method FindReceivedFilesByIds (line 143) | func (m *model) FindReceivedFilesByIds(ctx context.Context, ids []string...
  method FindReceivedFile (line 169) | func (m *model) FindReceivedFile(ctx context.Context, remoteDbID, bucket...
  method FindPublicLinkReceivedFile (line 192) | func (m *model) FindPublicLinkReceivedFile(ctx context.Context, ipfsHash...
  method ListReceivedFiles (line 224) | func (m *model) ListReceivedFiles(ctx context.Context, accepted bool, se...
  method DeleteReceivedFiles (line 249) | func (m *model) DeleteReceivedFiles(ctx context.Context, paths []domain....
  method ListReceivedPublicFiles (line 291) | func (m *model) ListReceivedPublicFiles(
  method initReceivedFileModel (line 316) | func (m *model) initReceivedFileModel(ctx context.Context) (context.Cont...
  function GetReceivedFileCollectionConfig (line 329) | func GetReceivedFileCollectionConfig() db.CollectionConfig {

FILE: core/textile/model/received_file_test.go
  function TestReceivedFileSchema_IsPublicLinkReceived_ShouldBeFalse_For_InvitationId (line 9) | func TestReceivedFileSchema_IsPublicLinkReceived_ShouldBeFalse_For_Invit...

FILE: core/textile/model/search.go
  type SearchItemType (line 13) | type SearchItemType
  constant FileItem (line 16) | FileItem                 SearchItemType = "FILE"
  constant DirectoryItem (line 17) | DirectoryItem            SearchItemType = "DIRECTORY"
  constant DefaultSearchResultLimit (line 18) | DefaultSearchResultLimit int            = 20
  type SearchIndexRecord (line 21) | type SearchIndexRecord
  method InitSearchIndexCollection (line 23) | func (m *model) InitSearchIndexCollection(ctx context.Context) error {
  method UpdateSearchIndexRecord (line 28) | func (m *model) UpdateSearchIndexRecord(
  method QuerySearchIndex (line 49) | func (m *model) QuerySearchIndex(ctx context.Context, query string) ([]*...
  method DeleteSearchIndexRecord (line 64) | func (m *model) DeleteSearchIndexRecord(ctx context.Context, name, path,...

FILE: core/textile/model/sent_file.go
  type SentFileViaInvitationSchema (line 18) | type SentFileViaInvitationSchema struct
  type SentFileSchema (line 28) | type SentFileSchema struct
    method ReceivedFileSchema (line 144) | func (sf *SentFileSchema) ReceivedFileSchema() *ReceivedFileSchema {
  constant sentFileModelName (line 34) | sentFileModelName = "SentFile"
  method CreateSentFileViaInvitation (line 39) | func (m *model) CreateSentFileViaInvitation(
  method createSentFile (line 68) | func (m *model) createSentFile(ctx context.Context, instance *SentFileSc...
  method FindSentFile (line 91) | func (m *model) FindSentFile(ctx context.Context, remoteDbID, bucket, pa...
  method ListSentFiles (line 118) | func (m *model) ListSentFiles(ctx context.Context, seek string, limit in...
  method initSentFileModel (line 159) | func (m *model) initSentFileModel(ctx context.Context) (context.Context,...
  function GetSentFileCollectionConfig (line 172) | func GetSentFileCollectionConfig() db.CollectionConfig {

FILE: core/textile/model/shared_public_key.go
  type SharedPublicKeySchema (line 16) | type SharedPublicKeySchema struct
  constant sharedPublicKeyModel (line 24) | sharedPublicKeyModel = "SharedPublicKey"
  method CreateSharedPublicKey (line 29) | func (m *model) CreateSharedPublicKey(ctx context.Context, pubKey string...
  method FindSharedPublicKey (line 71) | func (m *model) FindSharedPublicKey(ctx context.Context, pubKey string) ...
  method initSharedPublicKey (line 94) | func (m *model) initSharedPublicKey(ctx context.Context) (context.Contex...
  constant listSharedPublicKeysLimit (line 116) | listSharedPublicKeysLimit = 128
  method ListSharedPublicKeys (line 118) | func (m *model) ListSharedPublicKeys(ctx context.Context) ([]*SharedPubl...
  function GetSharedPublicKeyCollectionConfig (line 137) | func GetSharedPublicKeyCollectionConfig() db.CollectionConfig {

FILE: core/textile/notifier/notifier.go
  type Notifier (line 8) | type Notifier struct
    method OnUploadFile (line 18) | func (n *Notifier) OnUploadFile(bucketSlug string, bucketPath string, ...
  function New (line 12) | func New(s sync.Synchronizer) *Notifier {

FILE: core/textile/public.go
  method GetPublicShareBucket (line 27) | func (tc *textileClient) GetPublicShareBucket(ctx context.Context) (Buck...
  method createDefaultPublicBucket (line 38) | func (tc *textileClient) createDefaultPublicBucket(ctx context.Context) ...
  method getOrCreatePublicBucket (line 58) | func (tc *textileClient) getOrCreatePublicBucket(ctx context.Context, bu...
  method getPublicShareBucketContext (line 97) | func (tc *textileClient) getPublicShareBucketContext(ctx context.Context...
  method createPublicBucket (line 111) | func (tc *textileClient) createPublicBucket(ctx context.Context, dbId th...
  constant publicShareThreadStoreKey (line 127) | publicShareThreadStoreKey = "publicSharedThreadKey"
  method getPublicShareThread (line 130) | func (tc *textileClient) getPublicShareThread(ctx context.Context) (thre...
  method DownloadPublicItem (line 159) | func (tc *textileClient) DownloadPublicItem(ctx context.Context, cid cid...

FILE: core/textile/search.go
  method initSearchIndex (line 5) | func (tc *textileClient) initSearchIndex(ctx context.Context) error {

FILE: core/textile/secure_bucket_client.go
  type SecureBucketClient (line 48) | type SecureBucketClient struct
    method PushPath (line 78) | func (s *SecureBucketClient) PushPath(ctx context.Context, key, path s...
    method PushPathAccessRoles (line 97) | func (s *SecureBucketClient) PushPathAccessRoles(ctx context.Context, ...
    method PullPathAccessRoles (line 111) | func (s *SecureBucketClient) PullPathAccessRoles(ctx context.Context, ...
    method PullPath (line 125) | func (s *SecureBucketClient) PullPath(ctx context.Context, key, path s...
    method overwriteDecryptedItem (line 165) | func (s *SecureBucketClient) overwriteDecryptedItem(ctx context.Contex...
    method ListIpfsPath (line 196) | func (s *SecureBucketClient) ListIpfsPath(ctx context.Context, pth pat...
    method ListPath (line 200) | func (s *SecureBucketClient) ListPath(ctx context.Context, key, path s...
    method RemovePath (line 236) | func (s *SecureBucketClient) RemovePath(ctx context.Context, key, path...
    method getBucketEncryptionKey (line 251) | func (s *SecureBucketClient) getBucketEncryptionKey(ctx context.Contex...
    method encryptPathData (line 258) | func (s *SecureBucketClient) encryptPathData(
    method decryptPathData (line 267) | func (s *SecureBucketClient) decryptPathData(
    method racePullFile (line 295) | func (s *SecureBucketClient) racePullFile(ctx context.Context, key, en...
    method pullFileFromClient (line 464) | func (s *SecureBucketClient) pullFileFromClient(ctx context.Context, k...
    method pullFileFromLocal (line 479) | func (s *SecureBucketClient) pullFileFromLocal(ctx context.Context, ke...
    method pullFileFromDHT (line 516) | func (s *SecureBucketClient) pullFileFromDHT(ctx context.Context, key,...
  function NewSecureBucketsClient (line 58) | func NewSecureBucketsClient(
  function cleanBucketPath (line 279) | func cleanBucketPath(path string) string {
  type pathPullingFn (line 283) | type pathPullingFn
  type pullSuccessResponse (line 285) | type pullSuccessResponse struct
  function getTempFileName (line 290) | func getTempFileName(encPath string) string {
  constant FileCachePrefix (line 458) | FileCachePrefix = "file_cache"
  function getFileCacheKey (line 460) | func getFileCacheKey(encCid string) []byte {
  constant cacheBucketThreadName (line 558) | cacheBucketThreadName = "cache_bucket"

FILE: core/textile/sharing.go
  method ManageShareFilesViaPublicKey (line 24) | func (tc *textileClient) ManageShareFilesViaPublicKey(
  method AcceptSharedFilesInvitation (line 77) | func (tc *textileClient) AcceptSharedFilesInvitation(
  method RejectSharedFilesInvitation (line 98) | func (tc *textileClient) RejectSharedFilesInvitation(
  method createReceivedFiles (line 119) | func (tc *textileClient) createReceivedFiles(
  method AcceptSharedFileLink (line 154) | func (tc *textileClient) AcceptSharedFileLink(
  method GetPublicReceivedFile (line 166) | func (tc *textileClient) GetPublicReceivedFile(
  method GetReceivedFiles (line 188) | func (tc *textileClient) GetReceivedFiles(
  method GetSentFiles (line 224) | func (tc *textileClient) GetSentFiles(
  method buildPublicLinkSharedDirEntry (line 255) | func (tc *textileClient) buildPublicLinkSharedDirEntry(
  method buildInvitationSharedDirEntry (line 283) | func (tc *textileClient) buildInvitationSharedDirEntry(
  method GetPathAccessRoles (line 375) | func (tc *textileClient) GetPathAccessRoles(ctx context.Context, b Bucke...
  method isSharedFile (line 431) | func (tc *textileClient) isSharedFile(ctx context.Context, bucket Bucket...

FILE: core/textile/sync/mirror.go
  constant mirrorThreadKeyName (line 19) | mirrorThreadKeyName = "mirrorV1"
  method setMirrorFileBackup (line 21) | func (s *synchronizer) setMirrorFileBackup(ctx context.Context, path, bu...
  method unsetMirrorFileBackup (line 55) | func (s *synchronizer) unsetMirrorFileBackup(ctx context.Context, path, ...
  method addCurrentUserAsFileOwner (line 76) | func (s *synchronizer) addCurrentUserAsFileOwner(ctx context.Context, bu...
  method createMirrorBucket (line 105) | func (s *synchronizer) createMirrorBucket(ctx context.Context, slug stri...
  method createMirrorThread (line 151) | func (s *synchronizer) createMirrorThread(ctx context.Context, slug stri...

FILE: core/textile/sync/pinning.go
  method uploadFileToRemote (line 12) | func (s *synchronizer) uploadFileToRemote(ctx context.Context, bucket, p...
  method uploadFileToBucket (line 26) | func (s *synchronizer) uploadFileToBucket(ctx context.Context, sourceBuc...
  method downloadFile (line 63) | func (s *synchronizer) downloadFile(ctx context.Context, sourceBucket, t...
  method uploadAllFilesInPath (line 101) | func (s *synchronizer) uploadAllFilesInPath(ctx context.Context, bucket,...
  method deleteFileFromRemote (line 133) | func (s *synchronizer) deleteFileFromRemote(ctx context.Context, bucket,...
  method deleteAllFilesInPath (line 147) | func (s *synchronizer) deleteAllFilesInPath(ctx context.Context, bucket,...

FILE: core/textile/sync/queue.go
  constant QueueStoreKey (line 9) | QueueStoreKey = "TextileSyncTaskQueue"
  type marshalledQueue (line 11) | type marshalledQueue struct
  method enqueueTask (line 16) | func (s *synchronizer) enqueueTask(task *Task, queue *list.List) {
  method enqueueTaskAtFront (line 23) | func (s *synchronizer) enqueueTaskAtFront(task *Task, queue *list.List) {
  method dequeueTask (line 30) | func (s *synchronizer) dequeueTask(queue *list.List) *Task {
  method storeQueue (line 40) | func (s *synchronizer) storeQueue() error {
  method restoreQueue (line 77) | func (s *synchronizer) restoreQueue() error {
  method isTaskEnqueued (line 107) | func (s *synchronizer) isTaskEnqueued(task *Task) bool {
  method queueString (line 121) | func (s *synchronizer) queueString(queue *list.List) string {

FILE: core/textile/sync/restore.go
  method newerBucketPath (line 14) | func (s *synchronizer) newerBucketPath(ctx context.Context, srcBucket, t...
  method restoreBucket (line 34) | func (s *synchronizer) restoreBucket(ctx context.Context, bucketSlug str...

FILE: core/textile/sync/sync.go
  type EventNotifier (line 9) | type EventNotifier interface
  type Synchronizer (line 13) | type Synchronizer interface

FILE: core/textile/sync/sync_test.go
  function initSync (line 32) | func initSync(t *testing.T) sync.Synchronizer {
  function TestSync_ProcessTask (line 65) | func TestSync_ProcessTask(t *testing.T) {
  function TestSync_Restore (line 91) | func TestSync_Restore(t *testing.T) {

FILE: core/textile/sync/synchronizer.go
  type GetMirrorBucketFn (line 25) | type GetMirrorBucketFn
  type GetBucketFn (line 26) | type GetBucketFn
  type GetBucketCtxFn (line 27) | type GetBucketCtxFn
  type AddBucketListenerFn (line 28) | type AddBucketListenerFn
  constant maxParallelTasks (line 30) | maxParallelTasks = 16
  type synchronizer (line 32) | type synchronizer struct
    method NotifyItemAdded (line 109) | func (s *synchronizer) NotifyItemAdded(bucket, path string) {
    method NotifyItemRemoved (line 117) | func (s *synchronizer) NotifyItemRemoved(bucket, path string) {
    method NotifyBucketCreated (line 124) | func (s *synchronizer) NotifyBucketCreated(bucket string, enckey []byt...
    method NotifyBucketBackupOn (line 130) | func (s *synchronizer) NotifyBucketBackupOn(bucket string) {
    method NotifyBucketBackupOff (line 138) | func (s *synchronizer) NotifyBucketBackupOff(bucket string) {
    method NotifyBucketRestore (line 145) | func (s *synchronizer) NotifyBucketRestore(bucket string) {
    method NotifyFileRestore (line 152) | func (s *synchronizer) NotifyFileRestore(bucket, path string) {
    method NotifyBucketStartup (line 159) | func (s *synchronizer) NotifyBucketStartup(bucket string) {
    method NotifyIndexItemAdded (line 166) | func (s *synchronizer) NotifyIndexItemAdded(bucket, path, dbId string) {
    method notifySyncNeeded (line 175) | func (s *synchronizer) notifySyncNeeded() {
    method Start (line 187) | func (s *synchronizer) Start(ctx context.Context) {
    method RestoreQueue (line 202) | func (s *synchronizer) RestoreQueue() error {
    method startSyncLoop (line 210) | func (s *synchronizer) startSyncLoop(ctx context.Context, queue *list....
    method Shutdown (line 243) | func (s *synchronizer) Shutdown() {
    method String (line 259) | func (s *synchronizer) String() string {
    method executeTask (line 272) | func (s *synchronizer) executeTask(ctx context.Context, t *Task) error {
    method sync (line 321) | func (s *synchronizer) sync(ctx context.Context, queue *list.List) err...
    method AttachNotifier (line 397) | func (s *synchronizer) AttachNotifier(notif EventNotifier) {
  function New (line 57) | func New(

FILE: core/textile/sync/task-executors.go
  function checkTaskType (line 21) | func checkTaskType(t *Task, tp taskType) error {
  method processAddItem (line 29) | func (s *synchronizer) processAddItem(ctx context.Context, task *Task) e...
  method processRemoveItem (line 72) | func (s *synchronizer) processRemoveItem(ctx context.Context, task *Task...
  method processPinFile (line 97) | func (s *synchronizer) processPinFile(ctx context.Context, task *Task) e...
  method processUnpinFile (line 132) | func (s *synchronizer) processUnpinFile(ctx context.Context, task *Task)...
  method processCreateBucket (line 145) | func (s *synchronizer) processCreateBucket(ctx context.Context, task *Ta...
  method processBucketBackupOn (line 171) | func (s *synchronizer) processBucketBackupOn(ctx context.Context, task *...
  method processBucketBackupOff (line 200) | func (s *synchronizer) processBucketBackupOff(ctx context.Context, task ...
  method processBucketRestoreTask (line 229) | func (s *synchronizer) processBucketRestoreTask(ctx context.Context, tas...
  method processRestoreFile (line 254) | func (s *synchronizer) processRestoreFile(ctx context.Context, task *Tas...
  method processAddIndexItemTask (line 304) | func (s *synchronizer) processAddIndexItemTask(ctx context.Context, task...
  method processRemoveIndexItemTask (line 379) | func (s *synchronizer) processRemoveIndexItemTask(ctx context.Context, t...

FILE: core/textile/sync/task.go
  type taskType (line 7) | type taskType
  constant addItemTask (line 10) | addItemTask         taskType = "ADD_ITEM"
  constant removeItemTask (line 11) | removeItemTask      taskType = "REMOVE_ITEM"
  constant createBucketTask (line 12) | createBucketTask    taskType = "CREATE_BUCKET"
  constant pinFileTask (line 13) | pinFileTask         taskType = "PIN_FILE"
  constant unpinFileTask (line 14) | unpinFileTask       taskType = "UNPIN_FILE"
  constant bucketBackupOnTask (line 15) | bucketBackupOnTask  taskType = "TOGGLE_BACKUP_ON"
  constant bucketBackupOffTask (line 16) | bucketBackupOffTask taskType = "TOGGLE_BACKUP_OFF"
  constant bucketRestoreTask (line 17) | bucketRestoreTask   taskType = "BUCKET_RESTORE"
  constant restoreFileTask (line 18) | restoreFileTask     taskType = "RESTORE_FILE"
  constant addIndexItemTask (line 19) | addIndexItemTask    taskType = "ADD_INDEX_ITEM"
  constant removeIndexItemTask (line 20) | removeIndexItemTask taskType = "REMOVE_INDEX_ITEM"
  type taskState (line 23) | type taskState
  constant taskQueued (line 26) | taskQueued    taskState = "QUEUED"
  constant taskPending (line 27) | taskPending   taskState = "PENDING"
  constant taskSucceeded (line 28) | taskSucceeded taskState = "SUCCESS"
  constant taskFailed (line 29) | taskFailed    taskState = "FAILED"
  constant taskDequeued (line 30) | taskDequeued  taskState = "DEQUEUED"
  type Task (line 33) | type Task struct
  function newTask (line 45) | func newTask(t taskType, args []string) *Task {

FILE: core/textile/sync/threads.go
  method replicateThreadToHub (line 13) | func (s *synchronizer) replicateThreadToHub(ctx context.Context, dbID *t...
  method dereplicateThreadFromHub (line 29) | func (s *synchronizer) dereplicateThreadFromHub(ctx context.Context, dbI...

FILE: core/textile/textile.go
  constant hubTarget (line 24) | hubTarget                       = "127.0.0.1:3006"
  constant threadsTarget (line 25) | threadsTarget                   = "127.0.0.1:3006"
  constant defaultPersonalBucketSlug (line 26) | defaultPersonalBucketSlug       = "personal"
  constant defaultCacheBucketSlug (line 27) | defaultCacheBucketSlug          = "personal_cache"
  constant defaultPersonalMirrorBucketSlug (line 28) | defaultPersonalMirrorBucketSlug = "personal_mirror"
  constant defaultPublicShareBucketSlug (line 29) | defaultPublicShareBucketSlug    = "personal_public"
  type BucketRoot (line 32) | type BucketRoot
  type Bucket (line 34) | type Bucket interface
  type Client (line 38) | type Client interface
  type Buckd (line 88) | type Buckd interface
  type Listener (line 93) | type Listener interface

FILE: core/textile/utils/utils.go
  function CastDbIDToString (line 33) | func CastDbIDToString(dbID thread.ID) string {
  function ParseDbIDFromString (line 38) | func ParseDbIDFromString(dbID string) (*thread.ID, error) {
  type DeterministicThreadVariant (line 51) | type DeterministicThreadVariant
  constant MetathreadThreadVariant (line 54) | MetathreadThreadVariant DeterministicThreadVariant = "metathread"
  constant MirrorBucketVariant (line 55) | MirrorBucketVariant     DeterministicThreadVariant = "mirror_bucket"
  function MirrorBucketVariantGen (line 58) | func MirrorBucketVariantGen(mirrorBucketSlug string) DeterministicThread...
  function NewDeterministicThreadID (line 62) | func NewDeterministicThreadID(kc keychain.Keychain, threadVariant Determ...
  function getThreadName (line 97) | func getThreadName(userPubKey []byte, bucketSlug string) string {
  function GetThreadContext (line 102) | func GetThreadContext(parentCtx context.Context, threadName string, dbID...
  function RandBytes (line 142) | func RandBytes(size int) ([]byte, error) {
  function IsMetaFileName (line 156) | func IsMetaFileName(pathOrName string) bool {
  constant threadIDStoreKey (line 162) | threadIDStoreKey = "thread_id"
  function getDeterministicthreadStoreKey (line 165) | func getDeterministicthreadStoreKey(kc keychain.Keychain, variant Determ...
  function FindOrCreateDeterministicThread (line 184) | func FindOrCreateDeterministicThread(
  function successfulThreadCreation (line 290) | func successfulThreadCreation(st store.Store, dbID *thread.ID, dbIDInByt...
  function MapDirEntryToFileInfo (line 299) | func MapDirEntryToFileInfo(entry bucketsproto.ListPathResponse, itemPath...

FILE: core/textile/utils/utils_test.go
  function initMocks (line 20) | func initMocks(t *testing.T) {
  function TestUtils_NewDeterministicThreadID (line 35) | func TestUtils_NewDeterministicThreadID(t *testing.T) {

FILE: core/util/address/address.go
  function DeriveAddress (line 12) | func DeriveAddress(pubKey crypto.PubKey) string {

FILE: core/util/paths.go
  function ResolvePath (line 12) | func ResolvePath(path string) (string, error) {
  function DirEntryExists (line 25) | func DirEntryExists(filename string) bool {

FILE: core/util/rlimit/rlimit_unix.go
  function SetRLimit (line 14) | func SetRLimit() {

FILE: core/util/rlimit/rlimit_windows.go
  function SetRLimit (line 4) | func SetRLimit() {

FILE: core/vault/vault.go
  type vault (line 20) | type vault struct
    method Store (line 78) | func (v *vault) Store(uuid string, passphrase string, backupType domai...
    method Retrieve (line 132) | func (v *vault) Retrieve(uuid string, passphrase string, backupType do...
    method computeVk (line 190) | func (v *vault) computeVk(uuid string, pass string, version VkVersion)...
    method computeVsk (line 200) | func (v *vault) computeVsk(vk []byte, pass string, version VkVersion) ...
  type VaultItemType (line 25) | type VaultItemType
  constant PrivateKeyWithMnemonic (line 29) | PrivateKeyWithMnemonic VaultItemType = "PrivateKeyWithMnemonic"
  type VkVersion (line 32) | type VkVersion
  constant VkVersion1 (line 35) | VkVersion1 VkVersion = "V1"
  constant vaultKeyLength (line 39) | vaultKeyLength = 32
  type VaultItem (line 41) | type VaultItem struct
  type storeVaultRequest (line 46) | type storeVaultRequest struct
  type StoredVault (line 52) | type StoredVault struct
  type retrieveVaultRequest (line 57) | type retrieveVaultRequest struct
  type retrieveVaultResponse (line 62) | type retrieveVaultResponse struct
  type Vault (line 66) | type Vault interface
  function New (line 71) | func New(vaultAPIURL string, vaultSaltSecret string) *vault {
  function encrypt (line 206) | func encrypt(data []byte, key []byte) ([]byte, error) {
  function decrypt (line 226) | func decrypt(ciphertext []byte, key []byte) ([]byte, error) {
  function parseAPIResponse (line 248) | func parseAPIResponse(resp *http.Response) ([]byte, error) {

FILE: core/vault/vault_test.go
  constant testSaltSecret (line 13) | testSaltSecret = "someSecret"
  constant testUuid (line 14) | testUuid = "c907e7ef-7b36-4ab1-8a56-f788d7526a2c"
  constant testPassphrase (line 15) | testPassphrase = "banana1234"
  constant testAPIToken (line 16) | testAPIToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdWJrZXkiOiJhZTR...
  function TestVault_StoreAndRetrieve (line 18) | func TestVault_StoreAndRetrieve(t *testing.T) {
  function TestVault_StoreServerError (line 94) | func TestVault_StoreServerError(t *testing.T) {
  function TestVault_RetrieveServerError (line 132) | func TestVault_RetrieveServerError(t *testing.T) {

FILE: core/watcher/blacklist.go
  function isBlacklisted (line 11) | func isBlacklisted(path string, fileInfo os.FileInfo) bool {

FILE: core/watcher/blacklist_windows.go
  function isBlacklisted (line 11) | func isBlacklisted(path string, fileInfo os.FileInfo) bool {

FILE: core/watcher/handler.go
  type EventHandler (line 12) | type EventHandler interface
  type defaultWatcherHandler (line 21) | type defaultWatcherHandler struct
    method OnCreate (line 23) | func (h *defaultWatcherHandler) OnCreate(
    method OnRemove (line 31) | func (h *defaultWatcherHandler) OnRemove(
    method OnWrite (line 39) | func (h *defaultWatcherHandler) OnWrite(
    method OnRename (line 47) | func (h *defaultWatcherHandler) OnRename(
    method OnMove (line 61) | func (h *defaultWatcherHandler) OnMove(

FILE: core/watcher/options.go
  type watcherOptions (line 3) | type watcherOptions struct
  type Option (line 9) | type Option
  function WithPaths (line 13) | func WithPaths(path ...string) Option {

FILE: core/watcher/watcher.go
  type FolderWatcher (line 24) | type FolderWatcher interface
  type folderWatcher (line 31) | type folderWatcher struct
    method RegisterHandler (line 74) | func (fw *folderWatcher) RegisterHandler(handler EventHandler) {
    method AddFile (line 80) | func (fw *folderWatcher) AddFile(path string) error {
    method Watch (line 94) | func (fw *folderWatcher) Watch(ctx context.Context) error {
    method setToStarted (line 133) | func (fw *folderWatcher) setToStarted() {
    method publishEvent (line 142) | func (fw *folderWatcher) publishEvent(ctx context.Context, event watch...
    method publishEventToHandler (line 151) | func (fw *folderWatcher) publishEventToHandler(
    method Close (line 176) | func (fw *folderWatcher) Close() {
    method Shutdown (line 188) | func (fw *folderWatcher) Shutdown() error {
  function New (line 43) | func New(configs ...Option) (*folderWatcher, error) {

FILE: core/watcher/watcher_test.go
  type handlerMock (line 15) | type handlerMock struct
    method OnCreate (line 19) | func (h *handlerMock) OnCreate(ctx context.Context, path string, fileI...
    method OnRemove (line 23) | func (h *handlerMock) OnRemove(ctx context.Context, path string, fileI...
    method OnWrite (line 27) | func (h *handlerMock) OnWrite(ctx context.Context, path string, fileIn...
    method OnRename (line 31) | func (h *handlerMock) OnRename(ctx context.Context, path string, fileI...
    method OnMove (line 35) | func (h *handlerMock) OnMove(ctx context.Context, path string, fileInf...
  function isTriggeredEvent (line 39) | func isTriggeredEvent(info os.FileInfo) bool {
  function startWatcher (line 43) | func startWatcher(t *testing.T, watchPaths ...string) (context.Context, ...
  function TestFolderWatcher_Watch_Triggers_Handler_OnCreate (line 61) | func TestFolderWatcher_Watch_Triggers_Handler_OnCreate(t *testing.T) {
  function TestFolderWatcher_Watch_Triggers_Handler_OnRemove (line 86) | func TestFolderWatcher_Watch_Triggers_Handler_OnRemove(t *testing.T) {

FILE: examples/ipfsLite/ipfsLite.go
  function main (line 5) | func main() {

FILE: examples/textileBucketsClient/bucket-sync/bucket-sync.go
  type TextileBucketRoot (line 25) | type TextileBucketRoot
  function main (line 27) | func main() {

FILE: examples/textileBucketsClient/buckets.go
  constant ctxTimeout (line 40) | ctxTimeout = 30
  function authCtx (line 42) | func authCtx(duration time.Duration) (context.Context, context.CancelFun...
  function threadCtx (line 49) | func threadCtx(duration time.Duration) (context.Context, context.CancelF...
  function getThreadID (line 55) | func getThreadID() (id thread.ID) {
  function runThreadsLocally (line 68) | func runThreadsLocally() {
  type Bucket (line 175) | type Bucket struct
  function initUser (line 185) | func initUser(threads *tc.Client, buckets *bc.Client, users *uc.Client, ...
  function main (line 382) | func main() {

FILE: examples/textileBucketsClient/create-thread-with-key/create-thread-with-key.go
  constant exampleThreadName (line 27) | exampleThreadName = "meow"
  function main (line 29) | func main() {

FILE: examples/textileBucketsClient/join-thread/join-thread.go
  function main (line 25) | func main() {

FILE: examples/textileBucketsClient/local-buck/local-buck.go
  function main (line 26) | func main() {

FILE: examples/textileBucketsClient/open-share-file/open-share-file.go
  type TextileBucketRoot (line 25) | type TextileBucketRoot
  function main (line 27) | func main() {

FILE: examples/textileBucketsClient/sync-test/sync-test.go
  type TextileBucketRoot (line 23) | type TextileBucketRoot
  function main (line 25) | func main() {

FILE: grpc/auth/app_token_auth/app_token_auth.go
  type AppTokenAuth (line 13) | type AppTokenAuth struct
    method Authorize (line 23) | func (a *AppTokenAuth) Authorize(ctx context.Context, fullMethodName s...
    method validateToken (line 43) | func (a *AppTokenAuth) validateToken(tok, fullMethodName string) (*per...
  function New (line 17) | func New(kc keychain.Keychain) *AppTokenAuth {
  function canSkipAuth (line 82) | func canSkipAuth(fullMethodName string) bool {

FILE: grpc/auth/app_token_auth/auth_from_md.go
  function AuthFromMD (line 21) | func AuthFromMD(ctx context.Context, expectedScheme string) (string, err...

FILE: grpc/auth/middleware/grpc_auth.go
  type AuthFunc (line 21) | type AuthFunc
  function UnaryServerInterceptor (line 24) | func UnaryServerInterceptor(authFunc AuthFunc) grpc.UnaryServerIntercept...
  function StreamServerInterceptor (line 37) | func StreamServerInterceptor(authFunc AuthFunc) grpc.StreamServerInterce...

FILE: grpc/grpc.go
  constant DefaultGrpcPort (line 28) | DefaultGrpcPort = 9999
  type serverOptions (line 35) | type serverOptions struct
  type grpcServer (line 41) | type grpcServer struct
    method Start (line 79) | func (srv *grpcServer) Start(ctx context.Context) error {
    method startRestProxy (line 108) | func (srv *grpcServer) startRestProxy(ctx context.Context, lis net.Lis...
    method startGrpcWebProxy (line 136) | func (srv *grpcServer) startGrpcWebProxy() {
    method Shutdown (line 193) | func (srv *grpcServer) Shutdown() error {
    method WaitForReady (line 220) | func (srv *grpcServer) WaitForReady() chan bool {
  type ServerOption (line 59) | type ServerOption
  function New (line 62) | func New(sv space.Service, fc *fuse.Controller, kc keychain.Keychain, op...
  function WithPort (line 168) | func WithPort(port int) ServerOption {
  function WithProxyPort (line 176) | func WithProxyPort(port int) ServerOption {
  function WithRestProxyPort (line 185) | func WithRestProxyPort(port int) ServerOption {

FILE: grpc/handlers.go
  method sendFileEvent (line 16) | func (srv *grpcServer) sendFileEvent(event *pb.FileEventResponse) {
  method SendFileEvent (line 23) | func (srv *grpcServer) SendFileEvent(event events.FileEvent) {
  function mapFileEventToPb (line 37) | func mapFileEventToPb(eventType events.FileEventType) pb.EventType {
  method sendTextileEvent (line 64) | func (srv *grpcServer) sendTextileEvent(event *pb.TextileEventResponse) {
  method SendTextileEvent (line 71) | func (srv *grpcServer) SendTextileEvent(event events.TextileEvent) {
  method ListDirectories (line 77) | func (srv *grpcServer) ListDirectories(ctx context.Context, request *pb....
  method ListDirectory (line 95) | func (srv *grpcServer) ListDirectory(
  function mapFileInfoToDirectoryEntry (line 115) | func mapFileInfoToDirectoryEntry(entries []domain.FileInfo) []*pb.ListDi...
  method Subscribe (line 153) | func (srv *grpcServer) Subscribe(empty *empty.Empty, stream pb.SpaceApi_...
  method registerStream (line 166) | func (srv *grpcServer) registerStream(stream pb.SpaceApi_SubscribeServer) {
  method TxlSubscribe (line 170) | func (srv *grpcServer) TxlSubscribe(empty *empty.Empty, stream pb.SpaceA...
  method registerTxlStream (line 183) | func (srv *grpcServer) registerTxlStream(stream pb.SpaceApi_TxlSubscribe...
  method OpenFile (line 187) | func (srv *grpcServer) OpenFile(ctx context.Context, request *pb.OpenFil...
  method AddItems (line 196) | func (srv *grpcServer) AddItems(request *pb.AddItemsRequest, stream pb.S...
  method CreateFolder (line 262) | func (srv *grpcServer) CreateFolder(ctx context.Context, request *pb.Cre...
  method RemoveDirOrFile (line 271) | func (srv *grpcServer) RemoveDirOrFile(ctx context.Context, request *pb....

FILE: grpc/handlers_account.go
  method DeleteAccount (line 10) | func (srv *grpcServer) DeleteAccount(ctx context.Context, request *pb.De...

FILE: grpc/handlers_app_token.go
  method InitializeMasterAppToken (line 9) | func (srv *grpcServer) InitializeMasterAppToken(ctx context.Context, req...
  method GenerateAppToken (line 20) | func (srv *grpcServer) GenerateAppToken(ctx context.Context, request *pb...

FILE: grpc/handlers_backup.go
  method ToggleBucketBackup (line 8) | func (srv *grpcServer) ToggleBucketBackup(ctx context.Context, request *...
  method BucketBackupRestore (line 20) | func (srv *grpcServer) BucketBackupRestore(ctx context.Context, request ...
  method GetUsageInfo (line 31) | func (srv *grpcServer) GetUsageInfo(ctx context.Context, request *pb.Get...

FILE: grpc/handlers_central_services.go
  method GetAPISessionTokens (line 9) | func (srv *grpcServer) GetAPISessionTokens(ctx context.Context, request ...

FILE: grpc/handlers_fuse.go
  method ToggleFuseDrive (line 16) | func (srv *grpcServer) ToggleFuseDrive(ctx context.Context, request *pb....
  method GetFuseDriveStatus (line 34) | func (srv *grpcServer) GetFuseDriveStatus(ctx context.Context, empty *em...
  function fuseStateToRpcState (line 56) | func fuseStateToRpcState(state fuse.State) pb.FuseState {

FILE: grpc/handlers_key_pair.go
  method GenerateKeyPair (line 9) | func (srv *grpcServer) GenerateKeyPair(ctx context.Context, request *pb....
  method GenerateKeyPairWithForce (line 21) | func (srv *grpcServer) GenerateKeyPairWithForce(ctx context.Context, req...
  method GetPublicKey (line 32) | func (srv *grpcServer) GetPublicKey(ctx context.Context, request *pb.Get...
  method DeleteKeyPair (line 43) | func (srv *grpcServer) DeleteKeyPair(ctx context.Context, request *pb.De...
  method RestoreKeyPairViaMnemonic (line 52) | func (srv *grpcServer) RestoreKeyPairViaMnemonic(ctx context.Context, re...
  method GetStoredMnemonic (line 60) | func (srv *grpcServer) GetStoredMnemonic(ctx context.Context, request *p...

FILE: grpc/handlers_notif.go
  function mapToPbNotification (line 12) | func mapToPbNotification(n domain.Notification) *pb.Notification {
  method SetNotificationsLastSeenAt (line 114) | func (srv *grpcServer) SetNotificationsLastSeenAt(ctx context.Context, r...
  method GetNotifications (line 122) | func (srv *grpcServer) GetNotifications(ctx context.Context, request *pb...
  method ReadNotification (line 155) | func (srv *grpcServer) ReadNotification(ctx context.Context, request *pb...
  method HandleFilesInvitation (line 159) | func (srv *grpcServer) HandleFilesInvitation(
  method NotificationSubscribe (line 171) | func (srv *grpcServer) NotificationSubscribe(empty *empty.Empty, stream ...
  method registerNotificationStream (line 184) | func (srv *grpcServer) registerNotificationStream(stream pb.SpaceApi_Not...
  method sendNotificationEvent (line 188) | func (srv *grpcServer) sendNotificationEvent(event *pb.NotificationEvent...
  method SendNotificationEvent (line 195) | func (srv *grpcServer) SendNotificationEvent(notif *domain.Notification) {

FILE: grpc/handlers_search.go
  method SearchFiles (line 10) | func (srv *grpcServer) SearchFiles(ctx context.Context, request *pb.Sear...

FILE: grpc/handlers_sharing.go
  method ShareFilesViaPublicKey (line 14) | func (srv *grpcServer) ShareFilesViaPublicKey(ctx context.Context, reque...
  method UnshareFilesViaPublicKey (line 55) | func (srv *grpcServer) UnshareFilesViaPublicKey(
  method GetSharedWithMeFiles (line 89) | func (srv *grpcServer) GetSharedWithMeFiles(ctx context.Context, request...
  method GetSharedByMeFiles (line 142) | func (srv *grpcServer) GetSharedByMeFiles(ctx context.Context, request *...
  method GeneratePublicFileLink (line 194) | func (srv *grpcServer) GeneratePublicFileLink(ctx context.Context, reque...
  method OpenPublicFile (line 209) | func (srv *grpcServer) OpenPublicFile(ctx context.Context, request *pb.O...
  method GetRecentlySharedWith (line 220) | func (srv *grpcServer) GetRecentlySharedWith(ctx context.Context, reques...

FILE: grpc/handlers_textile.go
  function parseBucket (line 11) | func parseBucket(ctx context.Context, b textile.Bucket) *pb.Bucket {
  method CreateBucket (line 32) | func (srv *grpcServer) CreateBucket(ctx context.Context, request *pb.Cre...
  method ListBuckets (line 44) | func (srv *grpcServer) ListBuckets(ctx context.Context, request *pb.List...
  method ShareBucket (line 62) | func (srv *grpcServer) ShareBucket(ctx context.Context, request *pb.Shar...
  method JoinBucket (line 77) | func (srv *grpcServer) JoinBucket(ctx context.Context, request *pb.JoinB...

FILE: grpc/handlers_vault.go
  method BackupKeysByPassphrase (line 10) | func (srv *grpcServer) BackupKeysByPassphrase(ctx context.Context, reque...
  method RecoverKeysByPassphrase (line 17) | func (srv *grpcServer) RecoverKeysByPassphrase(ctx context.Context, requ...
  method CreateLocalKeysBackup (line 24) | func (srv *grpcServer) CreateLocalKeysBackup(ctx context.Context, reques...
  method RecoverKeysByLocalBackup (line 31) | func (srv *grpcServer) RecoverKeysByLocalBackup(ctx context.Context, req...
  method TestKeysPassphrase (line 38) | func (srv *grpcServer) TestKeysPassphrase(ctx context.Context, request *...

FILE: grpc/pb/space.pb.go
  constant _ (line 25) | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
  constant _ (line 27) | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
  constant _ (line 32) | _ = proto.ProtoPackageIsVersion4
  type EventType (line 34) | type EventType
    method Enum (line 77) | func (x EventType) Enum() *EventType {
    method String (line 83) | func (x EventType) String() string {
    method Descriptor (line 87) | func (EventType) Descriptor() protoreflect.EnumDescriptor {
    method Type (line 91) | func (EventType) Type() protoreflect.EnumType {
    method Number (line 95) | func (x EventType) Number() protoreflect.EnumNumber {
    method EnumDescriptor (line 100) | func (EventType) EnumDescriptor() ([]byte, []int) {
  constant EventType_ENTRY_ADDED (line 37) | EventType_ENTRY_ADDED               EventType = 0
  constant EventType_ENTRY_DELETED (line 38) | EventType_ENTRY_DELETED             EventType = 1
  constant EventType_ENTRY_UPDATED (line 39) | EventType_ENTRY_UPDATED             EventType = 2
  constant EventType_ENTRY_BACKUP_IN_PROGRESS (line 40) | EventType_ENTRY_BACKUP_IN_PROGRESS  EventType = 3
  constant EventType_ENTRY_BACKUP_READY (line 41) | EventType_ENTRY_BACKUP_READY        EventType = 4
  constant EventType_ENTRY_RESTORE_IN_PROGRESS (line 42) | EventType_ENTRY_RESTORE_IN_PROGRESS EventType = 5
  constant EventType_ENTRY_RESTORE_READY (line 43) | EventType_ENTRY_RESTORE_READY       EventType = 6
  constant EventType_FOLDER_ADDED (line 44) | EventType_FOLDER_ADDED              EventType = 7
  constant EventType_FOLDER_DELETED (line 45) | EventType_FOLDER_DELETED            EventType = 8
  constant EventType_FOLDER_UPDATED (line 46) | EventType_FOLDER_UPDATED            EventType = 9
  type KeyBackupType (line 104) | type KeyBackupType
    method Enum (line 129) | func (x KeyBackupType) Enum() *KeyBackupType {
    method String (line 135) | func (x KeyBackupType) String() string {
    method Descriptor (line 139) | func (KeyBackupType) Descriptor() protoreflect.EnumDescriptor {
    method Type (line 143) | func (KeyBackupType) Type() protoreflect.EnumType {
    method Number (line 147) | func (x KeyBackupType) Number() protoreflect.EnumNumber {
    method EnumDescriptor (line 152) | func (KeyBackupType) EnumDescriptor() ([]byte, []int) {
  constant KeyBackupType_PASSWORD (line 107) | KeyBackupType_PASSWORD KeyBackupType = 0
  constant KeyBackupType_GOOGLE (line 108) | KeyBackupType_GOOGLE   KeyBackupType = 1
  constant KeyBackupType_TWITTER (line 109) | KeyBackupType_TWITTER  KeyBackupType = 2
  constant KeyBackupType_EMAIL (line 110) | KeyBackupType_EMAIL    KeyBackupType = 3
  type FuseState (line 156) | type FuseState
    method Enum (line 181) | func (x FuseState) Enum() *FuseState {
    method String (line 187) | func (x FuseState) String() string {
    method Descriptor (line 191) | func (FuseState) Descriptor() protoreflect.EnumDescriptor {
    method Type (line 195) | func (FuseState) Type() protoreflect.EnumType {
    method Number (line 199) | func (x FuseState) Number() protoreflect.EnumNumber {
    method EnumDescriptor (line 204) | func (FuseState) EnumDescriptor() ([]byte, []int) {
  constant FuseState_UNSUPPORTED (line 159) | FuseState_UNSUPPORTED   FuseState = 0
  constant FuseState_NOT_INSTALLED (line 160) | FuseState_NOT_INSTALLED FuseState = 1
  constant FuseState_UNMOUNTED (line 161) | FuseState_UNMOUNTED     FuseState = 2
  constant FuseState_MOUNTED (line 162) | FuseState_MOUNTED       FuseState = 3
  type NotificationType (line 208) | type NotificationType
    method Enum (line 236) | func (x NotificationType) Enum() *NotificationType {
    method String (line 242) | func (x NotificationType) String() string {
    method Descriptor (line 246) | func (NotificationType) Descriptor() protoreflect.EnumDescriptor {
    method Type (line 250) | func (NotificationType) Type() protoreflect.EnumType {
    method Number (line 254) | func (x NotificationType) Number() protoreflect.EnumNumber {
    method EnumDescriptor (line 259) | func (NotificationType) EnumDescriptor() ([]byte, []int) {
  constant NotificationType_UNKNOWN (line 211) | NotificationType_UNKNOWN            NotificationType = 0
  constant NotificationType_INVITATION (line 212) | NotificationType_INVITATION         NotificationType = 1
  constant NotificationType_USAGEALERT (line 213) | NotificationType_USAGEALERT         NotificationType = 2
  constant NotificationType_INVITATION_REPLY (line 214) | NotificationType_INVITATION_REPLY   NotificationType = 3
  constant NotificationType_REVOKED_INVITATION (line 215) | NotificationType_REVOKED_INVITATION NotificationType = 4
  type InvitationStatus (line 263) | type InvitationStatus
    method Enum (line 285) | func (x InvitationStatus) Enum() *InvitationStatus {
    method String (line 291) | func (x InvitationStatus) String() string {
    method Descriptor (line 295) | func (InvitationStatus) Descriptor() protoreflect.EnumDescriptor {
    method Type (line 299) | func (InvitationStatus) Type() protoreflect.EnumType {
    method Number (line 303) | func (x InvitationStatus) Number() protoreflect.EnumNumber {
    method EnumDescriptor (line 308) | func (InvitationStatus) EnumDescriptor() ([]byte, []int) {
  constant InvitationStatus_PENDING (line 266) | InvitationStatus_PENDING  InvitationStatus = 0
  constant InvitationStatus_ACCEPTED (line 267) | InvitationStatus_ACCEPTED InvitationStatus = 1
  constant InvitationStatus_REJECTED (line 268) | InvitationStatus_REJECTED InvitationStatus = 2
  type SearchFilesRequest (line 312) | type SearchFilesRequest struct
    method Reset (line 320) | func (x *SearchFilesRequest) Reset() {
    method String (line 329) | func (x *SearchFilesRequest) String() string {
    method ProtoMessage (line 333) | func (*SearchFilesRequest) ProtoMessage() {}
    method ProtoReflect (line 335) | func (x *SearchFilesRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 348) | func (*SearchFilesRequest) Descriptor() ([]byte, []int) {
    method GetQuery (line 352) | func (x *SearchFilesRequest) GetQuery() string {
  type SearchFilesResponse (line 359) | type SearchFilesResponse struct
    method Reset (line 368) | func (x *SearchFilesResponse) Reset() {
    method String (line 377) | func (x *SearchFilesResponse) String() string {
    method ProtoMessage (line 381) | func (*SearchFilesResponse) ProtoMessage() {}
    method ProtoReflect (line 383) | func (x *SearchFilesResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 396) | func (*SearchFilesResponse) Descriptor() ([]byte, []int) {
    method GetEntries (line 400) | func (x *SearchFilesResponse) GetEntries() []*SearchFilesDirectoryEntry {
    method GetQuery (line 407) | func (x *SearchFilesResponse) GetQuery() string {
  type SearchFilesDirectoryEntry (line 414) | type SearchFilesDirectoryEntry struct
    method Reset (line 424) | func (x *SearchFilesDirectoryEntry) Reset() {
    method String (line 433) | func (x *SearchFilesDirectoryEntry) String() string {
    method ProtoMessage (line 437) | func (*SearchFilesDirectoryEntry) ProtoMessage() {}
    method ProtoReflect (line 439) | func (x *SearchFilesDirectoryEntry) ProtoReflect() protoreflect.Message {
    method Descriptor (line 452) | func (*SearchFilesDirectoryEntry) Descriptor() ([]byte, []int) {
    method GetEntry (line 456) | func (x *SearchFilesDirectoryEntry) GetEntry() *ListDirectoryEntry {
    method GetDbId (line 463) | func (x *SearchFilesDirectoryEntry) GetDbId() string {
    method GetBucket (line 470) | func (x *SearchFilesDirectoryEntry) GetBucket() string {
  type SetNotificationsLastSeenAtRequest (line 477) | type SetNotificationsLastSeenAtRequest struct
    method Reset (line 485) | func (x *SetNotificationsLastSeenAtRequest) Reset() {
    method String (line 494) | func (x *SetNotificationsLastSeenAtRequest) String() string {
    method ProtoMessage (line 498) | func (*SetNotificationsLastSeenAtRequest) ProtoMessage() {}
    method ProtoReflect (line 500) | func (x *SetNotificationsLastSeenAtRequest) ProtoReflect() protoreflec...
    method Descriptor (line 513) | func (*SetNotificationsLastSeenAtRequest) Descriptor() ([]byte, []int) {
    method GetTimestamp (line 517) | func (x *SetNotificationsLastSeenAtRequest) GetTimestamp() int64 {
  type SetNotificationsLastSeenAtResponse (line 524) | type SetNotificationsLastSeenAtResponse struct
    method Reset (line 530) | func (x *SetNotificationsLastSeenAtResponse) Reset() {
    method String (line 539) | func (x *SetNotificationsLastSeenAtResponse) String() string {
    method ProtoMessage (line 543) | func (*SetNotificationsLastSeenAtResponse) ProtoMessage() {}
    method ProtoReflect (line 545) | func (x *SetNotificationsLastSeenAtResponse) ProtoReflect() protorefle...
    method Descriptor (line 558) | func (*SetNotificationsLastSeenAtResponse) Descriptor() ([]byte, []int) {
  type GetSharedWithMeFilesRequest (line 562) | type GetSharedWithMeFilesRequest struct
    method Reset (line 571) | func (x *GetSharedWithMeFilesRequest) Reset() {
    method String (line 580) | func (x *GetSharedWithMeFilesRequest) String() string {
    method ProtoMessage (line 584) | func (*GetSharedWithMeFilesRequest) ProtoMessage() {}
    method ProtoReflect (line 586) | func (x *GetSharedWithMeFilesRequest) ProtoReflect() protoreflect.Mess...
    method Descriptor (line 599) | func (*GetSharedWithMeFilesRequest) Descriptor() ([]byte, []int) {
    method GetSeek (line 603) | func (x *GetSharedWithMeFilesRequest) GetSeek() string {
    method GetLimit (line 610) | func (x *GetSharedWithMeFilesRequest) GetLimit() int64 {
  type GetSharedWithMeFilesResponse (line 617) | type GetSharedWithMeFilesResponse struct
    method Reset (line 626) | func (x *GetSharedWithMeFilesResponse) Reset() {
    method String (line 635) | func (x *GetSharedWithMeFilesResponse) String() string {
    method ProtoMessage (line 639) | func (*GetSharedWithMeFilesResponse) ProtoMessage() {}
    method ProtoReflect (line 641) | func (x *GetSharedWithMeFilesResponse) ProtoReflect() protoreflect.Mes...
    method Descriptor (line 654) | func (*GetSharedWithMeFilesResponse) Descriptor() ([]byte, []int) {
    method GetItems (line 658) | func (x *GetSharedWithMeFilesResponse) GetItems() []*SharedListDirecto...
    method GetNextOffset (line 665) | func (x *GetSharedWithMeFilesResponse) GetNextOffset() string {
  type GetSharedByMeFilesRequest (line 672) | type GetSharedByMeFilesRequest struct
    method Reset (line 681) | func (x *GetSharedByMeFilesRequest) Reset() {
    method String (line 690) | func (x *GetSharedByMeFilesRequest) String() string {
    method ProtoMessage (line 694) | func (*GetSharedByMeFilesRequest) ProtoMessage() {}
    method ProtoReflect (line 696) | func (x *GetSharedByMeFilesRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 709) | func (*GetSharedByMeFilesRequest) Descriptor() ([]byte, []int) {
    method GetSeek (line 713) | func (x *GetSharedByMeFilesRequest) GetSeek() string {
    method GetLimit (line 720) | func (x *GetSharedByMeFilesRequest) GetLimit() int64 {
  type GetSharedByMeFilesResponse (line 727) | type GetSharedByMeFilesResponse struct
    method Reset (line 736) | func (x *GetSharedByMeFilesResponse) Reset() {
    method String (line 745) | func (x *GetSharedByMeFilesResponse) String() string {
    method ProtoMessage (line 749) | func (*GetSharedByMeFilesResponse) ProtoMessage() {}
    method ProtoReflect (line 751) | func (x *GetSharedByMeFilesResponse) ProtoReflect() protoreflect.Messa...
    method Descriptor (line 764) | func (*GetSharedByMeFilesResponse) Descriptor() ([]byte, []int) {
    method GetItems (line 768) | func (x *GetSharedByMeFilesResponse) GetItems() []*SharedListDirectory...
    method GetNextOffset (line 775) | func (x *GetSharedByMeFilesResponse) GetNextOffset() string {
  type GetUsageInfoRequest (line 782) | type GetUsageInfoRequest struct
    method Reset (line 788) | func (x *GetUsageInfoRequest) Reset() {
    method String (line 797) | func (x *GetUsageInfoRequest) String() string {
    method ProtoMessage (line 801) | func (*GetUsageInfoRequest) ProtoMessage() {}
    method ProtoReflect (line 803) | func (x *GetUsageInfoRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 816) | func (*GetUsageInfoRequest) Descriptor() ([]byte, []int) {
  type GetUsageInfoResponse (line 820) | type GetUsageInfoResponse struct
    method Reset (line 832) | func (x *GetUsageInfoResponse) Reset() {
    method String (line 841) | func (x *GetUsageInfoResponse) String() string {
    method ProtoMessage (line 845) | func (*GetUsageInfoResponse) ProtoMessage() {}
    method ProtoReflect (line 847) | func (x *GetUsageInfoResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 860) | func (*GetUsageInfoResponse) Descriptor() ([]byte, []int) {
    method GetLocalStarogeUsed (line 864) | func (x *GetUsageInfoResponse) GetLocalStarogeUsed() uint64 {
    method GetLocalBandwidthUsed (line 871) | func (x *GetUsageInfoResponse) GetLocalBandwidthUsed() uint64 {
    method GetSpaceStorageUsed (line 878) | func (x *GetUsageInfoResponse) GetSpaceStorageUsed() uint64 {
    method GetSpaceBandwidthUsed (line 885) | func (x *GetUsageInfoResponse) GetSpaceBandwidthUsed() uint64 {
    method GetUsageQuota (line 892) | func (x *GetUsageInfoResponse) GetUsageQuota() uint64 {
  type ToggleBucketBackupRequest (line 899) | type ToggleBucketBackupRequest struct
    method Reset (line 908) | func (x *ToggleBucketBackupRequest) Reset() {
    method String (line 917) | func (x *ToggleBucketBackupRequest) String() string {
    method ProtoMessage (line 921) | func (*ToggleBucketBackupRequest) ProtoMessage() {}
    method ProtoReflect (line 923) | func (x *ToggleBucketBackupRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 936) | func (*ToggleBucketBackupRequest) Descriptor() ([]byte, []int) {
    method GetBucket (line 940) | func (x *ToggleBucketBackupRequest) GetBucket() string {
    method GetBackup (line 947) | func (x *ToggleBucketBackupRequest) GetBackup() bool {
  type ToggleBucketBackupResponse (line 954) | type ToggleBucketBackupResponse struct
    method Reset (line 960) | func (x *ToggleBucketBackupResponse) Reset() {
    method String (line 969) | func (x *ToggleBucketBackupResponse) String() string {
    method ProtoMessage (line 973) | func (*ToggleBucketBackupResponse) ProtoMessage() {}
    method ProtoReflect (line 975) | func (x *ToggleBucketBackupResponse) ProtoReflect() protoreflect.Messa...
    method Descriptor (line 988) | func (*ToggleBucketBackupResponse) Descriptor() ([]byte, []int) {
  type BucketBackupRestoreRequest (line 992) | type BucketBackupRestoreRequest struct
    method Reset (line 1000) | func (x *BucketBackupRestoreRequest) Reset() {
    method String (line 1009) | func (x *BucketBackupRestoreRequest) String() string {
    method ProtoMessage (line 1013) | func (*BucketBackupRestoreRequest) ProtoMessage() {}
    method ProtoReflect (line 1015) | func (x *BucketBackupRestoreRequest) ProtoReflect() protoreflect.Messa...
    method Descriptor (line 1028) | func (*BucketBackupRestoreRequest) Descriptor() ([]byte, []int) {
    method GetBucket (line 1032) | func (x *BucketBackupRestoreRequest) GetBucket() string {
  type BucketBackupRestoreResponse (line 1039) | type BucketBackupRestoreResponse struct
    method Reset (line 1045) | func (x *BucketBackupRestoreResponse) Reset() {
    method String (line 1054) | func (x *BucketBackupRestoreResponse) String() string {
    method ProtoMessage (line 1058) | func (*BucketBackupRestoreResponse) ProtoMessage() {}
    method ProtoReflect (line 1060) | func (x *BucketBackupRestoreResponse) ProtoReflect() protoreflect.Mess...
    method Descriptor (line 1073) | func (*BucketBackupRestoreResponse) Descriptor() ([]byte, []int) {
  type ListDirectoriesRequest (line 1077) | type ListDirectoriesRequest struct
    method Reset (line 1086) | func (x *ListDirectoriesRequest) Reset() {
    method String (line 1095) | func (x *ListDirectoriesRequest) String() string {
    method ProtoMessage (line 1099) | func (*ListDirectoriesRequest) ProtoMessage() {}
    method ProtoReflect (line 1101) | func (x *ListDirectoriesRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1114) | func (*ListDirectoriesRequest) Descriptor() ([]byte, []int) {
    method GetBucket (line 1118) | func (x *ListDirectoriesRequest) GetBucket() string {
    method GetOmitMembers (line 1125) | func (x *ListDirectoriesRequest) GetOmitMembers() bool {
  type FileMember (line 1132) | type FileMember struct
    method Reset (line 1141) | func (x *FileMember) Reset() {
    method String (line 1150) | func (x *FileMember) String() string {
    method ProtoMessage (line 1154) | func (*FileMember) ProtoMessage() {}
    method ProtoReflect (line 1156) | func (x *FileMember) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1169) | func (*FileMember) Descriptor() ([]byte, []int) {
    method GetPublicKey (line 1173) | func (x *FileMember) GetPublicKey() string {
    method GetAddress (line 1180) | func (x *FileMember) GetAddress() string {
  type ListDirectoryEntry (line 1187) | type ListDirectoryEntry struct
    method Reset (line 1207) | func (x *ListDirectoryEntry) Reset() {
    method String (line 1216) | func (x *ListDirectoryEntry) String() string {
    method ProtoMessage (line 1220) | func (*ListDirectoryEntry) ProtoMessage() {}
    method ProtoReflect (line 1222) | func (x *ListDirectoryEntry) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1235) | func (*ListDirectoryEntry) Descriptor() ([]byte, []int) {
    method GetPath (line 1239) | func (x *ListDirectoryEntry) GetPath() string {
    method GetIsDir (line 1246) | func (x *ListDirectoryEntry) GetIsDir() bool {
    method GetName (line 1253) | func (x *ListDirectoryEntry) GetName() string {
    method GetSizeInBytes (line 1260) | func (x *ListDirectoryEntry) GetSizeInBytes() string {
    method GetCreated (line 1267) | func (x *ListDirectoryEntry) GetCreated() string {
    method GetUpdated (line 1274) | func (x *ListDirectoryEntry) GetUpdated() string {
    method GetFileExtension (line 1281) | func (x *ListDirectoryEntry) GetFileExtension() string {
    method GetIpfsHash (line 1288) | func (x *ListDirectoryEntry) GetIpfsHash() string {
    method GetIsLocallyAvailable (line 1295) | func (x *ListDirectoryEntry) GetIsLocallyAvailable() bool {
    method GetBackupCount (line 1302) | func (x *ListDirectoryEntry) GetBackupCount() int64 {
    method GetMembers (line 1309) | func (x *ListDirectoryEntry) GetMembers() []*FileMember {
    method GetIsBackupInProgress (line 1316) | func (x *ListDirectoryEntry) GetIsBackupInProgress() bool {
    method GetIsRestoreInProgress (line 1323) | func (x *ListDirectoryEntry) GetIsRestoreInProgress() bool {
  type SharedListDirectoryEntry (line 1330) | type SharedListDirectoryEntry struct
    method Reset (line 1342) | func (x *SharedListDirectoryEntry) Reset() {
    method String (line 1351) | func (x *SharedListDirectoryEntry) String() string {
    method ProtoMessage (line 1355) | func (*SharedListDirectoryEntry) ProtoMessage() {}
    method ProtoReflect (line 1357) | func (x *SharedListDirectoryEntry) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1370) | func (*SharedListDirectoryEntry) Descriptor() ([]byte, []int) {
    method GetEntry (line 1374) | func (x *SharedListDirectoryEntry) GetEntry() *ListDirectoryEntry {
    method GetDbId (line 1381) | func (x *SharedListDirectoryEntry) GetDbId() string {
    method GetBucket (line 1388) | func (x *SharedListDirectoryEntry) GetBucket() string {
    method GetIsPublicLink (line 1395) | func (x *SharedListDirectoryEntry) GetIsPublicLink() bool {
    method GetSharedBy (line 1402) | func (x *SharedListDirectoryEntry) GetSharedBy() string {
  type ListDirectoriesResponse (line 1409) | type ListDirectoriesResponse struct
    method Reset (line 1417) | func (x *ListDirectoriesResponse) Reset() {
    method String (line 1426) | func (x *ListDirectoriesResponse) String() string {
    method ProtoMessage (line 1430) | func (*ListDirectoriesResponse) ProtoMessage() {}
    method ProtoReflect (line 1432) | func (x *ListDirectoriesResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1445) | func (*ListDirectoriesResponse) Descriptor() ([]byte, []int) {
    method GetEntries (line 1449) | func (x *ListDirectoriesResponse) GetEntries() []*ListDirectoryEntry {
  type ListDirectoryRequest (line 1456) | type ListDirectoryRequest struct
    method Reset (line 1466) | func (x *ListDirectoryRequest) Reset() {
    method String (line 1475) | func (x *ListDirectoryRequest) String() string {
    method ProtoMessage (line 1479) | func (*ListDirectoryRequest) ProtoMessage() {}
    method ProtoReflect (line 1481) | func (x *ListDirectoryRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1494) | func (*ListDirectoryRequest) Descriptor() ([]byte, []int) {
    method GetPath (line 1498) | func (x *ListDirectoryRequest) GetPath() string {
    method GetBucket (line 1505) | func (x *ListDirectoryRequest) GetBucket() string {
    method GetOmitMembers (line 1512) | func (x *ListDirectoryRequest) GetOmitMembers() bool {
  type ListDirectoryResponse (line 1519) | type ListDirectoryResponse struct
    method Reset (line 1527) | func (x *ListDirectoryResponse) Reset() {
    method String (line 1536) | func (x *ListDirectoryResponse) String() string {
    method ProtoMessage (line 1540) | func (*ListDirectoryResponse) ProtoMessage() {}
    method ProtoReflect (line 1542) | func (x *ListDirectoryResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1555) | func (*ListDirectoryResponse) Descriptor() ([]byte, []int) {
    method GetEntries (line 1559) | func (x *ListDirectoryResponse) GetEntries() []*ListDirectoryEntry {
  type CreateBucketRequest (line 1566) | type CreateBucketRequest struct
    method Reset (line 1574) | func (x *CreateBucketRequest) Reset() {
    method String (line 1583) | func (x *CreateBucketRequest) String() string {
    method ProtoMessage (line 1587) | func (*CreateBucketRequest) ProtoMessage() {}
    method ProtoReflect (line 1589) | func (x *CreateBucketRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1602) | func (*CreateBucketRequest) Descriptor() ([]byte, []int) {
    method GetSlug (line 1606) | func (x *CreateBucketRequest) GetSlug() string {
  type BucketMember (line 1613) | type BucketMember struct
    method Reset (line 1624) | func (x *BucketMember) Reset() {
    method String (line 1633) | func (x *BucketMember) String() string {
    method ProtoMessage (line 1637) | func (*BucketMember) ProtoMessage() {}
    method ProtoReflect (line 1639) | func (x *BucketMember) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1652) | func (*BucketMember) Descriptor() ([]byte, []int) {
    method GetAddress (line 1656) | func (x *BucketMember) GetAddress() string {
    method GetPublicKey (line 1663) | func (x *BucketMember) GetPublicKey() string {
    method GetIsOwner (line 1670) | func (x *BucketMember) GetIsOwner() bool {
    method GetHasJoined (line 1677) | func (x *BucketMember) GetHasJoined() bool {
  type Bucket (line 1684) | type Bucket struct
    method Reset (line 1700) | func (x *Bucket) Reset() {
    method String (line 1709) | func (x *Bucket) String() string {
    method ProtoMessage (line 1713) | func (*Bucket) ProtoMessage() {}
    method ProtoReflect (line 1715) | func (x *Bucket) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1728) | func (*Bucket) Descriptor() ([]byte, []int) {
    method GetKey (line 1732) | func (x *Bucket) GetKey() string {
    method GetName (line 1739) | func (x *Bucket) GetName() string {
    method GetPath (line 1746) | func (x *Bucket) GetPath() string {
    method GetCreatedAt (line 1753) | func (x *Bucket) GetCreatedAt() int64 {
    method GetUpdatedAt (line 1760) | func (x *Bucket) GetUpdatedAt() int64 {
    method GetMembers (line 1767) | func (x *Bucket) GetMembers() []*BucketMember {
    method GetIsPersonalBucket (line 1774) | func (x *Bucket) GetIsPersonalBucket() bool {
    method GetIsBackupEnabled (line 1781) | func (x *Bucket) GetIsBackupEnabled() bool {
    method GetItemsCount (line 1788) | func (x *Bucket) GetItemsCount() int32 {
  type CreateBucketResponse (line 1795) | type CreateBucketResponse struct
    method Reset (line 1803) | func (x *CreateBucketResponse) Reset() {
    method String (line 1812) | func (x *CreateBucketResponse) String() string {
    method ProtoMessage (line 1816) | func (*CreateBucketResponse) ProtoMessage() {}
    method ProtoReflect (line 1818) | func (x *CreateBucketResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1831) | func (*CreateBucketResponse) Descriptor() ([]byte, []int) {
    method GetBucket (line 1835) | func (x *CreateBucketResponse) GetBucket() *Bucket {
  type GenerateKeyPairRequest (line 1842) | type GenerateKeyPairRequest struct
    method Reset (line 1848) | func (x *GenerateKeyPairRequest) Reset() {
    method String (line 1857) | func (x *GenerateKeyPairRequest) String() string {
    method ProtoMessage (line 1861) | func (*GenerateKeyPairRequest) ProtoMessage() {}
    method ProtoReflect (line 1863) | func (x *GenerateKeyPairRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1876) | func (*GenerateKeyPairRequest) Descriptor() ([]byte, []int) {
  type GenerateKeyPairResponse (line 1880) | type GenerateKeyPairResponse struct
    method Reset (line 1888) | func (x *GenerateKeyPairResponse) Reset() {
    method String (line 1897) | func (x *GenerateKeyPairResponse) String() string {
    method ProtoMessage (line 1901) | func (*GenerateKeyPairResponse) ProtoMessage() {}
    method ProtoReflect (line 1903) | func (x *GenerateKeyPairResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1916) | func (*GenerateKeyPairResponse) Descriptor() ([]byte, []int) {
    method GetMnemonic (line 1920) | func (x *GenerateKeyPairResponse) GetMnemonic() string {
  type GetStoredMnemonicRequest (line 1927) | type GetStoredMnemonicRequest struct
    method Reset (line 1933) | func (x *GetStoredMnemonicRequest) Reset() {
    method String (line 1942) | func (x *GetStoredMnemonicRequest) String() string {
    method ProtoMessage (line 1946) | func (*GetStoredMnemonicRequest) ProtoMessage() {}
    method ProtoReflect (line 1948) | func (x *GetStoredMnemonicRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 1961) | func (*GetStoredMnemonicRequest) Descriptor() ([]byte, []int) {
  type GetStoredMnemonicResponse (line 1965) | type GetStoredMnemonicResponse struct
    method Reset (line 1973) | func (x *GetStoredMnemonicResponse) Reset() {
    method String (line 1982) | func (x *GetStoredMnemonicResponse) String() string {
    method ProtoMessage (line 1986) | func (*GetStoredMnemonicResponse) ProtoMessage() {}
    method ProtoReflect (line 1988) | func (x *GetStoredMnemonicResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2001) | func (*GetStoredMnemonicResponse) Descriptor() ([]byte, []int) {
    method GetMnemonic (line 2005) | func (x *GetStoredMnemonicResponse) GetMnemonic() string {
  type RestoreKeyPairViaMnemonicRequest (line 2012) | type RestoreKeyPairViaMnemonicRequest struct
    method Reset (line 2020) | func (x *RestoreKeyPairViaMnemonicRequest) Reset() {
    method String (line 2029) | func (x *RestoreKeyPairViaMnemonicRequest) String() string {
    method ProtoMessage (line 2033) | func (*RestoreKeyPairViaMnemonicRequest) ProtoMessage() {}
    method ProtoReflect (line 2035) | func (x *RestoreKeyPairViaMnemonicRequest) ProtoReflect() protoreflect...
    method Descriptor (line 2048) | func (*RestoreKeyPairViaMnemonicRequest) Descriptor() ([]byte, []int) {
    method GetMnemonic (line 2052) | func (x *RestoreKeyPairViaMnemonicRequest) GetMnemonic() string {
  type RestoreKeyPairViaMnemonicResponse (line 2059) | type RestoreKeyPairViaMnemonicResponse struct
    method Reset (line 2065) | func (x *RestoreKeyPairViaMnemonicResponse) Reset() {
    method String (line 2074) | func (x *RestoreKeyPairViaMnemonicResponse) String() string {
    method ProtoMessage (line 2078) | func (*RestoreKeyPairViaMnemonicResponse) ProtoMessage() {}
    method ProtoReflect (line 2080) | func (x *RestoreKeyPairViaMnemonicResponse) ProtoReflect() protoreflec...
    method Descriptor (line 2093) | func (*RestoreKeyPairViaMnemonicResponse) Descriptor() ([]byte, []int) {
  type FileEventResponse (line 2097) | type FileEventResponse struct
    method Reset (line 2108) | func (x *FileEventResponse) Reset() {
    method String (line 2117) | func (x *FileEventResponse) String() string {
    method ProtoMessage (line 2121) | func (*FileEventResponse) ProtoMessage() {}
    method ProtoReflect (line 2123) | func (x *FileEventResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2136) | func (*FileEventResponse) Descriptor() ([]byte, []int) {
    method GetType (line 2140) | func (x *FileEventResponse) GetType() EventType {
    method GetEntry (line 2147) | func (x *FileEventResponse) GetEntry() *ListDirectoryEntry {
    method GetBucket (line 2154) | func (x *FileEventResponse) GetBucket() string {
    method GetDbId (line 2161) | func (x *FileEventResponse) GetDbId() string {
  type TextileEventResponse (line 2168) | type TextileEventResponse struct
    method Reset (line 2176) | func (x *TextileEventResponse) Reset() {
    method String (line 2185) | func (x *TextileEventResponse) String() string {
    method ProtoMessage (line 2189) | func (*TextileEventResponse) ProtoMessage() {}
    method ProtoReflect (line 2191) | func (x *TextileEventResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2204) | func (*TextileEventResponse) Descriptor() ([]byte, []int) {
    method GetBucket (line 2208) | func (x *TextileEventResponse) GetBucket() string {
  type OpenFileRequest (line 2215) | type OpenFileRequest struct
    method Reset (line 2225) | func (x *OpenFileRequest) Reset() {
    method String (line 2234) | func (x *OpenFileRequest) String() string {
    method ProtoMessage (line 2238) | func (*OpenFileRequest) ProtoMessage() {}
    method ProtoReflect (line 2240) | func (x *OpenFileRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2253) | func (*OpenFileRequest) Descriptor() ([]byte, []int) {
    method GetPath (line 2257) | func (x *OpenFileRequest) GetPath() string {
    method GetBucket (line 2264) | func (x *OpenFileRequest) GetBucket() string {
    method GetDbId (line 2271) | func (x *OpenFileRequest) GetDbId() string {
  type OpenFileResponse (line 2278) | type OpenFileResponse struct
    method Reset (line 2286) | func (x *OpenFileResponse) Reset() {
    method String (line 2295) | func (x *OpenFileResponse) String() string {
    method ProtoMessage (line 2299) | func (*OpenFileResponse) ProtoMessage() {}
    method ProtoReflect (line 2301) | func (x *OpenFileResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2314) | func (*OpenFileResponse) Descriptor() ([]byte, []int) {
    method GetLocation (line 2318) | func (x *OpenFileResponse) GetLocation() string {
  type OpenPublicFileRequest (line 2325) | type OpenPublicFileRequest struct
    method Reset (line 2335) | func (x *OpenPublicFileRequest) Reset() {
    method String (line 2344) | func (x *OpenPublicFileRequest) String() string {
    method ProtoMessage (line 2348) | func (*OpenPublicFileRequest) ProtoMessage() {}
    method ProtoReflect (line 2350) | func (x *OpenPublicFileRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2363) | func (*OpenPublicFileRequest) Descriptor() ([]byte, []int) {
    method GetFileCid (line 2367) | func (x *OpenPublicFileRequest) GetFileCid() string {
    method GetPassword (line 2374) | func (x *OpenPublicFileRequest) GetPassword() string {
    method GetFilename (line 2381) | func (x *OpenPublicFileRequest) GetFilename() string {
  type OpenPublicFileResponse (line 2388) | type OpenPublicFileResponse struct
    method Reset (line 2396) | func (x *OpenPublicFileResponse) Reset() {
    method String (line 2405) | func (x *OpenPublicFileResponse) String() string {
    method ProtoMessage (line 2409) | func (*OpenPublicFileResponse) ProtoMessage() {}
    method ProtoReflect (line 2411) | func (x *OpenPublicFileResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2424) | func (*OpenPublicFileResponse) Descriptor() ([]byte, []int) {
    method GetLocation (line 2428) | func (x *OpenPublicFileResponse) GetLocation() string {
  type AddItemsRequest (line 2435) | type AddItemsRequest struct
    method Reset (line 2448) | func (x *AddItemsRequest) Reset() {
    method String (line 2457) | func (x *AddItemsRequest) String() string {
    method ProtoMessage (line 2461) | func (*AddItemsRequest) ProtoMessage() {}
    method ProtoReflect (line 2463) | func (x *AddItemsRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2476) | func (*AddItemsRequest) Descriptor() ([]byte, []int) {
    method GetSourcePaths (line 2480) | func (x *AddItemsRequest) GetSourcePaths() []string {
    method GetTargetPath (line 2487) | func (x *AddItemsRequest) GetTargetPath() string {
    method GetBucket (line 2494) | func (x *AddItemsRequest) GetBucket() string {
  type AddItemResult (line 2501) | type AddItemResult struct
    method Reset (line 2511) | func (x *AddItemResult) Reset() {
    method String (line 2520) | func (x *AddItemResult) String() string {
    method ProtoMessage (line 2524) | func (*AddItemResult) ProtoMessage() {}
    method ProtoReflect (line 2526) | func (x *AddItemResult) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2539) | func (*AddItemResult) Descriptor() ([]byte, []int) {
    method GetSourcePath (line 2543) | func (x *AddItemResult) GetSourcePath() string {
    method GetBucketPath (line 2550) | func (x *AddItemResult) GetBucketPath() string {
    method GetError (line 2557) | func (x *AddItemResult) GetError() string {
  type AddItemsResponse (line 2564) | type AddItemsResponse struct
    method Reset (line 2576) | func (x *AddItemsResponse) Reset() {
    method String (line 2585) | func (x *AddItemsResponse) String() string {
    method ProtoMessage (line 2589) | func (*AddItemsResponse) ProtoMessage() {}
    method ProtoReflect (line 2591) | func (x *AddItemsResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2604) | func (*AddItemsResponse) Descriptor() ([]byte, []int) {
    method GetResult (line 2608) | func (x *AddItemsResponse) GetResult() *AddItemResult {
    method GetTotalFiles (line 2615) | func (x *AddItemsResponse) GetTotalFiles() int64 {
    method GetTotalBytes (line 2622) | func (x *AddItemsResponse) GetTotalBytes() int64 {
    method GetCompletedFiles (line 2629) | func (x *AddItemsResponse) GetCompletedFiles() int64 {
    method GetCompletedBytes (line 2636) | func (x *AddItemsResponse) GetCompletedBytes() int64 {
  type CreateFolderRequest (line 2643) | type CreateFolderRequest struct
    method Reset (line 2654) | func (x *CreateFolderRequest) Reset() {
    method String (line 2663) | func (x *CreateFolderRequest) String() string {
    method ProtoMessage (line 2667) | func (*CreateFolderRequest) ProtoMessage() {}
    method ProtoReflect (line 2669) | func (x *CreateFolderRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2682) | func (*CreateFolderRequest) Descriptor() ([]byte, []int) {
    method GetPath (line 2686) | func (x *CreateFolderRequest) GetPath() string {
    method GetBucket (line 2693) | func (x *CreateFolderRequest) GetBucket() string {
  type CreateFolderResponse (line 2701) | type CreateFolderResponse struct
    method Reset (line 2707) | func (x *CreateFolderResponse) Reset() {
    method String (line 2716) | func (x *CreateFolderResponse) String() string {
    method ProtoMessage (line 2720) | func (*CreateFolderResponse) ProtoMessage() {}
    method ProtoReflect (line 2722) | func (x *CreateFolderResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2735) | func (*CreateFolderResponse) Descriptor() ([]byte, []int) {
  type BackupKeysByPassphraseRequest (line 2739) | type BackupKeysByPassphraseRequest struct
    method Reset (line 2749) | func (x *BackupKeysByPassphraseRequest) Reset() {
    method String (line 2758) | func (x *BackupKeysByPassphraseRequest) String() string {
    method ProtoMessage (line 2762) | func (*BackupKeysByPassphraseRequest) ProtoMessage() {}
    method ProtoReflect (line 2764) | func (x *BackupKeysByPassphraseRequest) ProtoReflect() protoreflect.Me...
    method Descriptor (line 2777) | func (*BackupKeysByPassphraseRequest) Descriptor() ([]byte, []int) {
    method GetUuid (line 2781) | func (x *BackupKeysByPassphraseRequest) GetUuid() string {
    method GetPassphrase (line 2788) | func (x *BackupKeysByPassphraseRequest) GetPassphrase() string {
    method GetType (line 2795) | func (x *BackupKeysByPassphraseRequest) GetType() KeyBackupType {
  type BackupKeysByPassphraseResponse (line 2802) | type BackupKeysByPassphraseResponse struct
    method Reset (line 2808) | func (x *BackupKeysByPassphraseResponse) Reset() {
    method String (line 2817) | func (x *BackupKeysByPassphraseResponse) String() string {
    method ProtoMessage (line 2821) | func (*BackupKeysByPassphraseResponse) ProtoMessage() {}
    method ProtoReflect (line 2823) | func (x *BackupKeysByPassphraseResponse) ProtoReflect() protoreflect.M...
    method Descriptor (line 2836) | func (*BackupKeysByPassphraseResponse) Descriptor() ([]byte, []int) {
  type RecoverKeysByPassphraseRequest (line 2840) | type RecoverKeysByPassphraseRequest struct
    method Reset (line 2850) | func (x *RecoverKeysByPassphraseRequest) Reset() {
    method String (line 2859) | func (x *RecoverKeysByPassphraseRequest) String() string {
    method ProtoMessage (line 2863) | func (*RecoverKeysByPassphraseRequest) ProtoMessage() {}
    method ProtoReflect (line 2865) | func (x *RecoverKeysByPassphraseRequest) ProtoReflect() protoreflect.M...
    method Descriptor (line 2878) | func (*RecoverKeysByPassphraseRequest) Descriptor() ([]byte, []int) {
    method GetUuid (line 2882) | func (x *RecoverKeysByPassphraseRequest) GetUuid() string {
    method GetPassphrase (line 2889) | func (x *RecoverKeysByPassphraseRequest) GetPassphrase() string {
    method GetType (line 2896) | func (x *RecoverKeysByPassphraseRequest) GetType() KeyBackupType {
  type RecoverKeysByPassphraseResponse (line 2903) | type RecoverKeysByPassphraseResponse struct
    method Reset (line 2909) | func (x *RecoverKeysByPassphraseResponse) Reset() {
    method String (line 2918) | func (x *RecoverKeysByPassphraseResponse) String() string {
    method ProtoMessage (line 2922) | func (*RecoverKeysByPassphraseResponse) ProtoMessage() {}
    method ProtoReflect (line 2924) | func (x *RecoverKeysByPassphraseResponse) ProtoReflect() protoreflect....
    method Descriptor (line 2937) | func (*RecoverKeysByPassphraseResponse) Descriptor() ([]byte, []int) {
  type TestKeysPassphraseRequest (line 2941) | type TestKeysPassphraseRequest struct
    method Reset (line 2950) | func (x *TestKeysPassphraseRequest) Reset() {
    method String (line 2959) | func (x *TestKeysPassphraseRequest) String() string {
    method ProtoMessage (line 2963) | func (*TestKeysPassphraseRequest) ProtoMessage() {}
    method ProtoReflect (line 2965) | func (x *TestKeysPassphraseRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 2978) | func (*TestKeysPassphraseRequest) Descriptor() ([]byte, []int) {
    method GetUuid (line 2982) | func (x *TestKeysPassphraseRequest) GetUuid() string {
    method GetPassphrase (line 2989) | func (x *TestKeysPassphraseRequest) GetPassphrase() string {
  type TestKeysPassphraseResponse (line 2996) | type TestKeysPassphraseResponse struct
    method Reset (line 3002) | func (x *TestKeysPassphraseResponse) Reset() {
    method String (line 3011) | func (x *TestKeysPassphraseResponse) String() string {
    method ProtoMessage (line 3015) | func (*TestKeysPassphraseResponse) ProtoMessage() {}
    method ProtoReflect (line 3017) | func (x *TestKeysPassphraseResponse) ProtoReflect() protoreflect.Messa...
    method Descriptor (line 3030) | func (*TestKeysPassphraseResponse) Descriptor() ([]byte, []int) {
  type ThreadInfo (line 3034) | type ThreadInfo struct
    method Reset (line 3043) | func (x *ThreadInfo) Reset() {
    method String (line 3052) | func (x *ThreadInfo) String() string {
    method ProtoMessage (line 3056) | func (*ThreadInfo) ProtoMessage() {}
    method ProtoReflect (line 3058) | func (x *ThreadInfo) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3071) | func (*ThreadInfo) Descriptor() ([]byte, []int) {
    method GetAddresses (line 3075) | func (x *ThreadInfo) GetAddresses() []string {
    method GetKey (line 3082) | func (x *ThreadInfo) GetKey() string {
  type ShareBucketRequest (line 3089) | type ShareBucketRequest struct
    method Reset (line 3097) | func (x *ShareBucketRequest) Reset() {
    method String (line 3106) | func (x *ShareBucketRequest) String() string {
    method ProtoMessage (line 3110) | func (*ShareBucketRequest) ProtoMessage() {}
    method ProtoReflect (line 3112) | func (x *ShareBucketRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3125) | func (*ShareBucketRequest) Descriptor() ([]byte, []int) {
    method GetBucket (line 3129) | func (x *ShareBucketRequest) GetBucket() string {
  type ShareBucketResponse (line 3136) | type ShareBucketResponse struct
    method Reset (line 3144) | func (x *ShareBucketResponse) Reset() {
    method String (line 3153) | func (x *ShareBucketResponse) String() string {
    method ProtoMessage (line 3157) | func (*ShareBucketResponse) ProtoMessage() {}
    method ProtoReflect (line 3159) | func (x *ShareBucketResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3172) | func (*ShareBucketResponse) Descriptor() ([]byte, []int) {
    method GetThreadinfo (line 3176) | func (x *ShareBucketResponse) GetThreadinfo() *ThreadInfo {
  type JoinBucketRequest (line 3183) | type JoinBucketRequest struct
    method Reset (line 3192) | func (x *JoinBucketRequest) Reset() {
    method String (line 3201) | func (x *JoinBucketRequest) String() string {
    method ProtoMessage (line 3205) | func (*JoinBucketRequest) ProtoMessage() {}
    method ProtoReflect (line 3207) | func (x *JoinBucketRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3220) | func (*JoinBucketRequest) Descriptor() ([]byte, []int) {
    method GetThreadinfo (line 3224) | func (x *JoinBucketRequest) GetThreadinfo() *ThreadInfo {
    method GetBucket (line 3231) | func (x *JoinBucketRequest) GetBucket() string {
  type JoinBucketResponse (line 3238) | type JoinBucketResponse struct
    method Reset (line 3246) | func (x *JoinBucketResponse) Reset() {
    method String (line 3255) | func (x *JoinBucketResponse) String() string {
    method ProtoMessage (line 3259) | func (*JoinBucketResponse) ProtoMessage() {}
    method ProtoReflect (line 3261) | func (x *JoinBucketResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3274) | func (*JoinBucketResponse) Descriptor() ([]byte, []int) {
    method GetResult (line 3278) | func (x *JoinBucketResponse) GetResult() bool {
  type ShareFilesViaPublicKeyRequest (line 3285) | type ShareFilesViaPublicKeyRequest struct
    method Reset (line 3294) | func (x *ShareFilesViaPublicKeyRequest) Reset() {
    method String (line 3303) | func (x *ShareFilesViaPublicKeyRequest) String() string {
    method ProtoMessage (line 3307) | func (*ShareFilesViaPublicKeyRequest) ProtoMessage() {}
    method ProtoReflect (line 3309) | func (x *ShareFilesViaPublicKeyRequest) ProtoReflect() protoreflect.Me...
    method Descriptor (line 3322) | func (*ShareFilesViaPublicKeyRequest) Descriptor() ([]byte, []int) {
    method GetPublicKeys (line 3326) | func (x *ShareFilesViaPublicKeyRequest) GetPublicKeys() []string {
    method GetPaths (line 3333) | func (x *ShareFilesViaPublicKeyRequest) GetPaths() []*FullPath {
  type FullPath (line 3340) | type FullPath struct
    method Reset (line 3350) | func (x *FullPath) Reset() {
    method String (line 3359) | func (x *FullPath) String() string {
    method ProtoMessage (line 3363) | func (*FullPath) ProtoMessage() {}
    method ProtoReflect (line 3365) | func (x *FullPath) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3378) | func (*FullPath) Descriptor() ([]byte, []int) {
    method GetDbId (line 3382) | func (x *FullPath) GetDbId() string {
    method GetBucket (line 3389) | func (x *FullPath) GetBucket() string {
    method GetPath (line 3396) | func (x *FullPath) GetPath() string {
  type ShareFilesViaPublicKeyResponse (line 3403) | type ShareFilesViaPublicKeyResponse struct
    method Reset (line 3409) | func (x *ShareFilesViaPublicKeyResponse) Reset() {
    method String (line 3418) | func (x *ShareFilesViaPublicKeyResponse) String() string {
    method ProtoMessage (line 3422) | func (*ShareFilesViaPublicKeyResponse) ProtoMessage() {}
    method ProtoReflect (line 3424) | func (x *ShareFilesViaPublicKeyResponse) ProtoReflect() protoreflect.M...
    method Descriptor (line 3437) | func (*ShareFilesViaPublicKeyResponse) Descriptor() ([]byte, []int) {
  type UnshareFilesViaPublicKeyRequest (line 3441) | type UnshareFilesViaPublicKeyRequest struct
    method Reset (line 3450) | func (x *UnshareFilesViaPublicKeyRequest) Reset() {
    method String (line 3459) | func (x *UnshareFilesViaPublicKeyRequest) String() string {
    method ProtoMessage (line 3463) | func (*UnshareFilesViaPublicKeyRequest) ProtoMessage() {}
    method ProtoReflect (line 3465) | func (x *UnshareFilesViaPublicKeyRequest) ProtoReflect() protoreflect....
    method Descriptor (line 3478) | func (*UnshareFilesViaPublicKeyRequest) Descriptor() ([]byte, []int) {
    method GetPublicKeys (line 3482) | func (x *UnshareFilesViaPublicKeyRequest) GetPublicKeys() []string {
    method GetPaths (line 3489) | func (x *UnshareFilesViaPublicKeyRequest) GetPaths() []*FullPath {
  type UnshareFilesViaPublicKeyResponse (line 3496) | type UnshareFilesViaPublicKeyResponse struct
    method Reset (line 3502) | func (x *UnshareFilesViaPublicKeyResponse) Reset() {
    method String (line 3511) | func (x *UnshareFilesViaPublicKeyResponse) String() string {
    method ProtoMessage (line 3515) | func (*UnshareFilesViaPublicKeyResponse) ProtoMessage() {}
    method ProtoReflect (line 3517) | func (x *UnshareFilesViaPublicKeyResponse) ProtoReflect() protoreflect...
    method Descriptor (line 3530) | func (*UnshareFilesViaPublicKeyResponse) Descriptor() ([]byte, []int) {
  type GeneratePublicFileLinkRequest (line 3534) | type GeneratePublicFileLinkRequest struct
    method Reset (line 3547) | func (x *GeneratePublicFileLinkRequest) Reset() {
    method String (line 3556) | func (x *GeneratePublicFileLinkRequest) String() string {
    method ProtoMessage (line 3560) | func (*GeneratePublicFileLinkRequest) ProtoMessage() {}
    method ProtoReflect (line 3562) | func (x *GeneratePublicFileLinkRequest) ProtoReflect() protoreflect.Me...
    method Descriptor (line 3575) | func (*GeneratePublicFileLinkRequest) Descriptor() ([]byte, []int) {
    method GetBucket (line 3579) | func (x *GeneratePublicFileLinkRequest) GetBucket() string {
    method GetItemPaths (line 3586) | func (x *GeneratePublicFileLinkRequest) GetItemPaths() []string {
    method GetPassword (line 3593) | func (x *GeneratePublicFileLinkRequest) GetPassword() string {
    method GetDbId (line 3600) | func (x *GeneratePublicFileLinkRequest) GetDbId() string {
  type GeneratePublicFileLinkResponse (line 3607) | type GeneratePublicFileLinkResponse struct
    method Reset (line 3616) | func (x *GeneratePublicFileLinkResponse) Reset() {
    method String (line 3625) | func (x *GeneratePublicFileLinkResponse) String() string {
    method ProtoMessage (line 3629) | func (*GeneratePublicFileLinkResponse) ProtoMessage() {}
    method ProtoReflect (line 3631) | func (x *GeneratePublicFileLinkResponse) ProtoReflect() protoreflect.M...
    method Descriptor (line 3644) | func (*GeneratePublicFileLinkResponse) Descriptor() ([]byte, []int) {
    method GetLink (line 3648) | func (x *GeneratePublicFileLinkResponse) GetLink() string {
    method GetFileCid (line 3655) | func (x *GeneratePublicFileLinkResponse) GetFileCid() string {
  type ToggleFuseRequest (line 3662) | type ToggleFuseRequest struct
    method Reset (line 3670) | func (x *ToggleFuseRequest) Reset() {
    method String (line 3679) | func (x *ToggleFuseRequest) String() string {
    method ProtoMessage (line 3683) | func (*ToggleFuseRequest) ProtoMessage() {}
    method ProtoReflect (line 3685) | func (x *ToggleFuseRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3698) | func (*ToggleFuseRequest) Descriptor() ([]byte, []int) {
    method GetMountDrive (line 3702) | func (x *ToggleFuseRequest) GetMountDrive() bool {
  type FuseDriveResponse (line 3709) | type FuseDriveResponse struct
    method Reset (line 3718) | func (x *FuseDriveResponse) Reset() {
    method String (line 3727) | func (x *FuseDriveResponse) String() string {
    method ProtoMessage (line 3731) | func (*FuseDriveResponse) ProtoMessage() {}
    method ProtoReflect (line 3733) | func (x *FuseDriveResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3746) | func (*FuseDriveResponse) Descriptor() ([]byte, []int) {
    method GetState (line 3750) | func (x *FuseDriveResponse) GetState() FuseState {
    method GetMountPath (line 3757) | func (x *FuseDriveResponse) GetMountPath() string {
  type ListBucketsRequest (line 3764) | type ListBucketsRequest struct
    method Reset (line 3770) | func (x *ListBucketsRequest) Reset() {
    method String (line 3779) | func (x *ListBucketsRequest) String() string {
    method ProtoMessage (line 3783) | func (*ListBucketsRequest) ProtoMessage() {}
    method ProtoReflect (line 3785) | func (x *ListBucketsRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3798) | func (*ListBucketsRequest) Descriptor() ([]byte, []int) {
  type ListBucketsResponse (line 3802) | type ListBucketsResponse struct
    method Reset (line 3810) | func (x *ListBucketsResponse) Reset() {
    method String (line 3819) | func (x *ListBucketsResponse) String() string {
    method ProtoMessage (line 3823) | func (*ListBucketsResponse) ProtoMessage() {}
    method ProtoReflect (line 3825) | func (x *ListBucketsResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3838) | func (*ListBucketsResponse) Descriptor() ([]byte, []int) {
    method GetBuckets (line 3842) | func (x *ListBucketsResponse) GetBuckets() []*Bucket {
  type Invitation (line 3849) | type Invitation struct
    method Reset (line 3860) | func (x *Invitation) Reset() {
    method String (line 3869) | func (x *Invitation) String() string {
    method ProtoMessage (line 3873) | func (*Invitation) ProtoMessage() {}
    method ProtoReflect (line 3875) | func (x *Invitation) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3888) | func (*Invitation) Descriptor() ([]byte, []int) {
    method GetInviterPublicKey (line 3892) | func (x *Invitation) GetInviterPublicKey() string {
    method GetInvitationID (line 3899) | func (x *Invitation) GetInvitationID() string {
    method GetStatus (line 3906) | func (x *Invitation) GetStatus() InvitationStatus {
    method GetItemPaths (line 3913) | func (x *Invitation) GetItemPaths() []*FullPath {
  type UsageAlert (line 3920) | type UsageAlert struct
    method Reset (line 3930) | func (x *UsageAlert) Reset() {
    method String (line 3939) | func (x *UsageAlert) String() string {
    method ProtoMessage (line 3943) | func (*UsageAlert) ProtoMessage() {}
    method ProtoReflect (line 3945) | func (x *UsageAlert) ProtoReflect() protoreflect.Message {
    method Descriptor (line 3958) | func (*UsageAlert) Descriptor() ([]byte, []int) {
    method GetUsed (line 3962) | func (x *UsageAlert) GetUsed() int64 {
    method GetLimit (line 3969) | func (x *UsageAlert) GetLimit() int64 {
    method GetMessage (line 3976) | func (x *UsageAlert) GetMessage() string {
  type InvitationAccept (line 3983) | type InvitationAccept struct
    method Reset (line 3991) | func (x *InvitationAccept) Reset() {
    method String (line 4000) | func (x *InvitationAccept) String() string {
    method ProtoMessage (line 4004) | func (*InvitationAccept) ProtoMessage() {}
    method ProtoReflect (line 4006) | func (x *InvitationAccept) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4019) | func (*InvitationAccept) Descriptor() ([]byte, []int) {
    method GetInvitationID (line 4023) | func (x *InvitationAccept) GetInvitationID() string {
  type RevokedInvitation (line 4030) | type RevokedInvitation struct
    method Reset (line 4039) | func (x *RevokedInvitation) Reset() {
    method String (line 4048) | func (x *RevokedInvitation) String() string {
    method ProtoMessage (line 4052) | func (*RevokedInvitation) ProtoMessage() {}
    method ProtoReflect (line 4054) | func (x *RevokedInvitation) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4067) | func (*RevokedInvitation) Descriptor() ([]byte, []int) {
    method GetInviterPublicKey (line 4071) | func (x *RevokedInvitation) GetInviterPublicKey() string {
    method GetItemPaths (line 4078) | func (x *RevokedInvitation) GetItemPaths() []*FullPath {
  type Notification (line 4085) | type Notification struct
    method Reset (line 4104) | func (x *Notification) Reset() {
    method String (line 4113) | func (x *Notification) String() string {
    method ProtoMessage (line 4117) | func (*Notification) ProtoMessage() {}
    method ProtoReflect (line 4119) | func (x *Notification) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4132) | func (*Notification) Descriptor() ([]byte, []int) {
    method GetID (line 4136) | func (x *Notification) GetID() string {
    method GetSubject (line 4143) | func (x *Notification) GetSubject() string {
    method GetBody (line 4150) | func (x *Notification) GetBody() string {
    method GetRelatedObject (line 4157) | func (m *Notification) GetRelatedObject() isNotification_RelatedObject {
    method GetInvitationValue (line 4164) | func (x *Notification) GetInvitationValue() *Invitation {
    method GetUsageAlert (line 4171) | func (x *Notification) GetUsageAlert() *UsageAlert {
    method GetInvitationAccept (line 4178) | func (x *Notification) GetInvitationAccept() *InvitationAccept {
    method GetRevokedInvitation (line 4185) | func (x *Notification) GetRevokedInvitation() *RevokedInvitation {
    method GetType (line 4192) | func (x *Notification) GetType() NotificationType {
    method GetCreatedAt (line 4199) | func (x *Notification) GetCreatedAt() int64 {
    method GetReadAt (line 4206) | func (x *Notification) GetReadAt() int64 {
  type isNotification_RelatedObject (line 4213) | type isNotification_RelatedObject interface
  type Notification_InvitationValue (line 4217) | type Notification_InvitationValue struct
    method isNotification_RelatedObject (line 4233) | func (*Notification_InvitationValue) isNotification_RelatedObject() {}
  type Notification_UsageAlert (line 4221) | type Notification_UsageAlert struct
    method isNotification_RelatedObject (line 4235) | func (*Notification_UsageAlert) isNotification_RelatedObject() {}
  type Notification_InvitationAccept (line 4225) | type Notification_InvitationAccept struct
    method isNotification_RelatedObject (line 4237) | func (*Notification_InvitationAccept) isNotification_RelatedObject() {}
  type Notification_RevokedInvitation (line 4229) | type Notification_RevokedInvitation struct
    method isNotification_RelatedObject (line 4239) | func (*Notification_RevokedInvitation) isNotification_RelatedObject() {}
  type HandleFilesInvitationRequest (line 4241) | type HandleFilesInvitationRequest struct
    method Reset (line 4250) | func (x *HandleFilesInvitationRequest) Reset() {
    method String (line 4259) | func (x *HandleFilesInvitationRequest) String() string {
    method ProtoMessage (line 4263) | func (*HandleFilesInvitationRequest) ProtoMessage() {}
    method ProtoReflect (line 4265) | func (x *HandleFilesInvitationRequest) ProtoReflect() protoreflect.Mes...
    method Descriptor (line 4278) | func (*HandleFilesInvitationRequest) Descriptor() ([]byte, []int) {
    method GetInvitationID (line 4282) | func (x *HandleFilesInvitationRequest) GetInvitationID() string {
    method GetAccept (line 4289) | func (x *HandleFilesInvitationRequest) GetAccept() bool {
  type HandleFilesInvitationResponse (line 4296) | type HandleFilesInvitationResponse struct
    method Reset (line 4302) | func (x *HandleFilesInvitationResponse) Reset() {
    method String (line 4311) | func (x *HandleFilesInvitationResponse) String() string {
    method ProtoMessage (line 4315) | func (*HandleFilesInvitationResponse) ProtoMessage() {}
    method ProtoReflect (line 4317) | func (x *HandleFilesInvitationResponse) ProtoReflect() protoreflect.Me...
    method Descriptor (line 4330) | func (*HandleFilesInvitationResponse) Descriptor() ([]byte, []int) {
  type NotificationEventResponse (line 4334) | type NotificationEventResponse struct
    method Reset (line 4342) | func (x *NotificationEventResponse) Reset() {
    method String (line 4351) | func (x *NotificationEventResponse) String() string {
    method ProtoMessage (line 4355) | func (*NotificationEventResponse) ProtoMessage() {}
    method ProtoReflect (line 4357) | func (x *NotificationEventResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4370) | func (*NotificationEventResponse) Descriptor() ([]byte, []int) {
    method GetNotification (line 4374) | func (x *NotificationEventResponse) GetNotification() *Notification {
  type GetNotificationsRequest (line 4381) | type GetNotificationsRequest struct
    method Reset (line 4390) | func (x *GetNotificationsRequest) Reset() {
    method String (line 4399) | func (x *GetNotificationsRequest) String() string {
    method ProtoMessage (line 4403) | func (*GetNotificationsRequest) ProtoMessage() {}
    method ProtoReflect (line 4405) | func (x *GetNotificationsRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4418) | func (*GetNotificationsRequest) Descriptor() ([]byte, []int) {
    method GetSeek (line 4422) | func (x *GetNotificationsRequest) GetSeek() string {
    method GetLimit (line 4429) | func (x *GetNotificationsRequest) GetLimit() int64 {
  type GetNotificationsResponse (line 4436) | type GetNotificationsResponse struct
    method Reset (line 4446) | func (x *GetNotificationsResponse) Reset() {
    method String (line 4455) | func (x *GetNotificationsResponse) String() string {
    method ProtoMessage (line 4459) | func (*GetNotificationsResponse) ProtoMessage() {}
    method ProtoReflect (line 4461) | func (x *GetNotificationsResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4474) | func (*GetNotificationsResponse) Descriptor() ([]byte, []int) {
    method GetNotifications (line 4478) | func (x *GetNotificationsResponse) GetNotifications() []*Notification {
    method GetNextOffset (line 4485) | func (x *GetNotificationsResponse) GetNextOffset() string {
    method GetLastSeenAt (line 4492) | func (x *GetNotificationsResponse) GetLastSeenAt() int64 {
  type ReadNotificationRequest (line 4499) | type ReadNotificationRequest struct
    method Reset (line 4507) | func (x *ReadNotificationRequest) Reset() {
    method String (line 4516) | func (x *ReadNotificationRequest) String() string {
    method ProtoMessage (line 4520) | func (*ReadNotificationRequest) ProtoMessage() {}
    method ProtoReflect (line 4522) | func (x *ReadNotificationRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4535) | func (*ReadNotificationRequest) Descriptor() ([]byte, []int) {
    method GetID (line 4539) | func (x *ReadNotificationRequest) GetID() string {
  type ReadNotificationResponse (line 4546) | type ReadNotificationResponse struct
    method Reset (line 4552) | func (x *ReadNotificationResponse) Reset() {
    method String (line 4561) | func (x *ReadNotificationResponse) String() string {
    method ProtoMessage (line 4565) | func (*ReadNotificationResponse) ProtoMessage() {}
    method ProtoReflect (line 4567) | func (x *ReadNotificationResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4580) | func (*ReadNotificationResponse) Descriptor() ([]byte, []int) {
  type GetPublicKeyRequest (line 4584) | type GetPublicKeyRequest struct
    method Reset (line 4590) | func (x *GetPublicKeyRequest) Reset() {
    method String (line 4599) | func (x *GetPublicKeyRequest) String() string {
    method ProtoMessage (line 4603) | func (*GetPublicKeyRequest) ProtoMessage() {}
    method ProtoReflect (line 4605) | func (x *GetPublicKeyRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4618) | func (*GetPublicKeyRequest) Descriptor() ([]byte, []int) {
  type GetPublicKeyResponse (line 4622) | type GetPublicKeyResponse struct
    method Reset (line 4631) | func (x *GetPublicKeyResponse) Reset() {
    method String (line 4640) | func (x *GetPublicKeyResponse) String() string {
    method ProtoMessage (line 4644) | func (*GetPublicKeyResponse) ProtoMessage() {}
    method ProtoReflect (line 4646) | func (x *GetPublicKeyResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4659) | func (*GetPublicKeyResponse) Descriptor() ([]byte, []int) {
    method GetPublicKey (line 4663) | func (x *GetPublicKeyResponse) GetPublicKey() string {
  type RecoverKeysByLocalBackupRequest (line 4670) | type RecoverKeysByLocalBackupRequest struct
    method Reset (line 4678) | func (x *RecoverKeysByLocalBackupRequest) Reset() {
    method String (line 4687) | func (x *RecoverKeysByLocalBackupRequest) String() string {
    method ProtoMessage (line 4691) | func (*RecoverKeysByLocalBackupRequest) ProtoMessage() {}
    method ProtoReflect (line 4693) | func (x *RecoverKeysByLocalBackupRequest) ProtoReflect() protoreflect....
    method Descriptor (line 4706) | func (*RecoverKeysByLocalBackupRequest) Descriptor() ([]byte, []int) {
    method GetPathToKeyBackup (line 4710) | func (x *RecoverKeysByLocalBackupRequest) GetPathToKeyBackup() string {
  type RecoverKeysByLocalBackupResponse (line 4717) | type RecoverKeysByLocalBackupResponse struct
    method Reset (line 4723) | func (x *RecoverKeysByLocalBackupResponse) Reset() {
    method String (line 4732) | func (x *RecoverKeysByLocalBackupResponse) String() string {
    method ProtoMessage (line 4736) | func (*RecoverKeysByLocalBackupResponse) ProtoMessage() {}
    method ProtoReflect (line 4738) | func (x *RecoverKeysByLocalBackupResponse) ProtoReflect() protoreflect...
    method Descriptor (line 4751) | func (*RecoverKeysByLocalBackupResponse) Descriptor() ([]byte, []int) {
  type CreateLocalKeysBackupRequest (line 4755) | type CreateLocalKeysBackupRequest struct
    method Reset (line 4764) | func (x *CreateLocalKeysBackupRequest) Reset() {
    method String (line 4773) | func (x *CreateLocalKeysBackupRequest) String() string {
    method ProtoMessage (line 4777) | func (*CreateLocalKeysBackupRequest) ProtoMessage() {}
    method ProtoReflect (line 4779) | func (x *CreateLocalKeysBackupRequest) ProtoReflect() protoreflect.Mes...
    method Descriptor (line 4792) | func (*CreateLocalKeysBackupRequest) Descriptor() ([]byte, []int) {
    method GetPathToKeyBackup (line 4796) | func (x *CreateLocalKeysBackupRequest) GetPathToKeyBackup() string {
  type CreateLocalKeysBackupResponse (line 4803) | type CreateLocalKeysBackupResponse struct
    method Reset (line 4809) | func (x *CreateLocalKeysBackupResponse) Reset() {
    method String (line 4818) | func (x *CreateLocalKeysBackupResponse) String() string {
    method ProtoMessage (line 4822) | func (*CreateLocalKeysBackupResponse) ProtoMessage() {}
    method ProtoReflect (line 4824) | func (x *CreateLocalKeysBackupResponse) ProtoReflect() protoreflect.Me...
    method Descriptor (line 4837) | func (*CreateLocalKeysBackupResponse) Descriptor() ([]byte, []int) {
  type DeleteAccountRequest (line 4841) | type DeleteAccountRequest struct
    method Reset (line 4847) | func (x *DeleteAccountRequest) Reset() {
    method String (line 4856) | func (x *DeleteAccountRequest) String() string {
    method ProtoMessage (line 4860) | func (*DeleteAccountRequest) ProtoMessage() {}
    method ProtoReflect (line 4862) | func (x *DeleteAccountRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4875) | func (*DeleteAccountRequest) Descriptor() ([]byte, []int) {
  type DeleteAccountResponse (line 4879) | type DeleteAccountResponse struct
    method Reset (line 4885) | func (x *DeleteAccountResponse) Reset() {
    method String (line 4894) | func (x *DeleteAccountResponse) String() string {
    method ProtoMessage (line 4898) | func (*DeleteAccountResponse) ProtoMessage() {}
    method ProtoReflect (line 4900) | func (x *DeleteAccountResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4913) | func (*DeleteAccountResponse) Descriptor() ([]byte, []int) {
  type DeleteKeyPairRequest (line 4917) | type DeleteKeyPairRequest struct
    method Reset (line 4923) | func (x *DeleteKeyPairRequest) Reset() {
    method String (line 4932) | func (x *DeleteKeyPairRequest) String() string {
    method ProtoMessage (line 4936) | func (*DeleteKeyPairRequest) ProtoMessage() {}
    method ProtoReflect (line 4938) | func (x *DeleteKeyPairRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4951) | func (*DeleteKeyPairRequest) Descriptor() ([]byte, []int) {
  type DeleteKeyPairResponse (line 4955) | type DeleteKeyPairResponse struct
    method Reset (line 4961) | func (x *DeleteKeyPairResponse) Reset() {
    method String (line 4970) | func (x *DeleteKeyPairResponse) String() string {
    method ProtoMessage (line 4974) | func (*DeleteKeyPairResponse) ProtoMessage() {}
    method ProtoReflect (line 4976) | func (x *DeleteKeyPairResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 4989) | func (*DeleteKeyPairResponse) Descriptor() ([]byte, []int) {
  type GetAPISessionTokensRequest (line 4993) | type GetAPISessionTokensRequest struct
    method Reset (line 4999) | func (x *GetAPISessionTokensRequest) Reset() {
    method String (line 5008) | func (x *GetAPISessionTokensRequest) String() string {
    method ProtoMessage (line 5012) | func (*GetAPISessionTokensRequest) ProtoMessage() {}
    method ProtoReflect (line 5014) | func (x *GetAPISessionTokensRequest) ProtoReflect() protoreflect.Messa...
    method Descriptor (line 5027) | func (*GetAPISessionTokensRequest) Descriptor() ([]byte, []int) {
  type GetAPISessionTokensResponse (line 5031) | type GetAPISessionTokensResponse struct
    method Reset (line 5040) | func (x *GetAPISessionTokensResponse) Reset() {
    method String (line 5049) | func (x *GetAPISessionTokensResponse) String() string {
    method ProtoMessage (line 5053) | func (*GetAPISessionTokensResponse) ProtoMessage() {}
    method ProtoReflect (line 5055) | func (x *GetAPISessionTokensResponse) ProtoReflect() protoreflect.Mess...
    method Descriptor (line 5068) | func (*GetAPISessionTokensResponse) Descriptor() ([]byte, []int) {
    method GetHubToken (line 5072) | func (x *GetAPISessionTokensResponse) GetHubToken() string {
    method GetServicesToken (line 5079) | func (x *GetAPISessionTokensResponse) GetServicesToken() string {
  type GetRecentlySharedWithRequest (line 5086) | type GetRecentlySharedWithRequest struct
    method Reset (line 5092) | func (x *GetRecentlySharedWithRequest) Reset() {
    method String (line 5101) | func (x *GetRecentlySharedWithRequest) String() string {
    method ProtoMessage (line 5105) | func (*GetRecentlySharedWithRequest) ProtoMessage() {}
    method ProtoReflect (line 5107) | func (x *GetRecentlySharedWithRequest) ProtoReflect() protoreflect.Mes...
    method Descriptor (line 5120) | func (*GetRecentlySharedWithRequest) Descriptor() ([]byte, []int) {
  type GetRecentlySharedWithResponse (line 5124) | type GetRecentlySharedWithResponse struct
    method Reset (line 5132) | func (x *GetRecentlySharedWithResponse) Reset() {
    method String (line 5141) | func (x *GetRecentlySharedWithResponse) String() string {
    method ProtoMessage (line 5145) | func (*GetRecentlySharedWithResponse) ProtoMessage() {}
    method ProtoReflect (line 5147) | func (x *GetRecentlySharedWithResponse) ProtoReflect() protoreflect.Me...
    method Descriptor (line 5160) | func (*GetRecentlySharedWithResponse) Descriptor() ([]byte, []int) {
    method GetMembers (line 5164) | func (x *GetRecentlySharedWithResponse) GetMembers() []*FileMember {
  type InitializeMasterAppTokenRequest (line 5171) | type InitializeMasterAppTokenRequest struct
    method Reset (line 5177) | func (x *InitializeMasterAppTokenRequest) Reset() {
    method String (line 5186) | func (x *InitializeMasterAppTokenRequest) String() string {
    method ProtoMessage (line 5190) | func (*InitializeMasterAppTokenRequest) ProtoMessage() {}
    method ProtoReflect (line 5192) | func (x *InitializeMasterAppTokenRequest) ProtoReflect() protoreflect....
    method Descriptor (line 5205) | func (*InitializeMasterAppTokenRequest) Descriptor() ([]byte, []int) {
  type InitializeMasterAppTokenResponse (line 5209) | type InitializeMasterAppTokenResponse struct
    method Reset (line 5217) | func (x *InitializeMasterAppTokenResponse) Reset() {
    method String (line 5226) | func (x *InitializeMasterAppTokenResponse) String() string {
    method ProtoMessage (line 5230) | func (*InitializeMasterAppTokenResponse) ProtoMessage() {}
    method ProtoReflect (line 5232) | func (x *InitializeMasterAppTokenResponse) ProtoReflect() protoreflect...
    method Descriptor (line 5245) | func (*InitializeMasterAppTokenResponse) Descriptor() ([]byte, []int) {
    method GetAppToken (line 5249) | func (x *InitializeMasterAppTokenResponse) GetAppToken() string {
  type AllowedMethod (line 5256) | type AllowedMethod struct
    method Reset (line 5264) | func (x *AllowedMethod) Reset() {
    method String (line 5273) | func (x *AllowedMethod) String() string {
    method ProtoMessage (line 5277) | func (*AllowedMethod) ProtoMessage() {}
    method ProtoReflect (line 5279) | func (x *AllowedMethod) ProtoReflect() protoreflect.Message {
    method Descriptor (line 5292) | func (*AllowedMethod) Descriptor() ([]byte, []int) {
    method GetMethodName (line 5296) | func (x *AllowedMethod) GetMethodName() string {
  type GenerateAppTokenRequest (line 5303) | type GenerateAppTokenRequest struct
    method Reset (line 5311) | func (x *GenerateAppTokenRequest) Reset() {
    method String (line 5320) | func (x *GenerateAppTokenRequest) String() string {
    method ProtoMessage (line 5324) | func (*GenerateAppTokenRequest) ProtoMessage() {}
    method ProtoReflect (line 5326) | func (x *GenerateAppTokenRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 5339) | func (*GenerateAppTokenRequest) Descriptor() ([]byte, []int) {
    method GetAllowedMethods (line 5343) | func (x *GenerateAppTokenRequest) GetAllowedMethods() []*AllowedMethod {
  type GenerateAppTokenResponse (line 5350) | type GenerateAppTokenResponse struct
    method Reset (line 5358) | func (x *GenerateAppTokenResponse) Reset() {
    method String (line 5367) | func (x *GenerateAppTokenResponse) String() string {
    method ProtoMessage (line 5371) | func (*GenerateAppTokenResponse) ProtoMessage() {}
    method ProtoReflect (line 5373) | func (x *GenerateAppTokenResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 5386) | func (*GenerateAppTokenResponse) Descriptor() ([]byte, []int) {
    method GetAppToken (line 5390) | func (x *GenerateAppTokenResponse) GetAppToken() string {
  type RemoveDirOrFileRequest (line 5397) | type RemoveDirOrFileRequest struct
    method Reset (line 5406) | func (x *RemoveDirOrFileRequest) Reset() {
    method String (line 5415) | func (x *RemoveDirOrFileRequest) String() string {
    method ProtoMessage (line 5419) | func (*RemoveDirOrFileRequest) ProtoMessage() {}
    method ProtoReflect (line 5421) | func (x *RemoveDirOrFileRequest) ProtoReflect() protoreflect.Message {
    method Descriptor (line 5434) | func (*RemoveDirOrFileRequest) Descriptor() ([]byte, []int) {
    method GetPath (line 5438) | func (x *RemoveDirOrFileRequest) GetPath() string {
    method GetBucket (line 5445) | func (x *RemoveDirOrFileRequest) GetBucket() string {
  type RemoveDirOrFileResponse (line 5452) | type RemoveDirOrFileResponse struct
    method Reset (line 5458) | func (x *RemoveDirOrFileResponse) Reset() {
    method String (line 5467) | func (x *RemoveDirOrFileResponse) String() string {
    method ProtoMessage (line 5471) | func (*RemoveDirOrFileResponse) ProtoMessage() {}
    method ProtoReflect (line 5473) | func (x *RemoveDirOrFileResponse) ProtoReflect() protoreflect.Message {
    method Descriptor (line 5486) | func (*RemoveDirOrFileResponse) Descriptor() ([]byte, []int) {
  function file_space_proto_rawDescGZIP (line 6378) | func file_space_proto_rawDescGZIP() []byte {
  function init (line 6624) | func init() { file_space_proto_init() }
  function file_space_proto_init (line 6625) | func file_space_proto_init() {
  constant _ (line 7840) | _ = grpc.SupportPackageIsVersion6
  type SpaceApiClient (line 7845) | type SpaceApiClient interface
  type spaceApiClient (line 7931) | type spaceApiClient struct
    method ListDirectories (line 7939) | func (c *spaceApiClient) ListDirectories(ctx context.Context, in *List...
    method ListDirectory (line 7948) | func (c *spaceApiClient) ListDirectory(ctx context.Context, in *ListDi...
    method GenerateKeyPair (line 7957) | func (c *spaceApiClient) GenerateKeyPair(ctx context.Context, in *Gene...
    method GetStoredMnemonic (line 7966) | func (c *spaceApiClient) GetStoredMnemonic(ctx context.Context, in *Ge...
    method RestoreKeyPairViaMnemonic (line 7975) | func (c *spaceApiClient) RestoreKeyPairViaMnemonic(ctx context.Context...
    method DeleteKeyPair (line 7984) | func (c *spaceApiClient) DeleteKeyPair(ctx context.Context, in *Delete...
    method GenerateKeyPairWithForce (line 7993) | func (c *spaceApiClient) GenerateKeyPairWithForce(ctx context.Context,...
    method GetPublicKey (line 8002) | func (c *spaceApiClient) GetPublicKey(ctx context.Context, in *GetPubl...
    method Subscribe (line 8011) | func (c *spaceApiClient) Subscribe(ctx context.Context, in *empty.Empt...
    method TxlSubscribe (line 8043) | func (c *spaceApiClient) TxlSubscribe(ctx context.Context, in *empty.E...
    method OpenFile (line 8075) | func (c *spaceApiClient) OpenFile(ctx context.Context, in *OpenFileReq...
    method RemoveDirOrFile (line 8084) | func (c *spaceApiClient) RemoveDirOrFile(ctx context.Context, in *Remo...
    method GeneratePublicFileLink (line 8093) | func (c *spaceApiClient) GeneratePublicFileLink(ctx context.Context, i...
    method GetSharedWithMeFiles (line 8102) | func (c *spaceApiClient) GetSharedWithMeFiles(ctx context.Context, in ...
    method GetSharedByMeFiles (line 8111) | func (c *spaceApiClient) GetSharedByMeFiles(ctx context.Context, in *G...
    method OpenPublicFile (line 8120) | func (c *spaceApiClient) OpenPublicFile(ctx context.Context, in *OpenP...
    method AddItems (line 8129) | func (c *spaceApiClient) AddItems(ctx context.Context, in *AddItemsReq...
    method CreateFolder (line 8161) | func (c *spaceApiClient) CreateFolder(ctx context.Context, in *CreateF...
    method ToggleFuseDrive (line 8170) | func (c *spaceApiClient) ToggleFuseDrive(ctx context.Context, in *Togg...
    method GetFuseDriveStatus (line 8179) | func (c *spaceApiClient) GetFuseDriveStatus(ctx context.Context, in *e...
    method CreateBucket (line 8188) | func (c *spaceApiClient) CreateBucket(ctx context.Context, in *CreateB...
    method BackupKeysByPassphrase (line 8197) | func (c *spaceApiClient) BackupKeysByPassphrase(ctx context.Context, i...
    method RecoverKeysByPassphrase (line 8206) | func (c *spaceApiClient) RecoverKeysByPassphrase(ctx context.Context, ...
    method TestKeysPassphrase (line 8215) | func (c *spaceApiClient) TestKeysPassphrase(ctx context.Context, in *T...
    method CreateLocalKeysBackup (line 8224) | func (c *spaceApiClient) CreateLocalKeysBackup(ctx context.Context, in...
    method RecoverKeysByLocalBackup (line 8233) | func (c *spaceApiClient) RecoverKeysByLocalBackup(ctx context.Context,...
    method ShareBucket (line 8242) | func (c *spaceApiClient) ShareBucket(ctx context.Context, in *ShareBuc...
    method JoinBucket (line 8251) | func (c *spaceApiClient) JoinBucket(ctx context.Context, in *JoinBucke...
    method ShareFilesViaPublicKey (line 8260) | func (c *spaceApiClient) ShareFilesViaPublicKey(ctx context.Context, i...
    method UnshareFilesViaPublicKey (line 8269) | func (c *spaceApiClient) UnshareFilesViaPublicKey(ctx context.Context,...
    method HandleFilesInvitation (line 8278) | func (c *spaceApiClient) HandleFilesInvitation(ctx context.Context, in...
    method NotificationSubscribe (line 8287) | func (c *spaceApiClient) NotificationSubscribe(ctx context.Context, in...
    method ListBuckets (line 8319) | func (c *spaceApiClient) ListBuckets(ctx context.Context, in *ListBuck...
    method GetNotifications (line 8328) | func (c *spaceApiClient) GetNotifications(ctx context.Context, in *Get...
    method ReadNotification (line 8337) | func (c *spaceApiClient) ReadNotification(ctx context.Context, in *Rea...
    method DeleteAccount (line 8346) | func (c *spaceApiClient) DeleteAccount(ctx context.Context, in *Delete...
    method ToggleBucketBackup (line 8355) | func (c *spaceApiClient) ToggleBucketBackup(ctx context.Context, in *T...
    method BucketBackupRestore (line 8364) | func (c *spaceApiClient) BucketBackupRestore(ctx context.Context, in *...
    method GetUsageInfo (line 8373) | func (c *spaceApiClient) GetUsageInfo(ctx context.Context, in *GetUsag...
    method GetAPISessionTokens (line 8382) | func (c *spaceApiClient) GetAPISessionTokens(ctx context.Context, in *...
    method GetRecentlySharedWith (line 8391) | func (c *spaceApiClient) GetRecentlySharedWith(ctx context.Context, in...
    method SetNotificationsLastSeenAt (line 8400) | func (c *spaceApiClient) SetNotificationsLastSeenAt(ctx context.Contex...
    method SearchFiles (line 8409) | func (c *spaceApiClient) SearchFiles(ctx context.Context, in *SearchFi...
    method InitializeMasterAppToken (line 8418) | func (c *spaceApiClient) InitializeMasterAppToken(ctx context.Context,...
    method GenerateAppToken (line 8427) | func (c *spaceApiClient) GenerateAppToken(ctx context.Context, in *Gen...
  function NewSpaceApiClient (line 7935) | func NewSpaceApiClient(cc grpc.ClientConnInterface) SpaceApiClient {
  type SpaceApi_SubscribeClient (line 8026) | type SpaceApi_SubscribeClient interface
  type spaceApiSubscribeClient (line 8031) | type spaceApiSubscribeClient struct
    method Recv (line 8035) | func (x *spaceApiSubscribeClient) Recv() (*FileEventResponse, error) {
  type SpaceApi_TxlSubscribeClient (line 8058) | type SpaceApi_TxlSubscribeClient interface
  type spaceApiTxlSubscribeClient (line 8063) | type spaceApiTxlSubscribeClient struct
    method Recv (line 8067) | func (x *spaceApiTxlSubscribeClient) Recv() (*TextileEventResponse, er...
  type SpaceApi_AddItemsClient (line 8144) | type SpaceApi_AddItemsClient interface
  type spaceApiAddItemsClient (line 8149) | type spaceApiAddItemsClient struct
    method Recv (line 8153) | func (x *spaceApiAddItemsClient) Recv() (*AddItemsResponse, error) {
  type SpaceApi_NotificationSubscribeClient (line 8302) | type SpaceApi_NotificationSubscribeClient interface
  type spaceApiNotificationSubscribeClient (line 8307) | type spaceApiNotificationSubscribeClient struct
    method Recv (line 8311) | func (x *spaceApiNotificationSubscribeClient) Recv() (*NotificationEve...
  type SpaceApiServer (line 8437) | type SpaceApiServer interface
  type UnimplementedSpaceApiServer (line 8524) | type UnimplementedSpaceApiServer struct
    method ListDirectories (line 8527) | func (*UnimplementedSpaceApiServer) ListDirectories(context.Context, *...
    method ListDirectory (line 8530) | func (*UnimplementedSpaceApiServer) ListDirectory(context.Context, *Li...
    method GenerateKeyPair (line 8533) | func (*UnimplementedSpaceApiServer) GenerateKeyPair(context.Context, *...
    method GetStoredMnemonic (line 8536) | func (*UnimplementedSpaceApiServer) GetStoredMnemonic(context.Context,...
    method RestoreKeyPairViaMnemonic (line 8539) | func (*UnimplementedSpaceApiServer) RestoreKeyPairViaMnemonic(context....
    method DeleteKeyPair (line 8542) | func (*UnimplementedSpaceApiServer) DeleteKeyPair(context.Context, *De...
    method GenerateKeyPairWithForce (line 8545) | func (*UnimplementedSpaceApiServer) GenerateKeyPairWithForce(context.C...
    method GetPublicKey (line 8548) | func (*UnimplementedSpaceApiServer) GetPublicKey(context.Context, *Get...
    method Subscribe (line 8551) | func (*UnimplementedSpaceApiServer) Subscribe(*empty.Empty, SpaceApi_S...
    method TxlSubscribe (line 8554) | func (*UnimplementedSpaceApiServer) TxlSubscribe(*empty.Empty, SpaceAp...
    method OpenFile (line 8557) | func (*UnimplementedSpaceApiServer) OpenFile(context.Context, *OpenFil...
    method RemoveDirOrFile (line 8560) | func (*UnimplementedSpaceApiServer) RemoveDirOrFile(context.Context, *...
    method GeneratePublicFileLink (line 8563) | func (*UnimplementedSpaceApiServer) GeneratePublicFileLink(context.Con...
    method GetSharedWithMeFiles (line 8566) | func (*UnimplementedSpaceApiServer) GetSharedWithMeFiles(context.Conte...
    method GetSharedByMeFiles (line 8569) | func (*UnimplementedSpaceApiServer) GetSharedByMeFiles(context.Context...
    method OpenPublicFile (line 8572) | func (*UnimplementedSpaceApiServer) OpenPublicFile(context.Context, *O...
    method AddItems (line 8575) | func (*UnimplementedSpaceApiServer) AddItems(*AddItemsRequest, SpaceAp...
    method CreateFolder (line 8578) | func (*UnimplementedSpaceApiServer) CreateFolder(context.Context, *Cre...
    method ToggleFuseDrive (line 8581) | func (*UnimplementedSpaceApiServer) ToggleFuseDrive(context.Context, *...
    method GetFuseDriveStatus (line 8584) | func (*UnimplementedSpaceApiServer) GetFuseDriveStatus(context.Context...
    method CreateBucket (line 8587) | func (*UnimplementedSpaceApiServer) CreateBucket(context.Context, *Cre...
    method BackupKeysByPassphrase (line 8590) | func (*UnimplementedSpaceApiServer) BackupKeysByPassphrase(context.Con...
    method RecoverKeysByPassphrase (line 8593) | func (*UnimplementedSpaceApiServer) RecoverKeysByPassphrase(context.Co...
    method TestKeysPassphrase (line 8596) | func (*UnimplementedSpaceApiServer) TestKeysPassphrase(context.Context...
    method CreateLocalKeysBackup (line 8599) | func (*UnimplementedSpaceApiServer) CreateLocalKeysBackup(context.Cont...
    method RecoverKeysByLocalBackup (line 8602) | func (*UnimplementedSpaceApiServer) RecoverKeysByLocalBackup(context.C...
    method ShareBucket (line 8605) | func (*UnimplementedSpaceApiServer) ShareBucket(context.Context, *Shar...
    method JoinBucket (line 8608) | func (*UnimplementedSpaceApiServer) JoinBucket(context.Context, *JoinB...
    method ShareFilesViaPublicKey (line 8611) | func (*UnimplementedSpaceApiServer) ShareFilesViaPublicKey(context.Con...
    method UnshareFilesViaPublicKey (line 8614) | func (*UnimplementedSpaceApiServer) UnshareFilesViaPublicKey(context.C...
    method HandleFilesInvitation (line 8617) | func (*UnimplementedSpaceApiServer) HandleFilesInvitation(context.Cont...
    method NotificationSubscribe (line 8620) | func (*UnimplementedSpaceApiServer) NotificationSubscribe(*empty.Empty...
    method ListBuckets (line 8623) | func (*UnimplementedSpaceApiServer) ListBuckets(
Condensed preview — 224 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,674K chars).
[
  {
    "path": ".github/workflows/release.yml",
    "chars": 3309,
    "preview": "name: Release with goreleaser\non:\n  push:\n    tags:\n      - v*.*.*\njobs:\n  build:\n    runs-on: macos-latest\n    name: go"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 3430,
    "preview": "#on: [push, pull_request]\non: [pull_request]\nname: Test\njobs:\n  unit-test:\n    strategy:\n      matrix:\n        go-versio"
  },
  {
    "path": ".gitignore",
    "chars": 400,
    "preview": "# 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# Ou"
  },
  {
    "path": ".goreleaser.yml",
    "chars": 3721,
    "preview": "# Make sure to check the documentation at http://goreleaser.com\nbefore:\n  hooks:\n    # You may remove this if you don't "
  },
  {
    "path": ".vscode/launch.json",
    "chars": 479,
    "preview": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  //"
  },
  {
    "path": "LICENSE",
    "chars": 10752,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "Makefile",
    "chars": 1597,
    "preview": "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_AD"
  },
  {
    "path": "README.md",
    "chars": 9388,
    "preview": "# Space Daemon\n\nSpace Daemon is a wrapper built in Go around awesome IPFS tools so that you can have start coding a dece"
  },
  {
    "path": "app/app.go",
    "chars": 6939,
    "preview": "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/Flee"
  },
  {
    "path": "ci/add-osx-cert.sh",
    "chars": 649,
    "preview": "#!/usr/bin/env sh\n\nKEY_CHAIN=build.keychain\nCERTIFICATE_P12=certificate.p12\n\n# Recreate the certificate from the secure "
  },
  {
    "path": "ci/gon.hcl",
    "chars": 362,
    "preview": "# The path follows a pattern\n# ./dist/BUILD-ID_TARGET/BINARY-NAME\nsource = [\"./dist/space-darwin_darwin_amd64/space\",\"./"
  },
  {
    "path": "cmd/space-daemon/main.go",
    "chars": 4311,
    "preview": "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\"s"
  },
  {
    "path": "config/config.go",
    "chars": 2751,
    "preview": "package config\n\nimport (\n\t\"errors\"\n)\n\nconst (\n\tJsonConfigFileName       = \"space.json\"\n\tSpaceServerPort          = \"spac"
  },
  {
    "path": "config/json_config.go",
    "chars": 3227,
    "preview": "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/e"
  },
  {
    "path": "config/map_config.go",
    "chars": 4308,
    "preview": "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 mapConfi"
  },
  {
    "path": "core/backup/backup.go",
    "chars": 1873,
    "preview": "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\n"
  },
  {
    "path": "core/component.go",
    "chars": 415,
    "preview": "package core\n\n// Component represents core application components. Modules should implement this interface to allow for "
  },
  {
    "path": "core/env/env.go",
    "chars": 1483,
    "preview": "package env\n\nimport (\n\tsyslog \"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nconst (\n\tSpaceWorkingDir      = \"SPACE_APP_DIR\"\n\tLogLevel       "
  },
  {
    "path": "core/env/file_env.go",
    "chars": 928,
    "preview": "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 "
  },
  {
    "path": "core/events/events.go",
    "chars": 1697,
    "preview": "package events\n\nimport \"github.com/FleekHQ/space-daemon/core/space/domain\"\n\n// These file defines events that daemon can"
  },
  {
    "path": "core/fsds/config.go",
    "chars": 1537,
    "preview": "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\""
  },
  {
    "path": "core/fsds/data_source.go",
    "chars": 2073,
    "preview": "package fsds\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// FileReadWriterCloser implements interfaces to "
  },
  {
    "path": "core/fsds/dir_entry.go",
    "chars": 3133,
    "preview": "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/lo"
  },
  {
    "path": "core/fsds/files_ds.go",
    "chars": 6394,
    "preview": "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/sp"
  },
  {
    "path": "core/fsds/read_write_wrapper.go",
    "chars": 2988,
    "preview": "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"
  },
  {
    "path": "core/fsds/shared_with_me_ds.go",
    "chars": 3851,
    "preview": "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/co"
  },
  {
    "path": "core/fsds/spacefs.go",
    "chars": 4912,
    "preview": "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/s"
  },
  {
    "path": "core/fsds/utils.go",
    "chars": 648,
    "preview": "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 i"
  },
  {
    "path": "core/ipfs/dag.go",
    "chars": 1607,
    "preview": "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\""
  },
  {
    "path": "core/ipfs/ipfs.go",
    "chars": 3047,
    "preview": "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/"
  },
  {
    "path": "core/ipfs/node/node.go",
    "chars": 5405,
    "preview": "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\"o"
  },
  {
    "path": "core/ipfs/utils.go",
    "chars": 2530,
    "preview": "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 \"git"
  },
  {
    "path": "core/ipfs/utils_test.go",
    "chars": 829,
    "preview": "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: bafybeiemzcx"
  },
  {
    "path": "core/keychain/app_token.go",
    "chars": 1744,
    "preview": "package keychain\n\nimport (\n\t\"errors\"\n\n\t\"github.com/99designs/keyring\"\n\t\"github.com/FleekHQ/space-daemon/core/permissions"
  },
  {
    "path": "core/keychain/keychain.go",
    "chars": 10174,
    "preview": "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/c"
  },
  {
    "path": "core/keychain/keyring/keyring.go",
    "chars": 212,
    "preview": "package keyring\n\nimport \"github.com/99designs/keyring\"\n\ntype Keyring interface {\n\tSet(keyring.Item) error\n\tGet(string) ("
  },
  {
    "path": "core/keychain/mnemonic.go",
    "chars": 2289,
    "preview": "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"
  },
  {
    "path": "core/keychain/test/keychain_test.go",
    "chars": 11228,
    "preview": "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\"githu"
  },
  {
    "path": "core/libfuse/block_size.go",
    "chars": 623,
    "preview": "package libfuse\n\n// fuseBlockSize is the block size used for calculating number of blocks. This\n// is to make du/df work"
  },
  {
    "path": "core/libfuse/directory.go",
    "chars": 5247,
    "preview": "//+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/Fle"
  },
  {
    "path": "core/libfuse/files.go",
    "chars": 5154,
    "preview": "//+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/"
  },
  {
    "path": "core/libfuse/vfs.go",
    "chars": 3334,
    "preview": "//+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/f"
  },
  {
    "path": "core/permissions/app_token.go",
    "chars": 1559,
    "preview": "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 invalidAppT"
  },
  {
    "path": "core/permissions/app_token_test.go",
    "chars": 866,
    "preview": "package permissions_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n\t\"github.com/stretchr"
  },
  {
    "path": "core/search/bleve/analyzer.go",
    "chars": 1007,
    "preview": "package bleve\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/blevesearch/bleve/analysis\"\n\t\"github.com/blevesearch/bleve/analysis/anal"
  },
  {
    "path": "core/search/bleve/bleve.go",
    "chars": 5050,
    "preview": "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/m"
  },
  {
    "path": "core/search/bleve/bleve_test.go",
    "chars": 5617,
    "preview": "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\"gotes"
  },
  {
    "path": "core/search/bleve/options.go",
    "chars": 113,
    "preview": "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",
    "chars": 435,
    "preview": "package search\n\nimport (\n\t\"context\"\n)\n\n// Represents Search Engines for File and Folders\n// Can be used for indexing and"
  },
  {
    "path": "core/search/model.go",
    "chars": 532,
    "preview": "package search\n\ntype IndexRecord struct {\n\tId            string\n\tItemName      string\n\tItemExtension string\n\tItemPath   "
  },
  {
    "path": "core/search/sqlite/model.go",
    "chars": 378,
    "preview": "package sqlite\n\nimport \"gorm.io/gorm\"\n\ntype SearchIndexRecord struct {\n\tgorm.Model\n\tItemName      string `gorm:\"index:id"
  },
  {
    "path": "core/search/sqlite/options.go",
    "chars": 260,
    "preview": "package sqlite\n\nimport \"gorm.io/gorm/logger\"\n\nfunc WithDBPath(path string) Option {\n\treturn func(o *sqliteSearchOption) "
  },
  {
    "path": "core/search/sqlite/sqlite.go",
    "chars": 3358,
    "preview": "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."
  },
  {
    "path": "core/search/sqlite/sqlite_test.go",
    "chars": 3375,
    "preview": "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\"got"
  },
  {
    "path": "core/space/domain/domain.go",
    "chars": 4849,
    "preview": "package domain\n\nimport \"fmt\"\n\ntype AppConfig struct {\n\tPort                 int\n\tAppPath              string\n\tTextileHub"
  },
  {
    "path": "core/space/fuse/controller.go",
    "chars": 3856,
    "preview": "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/spa"
  },
  {
    "path": "core/space/fuse/fs.go",
    "chars": 348,
    "preview": "package fuse\n\n// VFS represents the handler for virtually mounted drives.\n// it is implemented using FUSE for linux and "
  },
  {
    "path": "core/space/fuse/installer/installer_darwin.go",
    "chars": 1776,
    "preview": "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\"gi"
  },
  {
    "path": "core/space/fuse/installer/installer_darwin_test.go",
    "chars": 460,
    "preview": "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 "
  },
  {
    "path": "core/space/fuse/installer/installer_linux.go",
    "chars": 450,
    "preview": "package installer\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\ntype linuxFuseInstaller struct {\n}\n\nfunc NewFuseInstaller() *linuxFu"
  },
  {
    "path": "core/space/fuse/installer/installer_windows.go",
    "chars": 410,
    "preview": "package installer\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\ntype windowsFuseInstaller struct {\n}\n\nfunc NewFuseInstaller() *windo"
  },
  {
    "path": "core/space/fuse/installer/interface.go",
    "chars": 224,
    "preview": "package installer\n\nimport \"context\"\n\ntype FuseInstaller interface {\n\tIsInstalled(ctx context.Context) (bool, error)\n\tIns"
  },
  {
    "path": "core/space/fuse/mount.go",
    "chars": 1126,
    "preview": "//+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/l"
  },
  {
    "path": "core/space/fuse/mount_windows.go",
    "chars": 806,
    "preview": "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"
  },
  {
    "path": "core/space/fuse/state.go",
    "chars": 801,
    "preview": "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\tUNSU"
  },
  {
    "path": "core/space/fuse/state_test.go",
    "chars": 1652,
    "preview": "// +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/"
  },
  {
    "path": "core/space/services/fs_utils.go",
    "chars": 1255,
    "preview": "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\ti"
  },
  {
    "path": "core/space/services/services.go",
    "chars": 2895,
    "preview": "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.co"
  },
  {
    "path": "core/space/services/services_app_token.go",
    "chars": 360,
    "preview": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/permissions\"\n)\n\nfunc (s *Space) Initialize"
  },
  {
    "path": "core/space/services/services_central_server.go",
    "chars": 451,
    "preview": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\n// Return session token f"
  },
  {
    "path": "core/space/services/services_fs.go",
    "chars": 18297,
    "preview": "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"
  },
  {
    "path": "core/space/services/services_identity.go",
    "chars": 2154,
    "preview": "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\"gi"
  },
  {
    "path": "core/space/services/services_keypair.go",
    "chars": 2042,
    "preview": "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// "
  },
  {
    "path": "core/space/services/services_notifs.go",
    "chars": 963,
    "preview": "package services\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n)\n\nconst notifica"
  },
  {
    "path": "core/space/services/services_search.go",
    "chars": 938,
    "preview": "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\""
  },
  {
    "path": "core/space/services/services_sharing.go",
    "chars": 15787,
    "preview": "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\"pa"
  },
  {
    "path": "core/space/services/services_vault.go",
    "chars": 3635,
    "preview": "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/backu"
  },
  {
    "path": "core/space/services/sharing_utils.go",
    "chars": 1088,
    "preview": "package services\n\nimport (\n\t\"encoding/hex\"\n\t\"errors\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\tcrypto \"gith"
  },
  {
    "path": "core/space/space.go",
    "chars": 5157,
    "preview": "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/Fle"
  },
  {
    "path": "core/space/space_test.go",
    "chars": 26517,
    "preview": "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/htt"
  },
  {
    "path": "core/spacefs/fs.go",
    "chars": 4429,
    "preview": "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 represent"
  },
  {
    "path": "core/spacefs/fs_test.go",
    "chars": 1373,
    "preview": "package spacefs\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n//\nfunc TestSpaceFS_LookupPath(t *testing"
  },
  {
    "path": "core/spacefs/interfaces.go",
    "chars": 2803,
    "preview": "package spacefs\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"time\"\n)\n\ntype FileHandlerMode uint8\n\nconst (\n\tReadMode = FileHandlerMode(0)"
  },
  {
    "path": "core/store/store.go",
    "chars": 4837,
    "preview": "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\""
  },
  {
    "path": "core/sync/fs.go",
    "chars": 5467,
    "preview": "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/Fl"
  },
  {
    "path": "core/sync/notifier_default.go",
    "chars": 261,
    "preview": "package sync\n\nimport (\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n)\n\ntype defaultNotifier struct{}\n\nfunc (d defaultN"
  },
  {
    "path": "core/sync/sync.go",
    "chars": 6621,
    "preview": "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\"gi"
  },
  {
    "path": "core/sync/textile.go",
    "chars": 1433,
    "preview": "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/sp"
  },
  {
    "path": "core/sync/textile_test.go",
    "chars": 1790,
    "preview": "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-da"
  },
  {
    "path": "core/textile/README.md",
    "chars": 2929,
    "preview": "# Textile Wrappers\n\nThis package contains wrappers around Textile Threads and Buckets.\n\n## Usage\n\n### Initialization and"
  },
  {
    "path": "core/textile/account.go",
    "chars": 1011,
    "preview": "package textile\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n)\n\nfunc (tc *textileClient) "
  },
  {
    "path": "core/textile/buckd.go",
    "chars": 2968,
    "preview": "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/"
  },
  {
    "path": "core/textile/bucket/bucket.go",
    "chars": 4248,
    "preview": "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"
  },
  {
    "path": "core/textile/bucket/bucket_dir.go",
    "chars": 3545,
    "preview": "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\""
  },
  {
    "path": "core/textile/bucket/bucket_file.go",
    "chars": 2763,
    "preview": "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/Flee"
  },
  {
    "path": "core/textile/bucket/crypto/crypto.go",
    "chars": 3872,
    "preview": "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 ["
  },
  {
    "path": "core/textile/bucket/crypto/crypto_test.go",
    "chars": 2229,
    "preview": "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 "
  },
  {
    "path": "core/textile/bucket/crypto/decrypter.go",
    "chars": 2120,
    "preview": "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/odek"
  },
  {
    "path": "core/textile/bucket/crypto/encrypter.go",
    "chars": 1699,
    "preview": "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\""
  },
  {
    "path": "core/textile/bucket_factory.go",
    "chars": 14750,
    "preview": "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."
  },
  {
    "path": "core/textile/client.go",
    "chars": 15988,
    "preview": "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/multi"
  },
  {
    "path": "core/textile/common/common.go",
    "chars": 602,
    "preview": "package common\n\nimport \"context\"\n\n// NewBucketEncryptionKeyContext adds the encryption key to the context\n// which is us"
  },
  {
    "path": "core/textile/event_handler.go",
    "chars": 2150,
    "preview": "package textile\n\nimport (\n\t\"github.com/FleekHQ/space-daemon/core/store\"\n\t\"github.com/FleekHQ/space-daemon/core/textile/b"
  },
  {
    "path": "core/textile/hub/hmacTestKey",
    "chars": 37,
    "preview": "\u0003#5K+\u000f~\u0006ew{Z(T(\u000fP.Z\u0006Gwb=\"=.!r\u0005.O\b͚gЀ"
  },
  {
    "path": "core/textile/hub/hub_auth.go",
    "chars": 6376,
    "preview": "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.co"
  },
  {
    "path": "core/textile/hub/hub_auth_test.go",
    "chars": 802,
    "preview": "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/asse"
  },
  {
    "path": "core/textile/listener.go",
    "chars": 3240,
    "preview": "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/texti"
  },
  {
    "path": "core/textile/mailbox.go",
    "chars": 8197,
    "preview": "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/"
  },
  {
    "path": "core/textile/mailbox_test.go",
    "chars": 3744,
    "preview": "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.c"
  },
  {
    "path": "core/textile/mirror.go",
    "chars": 931,
    "preview": "package textile\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/FleekHQ/space-daemon/log\"\n)\n\nconst mirrorThreadKeyName = \"mirr"
  },
  {
    "path": "core/textile/model/buckets.go",
    "chars": 5051,
    "preview": "package model\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/textile/utils\"\n\t\"github.com/FleekHQ/space-dae"
  },
  {
    "path": "core/textile/model/mirror_file.go",
    "chars": 6416,
    "preview": "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/domai"
  },
  {
    "path": "core/textile/model/model.go",
    "chars": 5340,
    "preview": "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/co"
  },
  {
    "path": "core/textile/model/received_file.go",
    "chars": 9499,
    "preview": "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/"
  },
  {
    "path": "core/textile/model/received_file_test.go",
    "chars": 553,
    "preview": "package model\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestReceivedFileSchema_IsPublicLinkRec"
  },
  {
    "path": "core/textile/model/search.go",
    "chars": 1873,
    "preview": "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/Flee"
  },
  {
    "path": "core/textile/model/sent_file.go",
    "chars": 5041,
    "preview": "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\"gith"
  },
  {
    "path": "core/textile/model/shared_public_key.go",
    "chars": 4210,
    "preview": "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-t"
  },
  {
    "path": "core/textile/notifier/notifier.go",
    "chars": 409,
    "preview": "package notifier\n\nimport (\n\t\"github.com/FleekHQ/space-daemon/core/textile/sync\"\n\t\"github.com/ipfs/interface-go-ipfs-core"
  },
  {
    "path": "core/textile/public.go",
    "chars": 4357,
    "preview": "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/"
  },
  {
    "path": "core/textile/search.go",
    "chars": 172,
    "preview": "package textile\n\nimport \"context\"\n\nfunc (tc *textileClient) initSearchIndex(ctx context.Context) error {\n\terr := tc.GetM"
  },
  {
    "path": "core/textile/secure_bucket_client.go",
    "chars": 13722,
    "preview": "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"
  },
  {
    "path": "core/textile/sharing.go",
    "chars": 10937,
    "preview": "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"
  },
  {
    "path": "core/textile/sync/mirror.go",
    "chars": 4888,
    "preview": "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/co"
  },
  {
    "path": "core/textile/sync/pinning.go",
    "chars": 3970,
    "preview": "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/spa"
  },
  {
    "path": "core/textile/sync/queue.go",
    "chars": 2960,
    "preview": "package sync\n\nimport (\n\t\"container/list\"\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nconst QueueStoreKey = \"TextileSyncTaskQueue\"\n\ntype m"
  },
  {
    "path": "core/textile/sync/restore.go",
    "chars": 2306,
    "preview": "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"
  },
  {
    "path": "core/textile/sync/sync.go",
    "chars": 665,
    "preview": "package sync\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/events\"\n)\n\ntype EventNotifier interface {\n\tSen"
  },
  {
    "path": "core/textile/sync/sync_test.go",
    "chars": 3805,
    "preview": "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"
  },
  {
    "path": "core/textile/sync/synchronizer.go",
    "chars": 9999,
    "preview": "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/Fleek"
  },
  {
    "path": "core/textile/sync/task-executors.go",
    "chars": 8833,
    "preview": "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/FleekH"
  },
  {
    "path": "core/textile/sync/task.go",
    "chars": 1432,
    "preview": "package sync\n\nimport (\n\t\"strings\"\n)\n\ntype taskType string\n\nconst (\n\taddItemTask         taskType = \"ADD_ITEM\"\n\tremoveIte"
  },
  {
    "path": "core/textile/sync/threads.go",
    "chars": 697,
    "preview": "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/co"
  },
  {
    "path": "core/textile/textile.go",
    "chars": 3685,
    "preview": "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\"githu"
  },
  {
    "path": "core/textile/utils/utils.go",
    "chars": 9196,
    "preview": "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\""
  },
  {
    "path": "core/textile/utils/utils_test.go",
    "chars": 2054,
    "preview": "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."
  },
  {
    "path": "core/util/address/PROTOCOL.md",
    "chars": 419,
    "preview": "# Protocols\n\n## Address derivation\n\nPublic keys are created using `ed25519` elliptic curve algorithm. An address is a ha"
  },
  {
    "path": "core/util/address/address.go",
    "chars": 581,
    "preview": "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// "
  },
  {
    "path": "core/util/paths.go",
    "chars": 723,
    "preview": "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"
  },
  {
    "path": "core/util/rlimit/rlimit_unix.go",
    "chars": 1031,
    "preview": "// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris\n\npackage rlimit\n\nimport (\n\t\"fmt\"\n\t\"math"
  },
  {
    "path": "core/util/rlimit/rlimit_windows.go",
    "chars": 80,
    "preview": "package rlimit\n\n// Rlimit not supported on windows\nfunc SetRLimit() {\n\treturn\n}\n"
  },
  {
    "path": "core/vault/vault.go",
    "chars": 5845,
    "preview": "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\"enc"
  },
  {
    "path": "core/vault/vault_test.go",
    "chars": 4325,
    "preview": "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/d"
  },
  {
    "path": "core/watcher/blacklist.go",
    "chars": 268,
    "preview": "//+build !windows\n\npackage watcher\n\nimport (\n\t\"os\"\n)\n\n// isBlacklisted return true if the file or path is not a supporte"
  },
  {
    "path": "core/watcher/blacklist_windows.go",
    "chars": 471,
    "preview": "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 "
  },
  {
    "path": "core/watcher/handler.go",
    "chars": 1839,
    "preview": "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 EventH"
  },
  {
    "path": "core/watcher/options.go",
    "chars": 511,
    "preview": "package watcher\n\ntype watcherOptions struct {\n\tpaths []string\n}\n\n// Option configuration for the FileWatcher\n// Use expo"
  },
  {
    "path": "core/watcher/watcher.go",
    "chars": 3972,
    "preview": "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/co"
  },
  {
    "path": "core/watcher/watcher_test.go",
    "chars": 2519,
    "preview": "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/radov"
  },
  {
    "path": "coverage/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "devtools/googleapis/LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "devtools/googleapis/README.grpc-gateway",
    "chars": 435,
    "preview": "Google APIs\n============\n\nProject: Google APIs\nURL: https://github.com/google/googleapis\nRevision: 3544ab16c3342d790b007"
  },
  {
    "path": "devtools/googleapis/google/api/annotations.proto",
    "chars": 1051,
    "preview": "// Copyright (c) 2015, Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
  },
  {
    "path": "devtools/googleapis/google/api/http.proto",
    "chars": 12099,
    "preview": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use th"
  },
  {
    "path": "devtools/googleapis/google/api/httpbody.proto",
    "chars": 2674,
    "preview": "// Copyright 2018 Google LLC.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "devtools/googleapis/google/rpc/code.proto",
    "chars": 7056,
    "preview": "// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "devtools/googleapis/google/rpc/error_details.proto",
    "chars": 7564,
    "preview": "// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "devtools/googleapis/google/rpc/status.proto",
    "chars": 4047,
    "preview": "// Copyright 2017 Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use t"
  },
  {
    "path": "docs/crypto/vault.md",
    "chars": 3422,
    "preview": "# Vault\n\nA vault is used to securely store user private keys based on a master password. It is hosted on the cloud and u"
  },
  {
    "path": "docs/sharing/types-of-sharing.md",
    "chars": 2093,
    "preview": "# Types of Sharing\n\nSharing can happen at the file level or the bucket level.  Legacy sharing was done at the bucket lev"
  },
  {
    "path": "examples/ipfsLite/ipfsLite.go",
    "chars": 78,
    "preview": "package main\n\nimport \"log\"\n\nfunc main() {\n\tlog.Println(\"hello world IPFS!\")\n}\n"
  },
  {
    "path": "examples/textileBucketsClient/README.md",
    "chars": 1114,
    "preview": "# textile in Go poc\n\nTemporarily, buckets APIs aren't available in local threads so using the hub for all interactions. "
  },
  {
    "path": "examples/textileBucketsClient/bucket-sync/bucket-sync.go",
    "chars": 3664,
    "preview": "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/li"
  },
  {
    "path": "examples/textileBucketsClient/buckets.go",
    "chars": 11365,
    "preview": "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"
  },
  {
    "path": "examples/textileBucketsClient/create-thread-with-key/create-thread-with-key.go",
    "chars": 2991,
    "preview": "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-mult"
  },
  {
    "path": "examples/textileBucketsClient/join-thread/join-thread.go",
    "chars": 2764,
    "preview": "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"
  },
  {
    "path": "examples/textileBucketsClient/local-buck/local-buck.go",
    "chars": 3559,
    "preview": "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/textil"
  },
  {
    "path": "examples/textileBucketsClient/open-share-file/open-share-file.go",
    "chars": 3664,
    "preview": "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/li"
  },
  {
    "path": "examples/textileBucketsClient/set-envs",
    "chars": 223,
    "preview": "export TXL_HUB_TARGET=\nexport TXL_USER_KEY=\nexport TXL_USER_SECRET=\nexport MONGO_PW=\nexport MONGO_USR=\nexport MONGO_HOST"
  },
  {
    "path": "examples/textileBucketsClient/sync-test/sync-test.go",
    "chars": 2920,
    "preview": "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/l"
  },
  {
    "path": "go.mod",
    "chars": 3537,
    "preview": "module github.com/FleekHQ/space-daemon\n\ngo 1.14\n\nreplace github.com/textileio/go-threads => github.com/FleekHQ/go-thread"
  },
  {
    "path": "go.sum",
    "chars": 225881,
    "preview": "bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=\nbazil.org/fuse "
  },
  {
    "path": "grpc/auth/app_token_auth/app_token_auth.go",
    "chars": 1799,
    "preview": "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/Fle"
  },
  {
    "path": "grpc/auth/app_token_auth/auth_from_md.go",
    "chars": 1202,
    "preview": "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"
  },
  {
    "path": "grpc/auth/middleware/grpc_auth.go",
    "chars": 1987,
    "preview": "package grpc_auth\n\nimport (\n\t\"context\"\n\n\tgrpc_middleware \"github.com/grpc-ecosystem/go-grpc-middleware\"\n\t\"google.golang."
  },
  {
    "path": "grpc/grpc.go",
    "chars": 5618,
    "preview": "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/"
  },
  {
    "path": "grpc/handlers.go",
    "chars": 7126,
    "preview": "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-d"
  },
  {
    "path": "grpc/handlers_account.go",
    "chars": 612,
    "preview": "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 *grp"
  },
  {
    "path": "grpc/handlers_app_token.go",
    "chars": 685,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) InitializeMaster"
  },
  {
    "path": "grpc/handlers_backup.go",
    "chars": 918,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) ToggleBucketBacku"
  },
  {
    "path": "grpc/handlers_central_services.go",
    "chars": 439,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) GetAPISessionTok"
  },
  {
    "path": "grpc/handlers_fuse.go",
    "chars": 1630,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/opentracing/opentracing-go\"\n\n\t\"github.com/FleekHQ/space-daemon/core/spac"
  },
  {
    "path": "grpc/handlers_key_pair.go",
    "chars": 1814,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n)\n\nfunc (srv *grpcServer) GenerateKeyPair("
  },
  {
    "path": "grpc/handlers_notif.go",
    "chars": 5577,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemo"
  },
  {
    "path": "grpc/handlers_search.go",
    "chars": 1269,
    "preview": "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\nf"
  },
  {
    "path": "grpc/handlers_sharing.go",
    "chars": 6231,
    "preview": "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/Fle"
  },
  {
    "path": "grpc/handlers_textile.go",
    "chars": 2125,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemo"
  },
  {
    "path": "grpc/handlers_vault.go",
    "chars": 1678,
    "preview": "package grpc\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/core/space/domain\"\n\t\"github.com/FleekHQ/space-daemo"
  },
  {
    "path": "grpc/pb/space.pb.go",
    "chars": 355392,
    "preview": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.25.0\n// \tprotoc        v3.6.1\n// sour"
  },
  {
    "path": "grpc/pb/space.pb.gw.go",
    "chars": 149594,
    "preview": "// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.\n// source: space.proto\n\n/*\nPackage pb is a reverse proxy.\n\nIt"
  },
  {
    "path": "grpc/proto/space.proto",
    "chars": 19512,
    "preview": "syntax = \"proto3\";\n\n\nimport \"google/protobuf/empty.proto\";\nimport \"google/api/annotations.proto\";\n\npackage space;\n\noptio"
  },
  {
    "path": "integration_tests/README.md",
    "chars": 355,
    "preview": "### Integration Testing Guide\n\n#### Fixtures\nFixtures module contains test fixtures to setup and teardown tests and perf"
  },
  {
    "path": "integration_tests/fixtures/app.go",
    "chars": 2423,
    "preview": "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-"
  },
  {
    "path": "integration_tests/fixtures/client.go",
    "chars": 1621,
    "preview": "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."
  },
  {
    "path": "integration_tests/fixtures/configs.go",
    "chars": 2140,
    "preview": "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"
  },
  {
    "path": "integration_tests/fixtures/directories.go",
    "chars": 346,
    "preview": "package fixtures\n\nimport \"math/rand\"\n\nconst letterBytes = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \"\n\n// Ra"
  },
  {
    "path": "integration_tests/helpers/assertions.go",
    "chars": 2132,
    "preview": "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/"
  },
  {
    "path": "integration_tests/helpers/directories.go",
    "chars": 3745,
    "preview": "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/pr"
  },
  {
    "path": "integration_tests/helpers/initialize.go",
    "chars": 738,
    "preview": "package helpers\n\nimport (\n\t\"context\"\n\n\t\"github.com/FleekHQ/space-daemon/grpc/pb\"\n\t\"github.com/FleekHQ/space-daemon/integ"
  },
  {
    "path": "integration_tests/integration_tests_suite_test.go",
    "chars": 1262,
    "preview": "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 \"githu"
  }
]

// ... and 24 more files (download for full content)

About this extraction

This page contains the full source code of the FleekHQ/space-daemon GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 224 files (1.5 MB), approximately 535.6k tokens, and a symbol index with 2505 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!