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
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
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\u0006Gwb=\"=.!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.