Merge 7b5512e8482d579ddbe763c9708a1032874868da into 59437382121afb90f291e9c24d22c57c681456aa

This commit is contained in:
Arnaud 2025-12-24 13:12:36 +00:00 committed by GitHub
commit 45004f438a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 598 additions and 581 deletions

View File

@ -46,14 +46,14 @@ jobs:
toolchain: 1.85.0
- name: Record submodule commit
run: git -C vendor/nim-codex rev-parse HEAD > vendor/nim-codex/.codex-commit
run: git -C vendor/logos-storage-nim rev-parse HEAD > vendor/logos-storage-nim/.storage-commit
- name: Cache libcodex build
id: cache-libcodex
- name: Cache libstorage build
id: cache-libstorage
uses: actions/cache@v4
with:
path: vendor/nim-codex/build
key: ${{ runner.os }}-${{ matrix.target.cpu }}-libcodex-${{ hashFiles('vendor/nim-codex/.codex-commit') }}
path: vendor/logos-storage-nim/build
key: ${{ runner.os }}-${{ matrix.target.cpu }}-libstorage-${{ hashFiles('vendor/logos-storage-nim/.storage-commit') }}
- name: MSYS2 (Windows amd64)
if: matrix.target.os == 'windows-latest' && matrix.target.cpu == 'amd64'
@ -69,49 +69,49 @@ jobs:
mingw-w64-ucrt-x86_64-ntldd-git
mingw-w64-ucrt-x86_64-rust
- name: Build libcodex (Linux)
if: matrix.target.lib_ext == 'so' && steps.cache-libcodex.outputs.cache-hit != 'true'
- name: Build libstorage (Linux)
if: matrix.target.lib_ext == 'so' && steps.cache-libstorage.outputs.cache-hit != 'true'
run: |
make update
make libcodex
make libstorage
- name: Build libcodex (MacOS)
if: matrix.target.os == 'macos-latest' && steps.cache-libcodex.outputs.cache-hit != 'true'
- name: Build libstorage (MacOS)
if: matrix.target.os == 'macos-latest' && steps.cache-libstorage.outputs.cache-hit != 'true'
run: |
make update
CODEX_LIB_PARAMS="--passL:\"-Wl,-install_name,@rpath/libcodex.dylib\"" make libcodex
STORAGE_LIB_PARAMS="--passL:\"-Wl,-install_name,@rpath/libstorage.dylib\"" make libstorage
- name: Build libcodex (Windows)
if: matrix.target.os == 'windows-latest' && steps.cache-libcodex.outputs.cache-hit != 'true'
- name: Build libstorage (Windows)
if: matrix.target.os == 'windows-latest' && steps.cache-libstorage.outputs.cache-hit != 'true'
shell: msys2 {0}
run: |
pacman -Sy --noconfirm make
git config --global core.symlinks false
make update
make libcodex
make libstorage
- name: Package artifacts Linux
if: matrix.target.os == 'ubuntu-latest' || matrix.target.os == 'ubuntu-24.04-arm'
run: |
sudo apt-get update && sudo apt-get install -y zip
ZIPFILE=codex-linux-${{ matrix.target.cpu }}.zip
zip -j $ZIPFILE vendor/nim-codex/build/libcodex.${{ matrix.target.lib_ext }} vendor/nim-codex/library/libcodex.h
ZIPFILE=storage-linux-${{ matrix.target.cpu }}.zip
zip -j $ZIPFILE vendor/logos-storage-nim/build/libstorage.${{ matrix.target.lib_ext }} vendor/logos-storage-nim/library/libstorage.h
echo "ZIPFILE=$ZIPFILE" >> $GITHUB_ENV
- name: Package artifacts MacOS
if: matrix.target.os == 'macos-latest'
run: |
ZIPFILE=codex-macos-${{ matrix.target.cpu }}.zip
zip -j $ZIPFILE vendor/nim-codex/build/libcodex.${{ matrix.target.lib_ext }} vendor/nim-codex/library/libcodex.h
ZIPFILE=storage-macos-${{ matrix.target.cpu }}.zip
zip -j $ZIPFILE vendor/logos-storage-nim/build/libstorage.${{ matrix.target.lib_ext }} vendor/logos-storage-nim/library/libstorage.h
echo "ZIPFILE=$ZIPFILE" >> $GITHUB_ENV
- name: Package artifacts (Windows)
if: matrix.target.os == 'windows-latest'
shell: msys2 {0}
run: |
ZIPFILE=codex-windows-${{ matrix.target.cpu }}.zip
(cd vendor/nim-codex/build && 7z a -tzip "${GITHUB_WORKSPACE}/${ZIPFILE}" libcodex.dll)
(cd vendor/nim-codex/library && 7z a -tzip "${GITHUB_WORKSPACE}/${ZIPFILE}" libcodex.h)
ZIPFILE=storage-windows-${{ matrix.target.cpu }}.zip
(cd vendor/logos-storage-nim/build && 7z a -tzip "${GITHUB_WORKSPACE}/${ZIPFILE}" libstorage.dll)
(cd vendor/logos-storage-nim/library && 7z a -tzip "${GITHUB_WORKSPACE}/${ZIPFILE}" libstorage.h)
echo "ZIPFILE=$ZIPFILE" >> $GITHUB_ENV
- name: Upload artifacts

View File

@ -28,22 +28,22 @@ jobs:
toolchain: 1.85.0
- name: Record submodule commit
run: git -C vendor/nim-codex rev-parse HEAD > vendor/nim-codex/.codex-commit
run: git -C vendor/logos-storage-nim rev-parse HEAD > vendor/logos-storage-nim/.storage-commit
- name: Cache libcodex build
id: cache-libcodex
- name: Cache libstorage build
id: cache-libstorage
uses: actions/cache@v4
with:
path: vendor/nim-codex/build
key: ${{ runner.os }}-libcodex-${{ hashFiles('vendor/nim-codex/.codex-commit') }}
path: vendor/logos-storage-nim/build
key: ${{ runner.os }}-libstorage-${{ hashFiles('vendor/logos-storage-nim/.storage-commit') }}
- name: Build libcodex
if: steps.cache-libcodex.outputs.cache-hit != 'true'
- name: Build libstorage
if: steps.cache-libstorage.outputs.cache-hit != 'true'
run: |
make update
CODEX_LIB_PARAMS="-d:codex_enable_api_debug_peers=true -d:LeopardCmakeFlags=\"-DCMAKE_POSITION_INDEPENDENT_CODE=ON\"" make libcodex
STORAGE_LIB_PARAMS="-d:storage_enable_api_debug_peers=true -d:LeopardCmakeFlags=\"-DCMAKE_POSITION_INDEPENDENT_CODE=ON\"" make libstorage
- name: Build codex go
- name: Build Logos Storage go
run: make
- name: Install gotestsum

6
.gitignore vendored
View File

@ -18,8 +18,8 @@
nimcache
# Test files
codex/testdata/hello.downloaded.txt
codex/testdata/hello.downloaded.writer.txt
storage/testdata/hello.downloaded.txt
storage/testdata/hello.downloaded.writer.txt
# Bin
codex-go
storage-go

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "vendor/nim-codex"]
path = vendor/nim-codex
url = https://github.com/codex-storage/nim-codex.git
[submodule "vendor/logos-storage-nim"]
path = vendor/logos-storage-nim
url = https://github.com/logos-storage/logos-storage-nim.git

27
.vscode/launch.json vendored
View File

@ -10,7 +10,11 @@
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": ["-test.v", "-test.run", "^${selectedText}$"],
"args": [
"-test.v",
"-test.run",
"^${selectedText}$"
],
"env": {
"CGO_ENABLED": "1"
}
@ -31,7 +35,9 @@
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": ["-test.v"],
"args": [
"-test.v"
],
"env": {
"CGO_ENABLED": "1"
}
@ -42,18 +48,23 @@
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": ["-test.v", "-count=1"],
"args": [
"-test.v",
"-count=1"
],
"env": {
"CGO_ENABLED": "1"
}
},
{
"name": "Debug Codex Tests",
"name": "Debug Logos Storage Tests",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${workspaceFolder}/codex",
"args": ["-test.v"],
"program": "${workspaceFolder}/storage",
"args": [
"-test.v"
],
"env": {
"CGO_ENABLED": "1"
}
@ -63,7 +74,7 @@
"type": "go",
"request": "launch",
"mode": "test",
"program": "${workspaceFolder}/codex",
"program": "${workspaceFolder}/storage",
"args": [
"-test.v",
"-test.run",
@ -74,4 +85,4 @@
}
}
]
}
}

View File

@ -1,9 +1,9 @@
{
"go.toolsEnvVars": {
"CGO_ENABLED": "1",
"CGO_CFLAGS": "-I${workspaceFolder}/vendor/nim-codex/library",
"CGO_LDFLAGS": "-L${workspaceFolder}/vendor/nim-codex/build -lcodex -Wl,-rpath,${workspaceFolder}/vendor/nim-codex/build",
"LD_LIBRARY_PATH": "${workspaceFolder}/vendor/nim-codex/build:${env:LD_LIBRARY_PATH}"
"CGO_CFLAGS": "-I${workspaceFolder}/vendor/logos-storage-nim/library",
"CGO_LDFLAGS": "-L${workspaceFolder}/vendor/logos-storage-nim/build -lstorage -Wl,-rpath,${workspaceFolder}/vendor/logos-storage-nim/build",
"LD_LIBRARY_PATH": "${workspaceFolder}/vendor/logos-storage-nim/build:${env:LD_LIBRARY_PATH}"
},
"go.testTimeout": "2m"
}

View File

@ -1,13 +1,13 @@
# Makefile for Codex Go Bindings
# Makefile for Logos Storage Go Bindings
NIM_CODEX_DIR := vendor/nim-codex
NIM_CODEX_LIB_DIR := $(abspath $(NIM_CODEX_DIR)/library)
NIM_CODEX_BUILD_DIR := $(abspath $(NIM_CODEX_DIR)/build)
LOGOS_STORAGE_NIM_DIR := vendor/logos-storage-nim
LOGOS_STORAGE_NIM_LIB_DIR := $(abspath $(LOGOS_STORAGE_NIM_DIR)/library)
LOGOS_STORAGE_NIM_BUILD_DIR := $(abspath $(LOGOS_STORAGE_NIM_DIR)/build)
CGO_CFLAGS := -I$(NIM_CODEX_LIB_DIR)
CGO_LDFLAGS := -L$(NIM_CODEX_BUILD_DIR) -lcodex -Wl,-rpath,$(NIM_CODEX_BUILD_DIR)
CGO_CFLAGS := -I$(LOGOS_STORAGE_NIM_LIB_DIR)
CGO_LDFLAGS := -L$(LOGOS_STORAGE_NIM_BUILD_DIR) -lstorage -Wl,-rpath,$(LOGOS_STORAGE_NIM_BUILD_DIR)
.PHONY: all clean update libcodex build test
.PHONY: all clean update libstorage build test
all: build
@ -16,20 +16,20 @@ submodules:
@git submodule update --init --recursive
update: | submodules
@echo "Updating nim-codex..."
@$(MAKE) -C $(NIM_CODEX_DIR) update
@echo "Updating logos-storage-nim..."
@$(MAKE) -C $(LOGOS_STORAGE_NIM_DIR) update
libcodex:
@echo "Building libcodex..."
@$(MAKE) -C $(NIM_CODEX_DIR) libcodex
libstorage:
@echo "Building libstorage..."
@$(MAKE) -C $(LOGOS_STORAGE_NIM_DIR) libstorage
libcodex-with-debug-api:
@echo "Building libcodex..."
@$(MAKE) -C $(NIM_CODEX_DIR) libcodex CODEX_LIB_PARAMS="-d:codex_enable_api_debug_peers"
libstorage-with-debug-api:
@echo "Building libstorage..."
@$(MAKE) -C $(LOGOS_STORAGE_NIM_DIR) libstorage STORAGE_LIB_PARAMS="-d:storage_enable_api_debug_peers"
build:
@echo "Building Codex Go Bindings..."
CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go build -o codex-go ./codex
@echo "Building Logos Storage Go Bindings..."
CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go build -o storage-go ./storage
test:
@echo "Running tests..."
@ -44,5 +44,5 @@ test-with-params:
clean:
@echo "Cleaning up..."
@git submodule deinit -f $(NIM_CODEX_DIR)
@rm -f codex-go
@git submodule deinit -f $(LOGOS_STORAGE_NIM_DIR)
@rm -f storage-go

View File

@ -1,13 +1,13 @@
# Codex Go Bindings
# Logos Storage Go Bindings
This repository provides Go bindings for the Codex library, enabling seamless integration with Go projects.
This repository provides Go bindings for the Logos Stroage library, enabling seamless integration with Go projects.
## Usage
Include in your Go project:
```sh
go get github.com/codex-storage/codex-go-bindings
go get github.com/logos-storage/logos-storage-go-bindings
```
Then the easiest way is to download our prebuilt artifacts and configure your project.
@ -17,13 +17,13 @@ You can use this `Makefile` (or integrates the commands in your build process):
# Path configuration
LIBS_DIR := $(abspath ./libs)
CGO_CFLAGS := -I$(LIBS_DIR)
CGO_LDFLAGS := -L$(LIBS_DIR) -lcodex -Wl,-rpath,$(LIBS_DIR)
CGO_LDFLAGS := -L$(LIBS_DIR) -lstorage -Wl,-rpath,$(LIBS_DIR)
# Fetch configuration
OS ?= "linux"
ARCH ?= "amd64"
VERSION ?= "v0.0.21"
DOWNLOAD_URL := "https://github.com/codex-storage/codex-go-bindings/releases/download/$(VERSION)/codex-${OS}-${ARCH}.zip"
DOWNLOAD_URL := "https://github.com/logos-storage/logos-storage-go-bindings/releases/download/$(VERSION)/storage-${OS}-${ARCH}.zip"
# Edit your binary name here
ifeq ($(OS),Windows_NT)
@ -33,9 +33,9 @@ else
endif
fetch:
@echo "Fetching libcodex from GitHub Actions from: ${DOWNLOAD_URL}"
@curl -fSL --create-dirs -o $(LIBS_DIR)/codex-${OS}-${ARCH}.zip ${DOWNLOAD_URL}
@unzip -o -qq $(LIBS_DIR)/codex-${OS}-${ARCH}.zip -d $(LIBS_DIR)
@echo "Fetching libstorage from GitHub Actions from: ${DOWNLOAD_URL}"
@curl -fSL --create-dirs -o $(LIBS_DIR)/storage-${OS}-${ARCH}.zip ${DOWNLOAD_URL}
@unzip -o -qq $(LIBS_DIR)/storage-${OS}-${ARCH}.zip -d $(LIBS_DIR)
@rm -f $(LIBS_DIR)/*.zip
build:
@ -60,7 +60,7 @@ make build
That's it!
For an example on how to use this package, please take a look at our [example-go-bindings](https://github.com/codex-storage/example-codex-go-bindings) repo.
For an example on how to use this package, please take a look at our [example-go-bindings](https://github.com/logos-storage/example-logos-storage-go-bindings) repo.
If you want to build the library yourself, you need to clone this repo and follow the instructions
of the next step.
@ -69,13 +69,13 @@ of the next step.
To build the required dependencies for this module, the `make` command needs to be executed.
If you are integrating this module into another project via `go get`, ensure that you navigate
to the `codex-go-bindings` module directory and run the `make` commands.
to the `logos-storage-go-bindings` module directory and run the `make` commands.
### Steps to install
Follow these steps to install and set up the module:
1. Make sure your system has the [prerequisites](https://github.com/codex-storage/nim-codex) to run a local Codex node.
1. Make sure your system has the [prerequisites](https://github.com/logos-storage/logos-storage-nim) to run a local Logos Storage node.
2. Fetch the dependencies:
```sh
@ -84,20 +84,20 @@ Follow these steps to install and set up the module:
3. Build the library:
```sh
make libcodex
make libstorage
```
You can pass flags to the Codex building step by using `CODEX_LIB_PARAMS`. For example,
You can pass flags to the Logos Storage building step by using `STORAGE_LIB_PARAMS`. For example,
if you want to enable debug API for peers, you can build the library using:
```sh
CODEX_LIB_PARAMS="-d:codex_enable_api_debug_peers=true" make libcodex
STORAGE_LIB_PARAMS="-d:storage_enable_api_debug_peers=true" make libstorage
```
or you can use a convenience `libcodex-with-debug-api` make target:
or you can use a convenience `libstorage-with-debug-api` make target:
```sh
make libcodex-with-debug-api
make libstorage-with-debug-api
```
To run the test, you have to make sure you have `gotestsum` installed on your system, e.g.:
@ -143,11 +143,11 @@ The release process is defined [here](./RELEASE.md).
### Init
First you need to create a Codex node:
First you need to create a Logos Storage node:
```go
dataDir := "..."
node, err := CodexNew(CodexConfig{
node, err := StorageNew(StorageConfig{
DataDir: dataDir,
BlockRetries: 10,
})
@ -155,7 +155,7 @@ node, err := CodexNew(CodexConfig{
err := node.Destroy()
```
The `CodexConfig` object provides several options to configure your node. You should at least
The `StorageConfig` object provides several options to configure your node. You should at least
adjust the `DataDir` folder and the `BlockRetries` setting to avoid long retrieval times when
the data is unavailable.
@ -198,7 +198,7 @@ There are 3 strategies for uploading: `reader`, `file` or `chunks`. Each one req
The `reader` strategy is the easiest option when you already have a Go `Reader`.
It handles creating the upload session and cancels it if an error occurs.
The `filepath` should contain the datas name with its extension, because Codex uses that to
The `filepath` should contain the datas name with its extension, because Logos Storage uses that to
infer the MIME type.
An `onProgress` callback is available to receive progress updates and notify the user.
@ -213,12 +213,12 @@ onProgress := func(read, total int, percent float64, err error) {
// Do something with the data
}
ctx := context.Background()
cid, err := codex.UploadReader(ctx, UploadOptions{filepath: "hello.txt", onProgress: onProgress}, buf)
cid, err := storage.UploadReader(ctx, UploadOptions{filepath: "hello.txt", onProgress: onProgress}, buf)
```
#### file
The `file` strategy allows you to upload a file on Codex using the path.
The `file` strategy allows you to upload a file on Logos Storage using the path.
It handles creating the upload session and cancels it if an error occurs.
The `onProgress` callback is the same as for `reader` strategy.
@ -230,7 +230,7 @@ onProgress := func(read, total int, percent float64, err error) {
// Do something with the data
}
ctx := context.Background()
cid, err := codex.UploadFile(ctx, UploadOptions{filepath: "./testdata/hello.txt", onProgress: onProgress})
cid, err := storage.UploadFile(ctx, UploadOptions{filepath: "./testdata/hello.txt", onProgress: onProgress})
```
#### chunks
@ -240,13 +240,13 @@ but provides more flexibility. You have to create the upload session, send the c
and then finalize to get the cid.
```go
sessionId, err := codex.UploadInit(&UploadOptions{filepath: "hello.txt"})
sessionId, err := storage.UploadInit(&UploadOptions{filepath: "hello.txt"})
err = codex.UploadChunk(sessionId, []byte("Hello "))
err = storage.UploadChunk(sessionId, []byte("Hello "))
err = codex.UploadChunk(sessionId, []byte("World!"))
err = storage.UploadChunk(sessionId, []byte("World!"))
cid, err := codex.UploadFinalize(sessionId)
cid, err := storage.UploadFinalize(sessionId)
```
Using this strategy, you can handle resumable uploads and cancel the upload
@ -257,7 +257,7 @@ whenever you want!
When you receive a cid, you can download the `Manifest` to get information about the data:
```go
manifest, err := codex.DownloadManifest(cid)
manifest, err := storage.DownloadManifest(cid)
```
It is not mandatory for downloading the data but it is really useful.
@ -286,7 +286,7 @@ opt := DownloadStreamOptions{
},
}
ctx := context.Background()
err := codex.DownloadStream(ctx, cid, opt)
err := storage.DownloadStream(ctx, cid, opt)
```
#### chunks
@ -300,9 +300,9 @@ to terminate the download session.
```go
cid := "..."
err := codex.DownloadInit(cid, DownloadInitOptions{})
chunk, err := codex.DownloadChunk(cid)
err := codex.DownloadCancel(cid)
err := storage.DownloadInit(cid, DownloadInitOptions{})
chunk, err := storage.DownloadChunk(cid)
err := storage.DownloadCancel(cid)
```
Using this strategy, you can handle resumable downloads and cancel the download
@ -345,10 +345,10 @@ info, err := node.Debug()
err := node.UpdateLogLevel("DEBUG")
peerId := "..."
record, err := node.CodexPeerDebug(peerId)
record, err := node.StoragePeerDebug(peerId)
```
`CodexPeerDebug` is only available if you built with `-d:codex_enable_api_debug_peers=true` flag.
`StoragePeerDebug` is only available if you built with `-d:STORAGE_enable_api_debug_peers=true` flag.
### Context and cancellation

View File

@ -23,7 +23,7 @@ git push --tags
Once published, the artifacts can be downloaded using the `version`, example:
`https://github.com/codex-storage/codex-go-bindings/releases/download/v0.0.16/codex-linux-amd64.zip`
`https://github.com/logos-storage/logos-storage-go-bindings/releases/download/v0.0.16/storage-linux-amd64.zip`
It is not recommended to use the `latest` URL because you may face cache issues.
@ -32,33 +32,33 @@ It is not recommended to use the `latest` URL because you may face cache issues.
Once released, you can integrate it into your Go project using:
```bash
go get github.com/codex-storage/codex-go-bindings@v0.0.26
go get github.com/logos-storage/logos-storage-go-bindings@v0.0.26
```
Then you can use the following `Makefile` command to fetch the artifact:
```bash
LIBS_DIR := $(abspath ./libs)
CODEX_OS := linux
CODEX_ARCH := amd64
CODEX_VERSION := $(shell go list -m -f '{{.Version}}' github.com/codex-storage/codex-go-bindings 2>/dev/null)
CODEX_DOWNLOAD_URL := "https://github.com/codex-storage/codex-go-bindings/releases/download/$(CODEX_VERSION)/codex-${CODEX_OS}-${CODEX_ARCH}.zip"
STORAGE_OS := linux
STORAGE_ARCH := amd64
STORAGE_VERSION := $(shell go list -m -f '{{.Version}}' github.com/logos-storage/logos-storage-go-bindings 2>/dev/null)
STORAGE_DOWNLOAD_URL := "https://github.com/logos-storage/logos-storage-go-bindings/releases/download/$(STORAGE_VERSION)/storage-${STORAGE_OS}-${STORAGE_ARCH}.zip"
fetch-libcodex:
fetch-libstorage:
mkdir -p $(LIBS_DIR); \
curl -fSL --create-dirs -o $(LIBS_DIR)/codex-${CODEX_OS}-${CODEX_ARCH}.zip ${CODEX_DOWNLOAD_URL}; \
unzip -o -qq $(LIBS_DIR)/codex-${CODEX_OS}-${CODEX_ARCH}.zip -d $(LIBS_DIR); \
rm -f $(LIBS_DIR)/codex*.zip;
curl -fSL --create-dirs -o $(LIBS_DIR)/storage-${STORAGE_OS}-${STORAGE_ARCH}.zip ${STORAGE_DOWNLOAD_URL}; \
unzip -o -qq $(LIBS_DIR)/storage-${STORAGE_OS}-${STORAGE_ARCH}.zip -d $(LIBS_DIR); \
rm -f $(LIBS_DIR)/storage*.zip;
```
`CODEX_VERSION` uses the same version as the Codex Go dependency declared in your project.
`STORAGE_VERSION` uses the same version as the Logos Storage Go dependency declared in your project.
### Nix
If you use Nix in a sandboxed environment, you cannot use curl to download the artifacts, so you have to prefetch them using the artifacts `SHA-256` hash. To generate the hash, you can use the following command:
```bash
nix store prefetch-file --json --unpack https://github.com/codex-storage/codex-go-bindings/releases/download/v0.0.26/codex-macos-arm64.zip | jq -r .hash
nix store prefetch-file --json --unpack https://github.com/logos-storage/logos-storage-go-bindings/releases/download/v0.0.26/storage-macos-arm64.zip | jq -r .hash
# [10.4 MiB DL] sha256-3CHIWoSjo0plsYqzXQWm1EtY1STcljV4yfXTPon90uE=
```
@ -68,7 +68,7 @@ Then include this hash in your Nix configuration. For example:
```nix
let
optionalString = pkgs.lib.optionalString;
codexVersion = "v0.0.26";
storageVersion = "v0.0.26";
arch =
if stdenv.hostPlatform.isx86_64 then "amd64"
else if stdenv.hostPlatform.isAarch64 then "arm64"
@ -76,21 +76,21 @@ let
os = if stdenv.isDarwin then "macos" else "Linux";
hash =
if stdenv.hostPlatform.isDarwin
# nix store prefetch-file --json --unpack https://github.com/codex-storage/codex-go-bindings/releases/download/v0.0.26/codex-macos-arm64.zip | jq -r .hash
# nix store prefetch-file --json --unpack https://github.com/logos-storage/logos-storage-go-bindings/releases/download/v0.0.26/storage-macos-arm64.zip | jq -r .hash
then "sha256-3CHIWoSjo0plsYqzXQWm1EtY1STcljV4yfXTPon90uE="
# nix store prefetch-file --json --unpack https://github.com/codex-storage/codex-go-bindings/releases/download/v0.0.26/codex-Linux-amd64.zip | jq -r .hash
# nix store prefetch-file --json --unpack https://github.com/logos-storage/logos-storage-go-bindings/releases/download/v0.0.26/storage-Linux-amd64.zip | jq -r .hash
else "sha256-YxW2vFZlcLrOx1PYgWW4MIstH/oFBRF0ooS0sl3v6ig=";
# Pre-fetch libcodex to avoid network during build
codexLib = pkgs.fetchzip {
url = "https://github.com/codex-storage/codex-go-bindings/releases/download/${codexVersion}/codex-${os}-${arch}.zip";
# Pre-fetch libstorage to avoid network during build
storageLib = pkgs.fetchzip {
url = "https://github.com/logos-storage/logos-storage-go-bindings/releases/download/${storageVersion}/storage-${os}-${arch}.zip";
hash = hash;
stripRoot = false;
};
preBuild = ''
export LIBS_DIR="${codexLib}"
# Build something cool with Codex
export LIBS_DIR="${storageLib}"
# Build something cool with Logos Storage
'';
```

View File

@ -1,154 +0,0 @@
package codex
import (
"testing"
)
func TestCodexVersion(t *testing.T) {
config := defaultConfigHelper(t)
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Codex node: %v", err)
}
version, err := node.Version()
if err != nil {
t.Fatalf("Failed to get Codex version: %v", err)
}
if version == "" {
t.Fatal("Codex version is empty")
}
t.Logf("Codex version: %s", version)
}
func TestCodexRevision(t *testing.T) {
config := defaultConfigHelper(t)
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Codex node: %v", err)
}
revision, err := node.Revision()
if err != nil {
t.Fatalf("Failed to get Codex revision: %v", err)
}
if revision == "" {
t.Fatal("Codex revision is empty")
}
t.Logf("Codex revision: %s", revision)
}
func TestCodexRepo(t *testing.T) {
node := newCodexNode(t)
repo, err := node.Repo()
if err != nil {
t.Fatalf("Failed to get Codex repo: %v", err)
}
if repo == "" {
t.Fatal("Codex repo is empty")
}
t.Logf("Codex repo: %s", repo)
}
func TestSpr(t *testing.T) {
node := newCodexNode(t)
spr, err := node.Spr()
if err != nil {
t.Fatalf("Failed to get Codex SPR: %v", err)
}
if spr == "" {
t.Fatal("Codex SPR is empty")
}
t.Logf("Codex SPR: %s", spr)
}
func TestPeerId(t *testing.T) {
node := newCodexNode(t)
peerId, err := node.PeerId()
if err != nil {
t.Fatalf("Failed to get Codex PeerId: %v", err)
}
if peerId == "" {
t.Fatal("Codex PeerId is empty")
}
t.Logf("Codex PeerId: %s", peerId)
}
func TestStorageQuota(t *testing.T) {
node := newCodexNode(t, Config{
StorageQuota: 1024 * 1024 * 1024, // 1GB
})
if node == nil {
t.Fatal("expected codex node to be created")
}
}
func TestCreateAndDestroyMultipleInstancesWithSameDatadir(t *testing.T) {
datadir := t.TempDir()
config := Config{
DataDir: datadir,
LogFormat: LogFormatNoColors,
MetricsEnabled: false,
BlockRetries: 5,
Nat: "none",
}
for range 2 {
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Codex node: %v", err)
}
if err := node.Start(); err != nil {
t.Fatalf("Failed to start Codex node: %v", err)
}
if err := node.Stop(); err != nil {
t.Fatalf("Failed to stop Codex node: %v", err)
}
if err := node.Destroy(); err != nil {
t.Fatalf("Failed to stop Codex node after restart: %v", err)
}
}
}
func TestNumThreads(t *testing.T) {
node := newCodexNode(t, Config{
NumThreads: 1,
})
if node == nil {
t.Fatal("expected codex node to be created")
}
}
func TestBlockTtl(t *testing.T) {
node := newCodexNode(t, Config{
BlockTtl: "10H",
})
if node == nil {
t.Fatal("expected codex node to be created")
}
}
func TestBlockMaintenanceInterval(t *testing.T) {
node := newCodexNode(t, Config{
BlockMaintenanceInterval: "10H",
})
if node == nil {
t.Fatal("expected codex node to be created")
}
}

2
go.mod
View File

@ -1,3 +1,3 @@
module github.com/codex-storage/codex-go-bindings
module github.com/logos-storage/logos-go-bindings
go 1.24.0

View File

@ -1,9 +1,9 @@
package codex
package storage
/*
#include <stdbool.h>
#include <stdlib.h>
#include "libcodex.h"
#include "libstorage.h"
typedef struct {
int ret;

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdbool.h>
#include "libcodex.h"
#include "libstorage.h"
extern void callback(int ret, char* msg, size_t len, void* resp);

View File

@ -1,19 +1,19 @@
package codex
package storage
/*
#include "bridge.h"
#include <stdlib.h>
static int cGoCodexDebug(void* codexCtx, void* resp) {
return codex_debug(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageDebug(void* storageCtx, void* resp) {
return storage_debug(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexLogLevel(void* codexCtx, char* logLevel, void* resp) {
return codex_log_level(codexCtx, logLevel, (CodexCallback) callback, resp);
static int cGoStorageLogLevel(void* storageCtx, char* logLevel, void* resp) {
return storage_log_level(storageCtx, logLevel, (StorageCallback) callback, resp);
}
static int cGoCodexPeerDebug(void* codexCtx, char* peerId, void* resp) {
return codex_peer_debug(codexCtx, peerId, (CodexCallback) callback, resp);
static int cGoStoragePeerDebug(void* storageCtx, char* peerId, void* resp) {
return storage_peer_debug(storageCtx, peerId, (StorageCallback) callback, resp);
}
*/
import "C"
@ -40,7 +40,7 @@ type DebugInfo struct {
ID string `json:"id"`
// Peer info addresses
// Specified with `ListenAddresses` in `CodexConfig`
// Specified with `ListenAddresses` in `StorageConfig`
Addrs []string `json:"addrs"`
Spr string `json:"spr"`
@ -54,15 +54,15 @@ type PeerRecord struct {
Addresses []string `json:"addresses,omitempty"`
}
// Debug retrieves debugging information from the Codex node.
func (node CodexNode) Debug() (DebugInfo, error) {
// Debug retrieves debugging information from the Logos Storage node.
func (node StorageNode) Debug() (DebugInfo, error) {
var info DebugInfo
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexDebug(node.ctx, bridge.resp) != C.RET_OK {
return info, bridge.callError("cGoCodexDebug")
if C.cGoStorageDebug(node.ctx, bridge.resp) != C.RET_OK {
return info, bridge.callError("cGoStorageDebug")
}
value, err := bridge.wait()
@ -78,27 +78,27 @@ func (node CodexNode) Debug() (DebugInfo, error) {
// You can pass a plain level: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR, FATAL.
// The default level is TRACE.
// You can also use Chronicles topic directives. So for example if you want
// to update the general level to INFO but want to see TRACE logs for the codexlib
// topic, you can pass "INFO,codexlib:TRACE".
func (node CodexNode) UpdateLogLevel(logLevel string) error {
// to update the general level to INFO but want to see TRACE logs for the libstorage
// topic, you can pass "INFO,libstorage:TRACE".
func (node StorageNode) UpdateLogLevel(logLevel string) error {
bridge := newBridgeCtx()
defer bridge.free()
var cLogLevel = C.CString(string(logLevel))
defer C.free(unsafe.Pointer(cLogLevel))
if C.cGoCodexLogLevel(node.ctx, cLogLevel, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexLogLevel")
if C.cGoStorageLogLevel(node.ctx, cLogLevel, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageLogLevel")
}
_, err := bridge.wait()
return err
}
// CodexPeerDebug retrieves the peer record for a given peer ID.
// StoragePeerDebug retrieves the peer record for a given peer ID.
// This function is available only if the flag
// -d:codex_enable_api_debug_peers=true was set at build time.
func (node CodexNode) CodexPeerDebug(peerId string) (PeerRecord, error) {
// -d:storage_enable_api_debug_peers=true was set at build time.
func (node StorageNode) StoragePeerDebug(peerId string) (PeerRecord, error) {
var record PeerRecord
bridge := newBridgeCtx()
@ -107,8 +107,8 @@ func (node CodexNode) CodexPeerDebug(peerId string) (PeerRecord, error) {
var cPeerId = C.CString(peerId)
defer C.free(unsafe.Pointer(cPeerId))
if C.cGoCodexPeerDebug(node.ctx, cPeerId, bridge.resp) != C.RET_OK {
return record, bridge.callError("cGoCodexPeerDebug")
if C.cGoStoragePeerDebug(node.ctx, cPeerId, bridge.resp) != C.RET_OK {
return record, bridge.callError("cGoStoragePeerDebug")
}
value, err := bridge.wait()

View File

@ -1,4 +1,4 @@
package codex
package storage
import (
"os"
@ -8,9 +8,9 @@ import (
)
func TestDebug(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
info, err := codex.Debug()
info, err := storage.Debug()
if err != nil {
t.Fatalf("Debug call failed: %v", err)
}
@ -26,13 +26,13 @@ func TestDebug(t *testing.T) {
}
func TestUpdateLogLevel(t *testing.T) {
tmpFile, err := os.CreateTemp("", "codex-log-*.log")
tmpFile, err := os.CreateTemp("", "storage-log-*.log")
if err != nil {
t.Fatalf("Failed to create temp log file: %v", err)
}
defer os.Remove(tmpFile.Name())
node := newCodexNode(t, Config{
node := newStorageNode(t, Config{
LogLevel: "INFO",
LogFile: tmpFile.Name(),
LogFormat: LogFormatNoColors,
@ -53,7 +53,7 @@ func TestUpdateLogLevel(t *testing.T) {
}
if err := node.Stop(); err != nil {
t.Fatalf("Failed to stop Codex node: %v", err)
t.Fatalf("Failed to stop Logos Storage node: %v", err)
}
// Clear the file
@ -63,7 +63,7 @@ func TestUpdateLogLevel(t *testing.T) {
err = node.Start()
if err != nil {
t.Fatalf("Failed to start Codex node: %v", err)
t.Fatalf("Failed to start Logos Storage node: %v", err)
}
content, err = os.ReadFile(tmpFile.Name())
@ -76,11 +76,11 @@ func TestUpdateLogLevel(t *testing.T) {
}
}
func TestCodexPeerDebug(t *testing.T) {
var bootstrap, node1, node2 *CodexNode
func TestStoragePeerDebug(t *testing.T) {
var bootstrap, node1, node2 *StorageNode
var err error
bootstrap = newCodexNode(t, Config{
bootstrap = newStorageNode(t, Config{
DiscoveryPort: 8092,
})
@ -91,12 +91,12 @@ func TestCodexPeerDebug(t *testing.T) {
bootstrapNodes := []string{spr}
node1 = newCodexNode(t, Config{
node1 = newStorageNode(t, Config{
DiscoveryPort: 8090,
BootstrapNodes: bootstrapNodes,
})
node2 = newCodexNode(t, Config{
node2 = newStorageNode(t, Config{
DiscoveryPort: 8091,
BootstrapNodes: bootstrapNodes,
})
@ -108,7 +108,7 @@ func TestCodexPeerDebug(t *testing.T) {
var record PeerRecord
for range 10 {
record, err = node1.CodexPeerDebug(peerId)
record, err = node1.StoragePeerDebug(peerId)
if err == nil {
break
}
@ -117,22 +117,22 @@ func TestCodexPeerDebug(t *testing.T) {
}
if err != nil {
t.Fatalf("CodexPeerDebug call failed: %v", err)
t.Fatalf("Logos StoragePeerDebug call failed: %v", err)
}
if record.PeerId == "" {
t.Fatalf("CodexPeerDebug call failed: %v", err)
t.Fatalf("Logos StoragePeerDebug call failed: %v", err)
}
if record.PeerId == "" {
t.Error("CodexPeerDebug info PeerId is empty")
t.Error("Logos StoragePeerDebug info PeerId is empty")
}
if record.SeqNo == 0 {
t.Error("CodexPeerDebug info SeqNo is empty")
t.Error("Logos StoragePeerDebug info SeqNo is empty")
}
if len(record.Addresses) == 0 {
t.Error("CodexPeerDebug info Addresses is empty")
t.Error("Logos StoragePeerDebug info Addresses is empty")
}
if record.PeerId != peerId {
t.Errorf("CodexPeerDebug info PeerId (%s) does not match requested PeerId (%s)", record.PeerId, peerId)
t.Errorf("Logos StoragePeerDebug info PeerId (%s) does not match requested PeerId (%s)", record.PeerId, peerId)
}
}

View File

@ -1,27 +1,27 @@
package codex
package storage
/*
#include "bridge.h"
#include <stdlib.h>
static int cGoCodexDownloadInit(void* codexCtx, char* cid, size_t chunkSize, bool local, void* resp) {
return codex_download_init(codexCtx, cid, chunkSize, local, (CodexCallback) callback, resp);
static int cGoStorageDownloadInit(void* storageCtx, char* cid, size_t chunkSize, bool local, void* resp) {
return storage_download_init(storageCtx, cid, chunkSize, local, (StorageCallback) callback, resp);
}
static int cGoCodexDownloadChunk(void* codexCtx, char* cid, void* resp) {
return codex_download_chunk(codexCtx, cid, (CodexCallback) callback, resp);
static int cGoStorageDownloadChunk(void* storageCtx, char* cid, void* resp) {
return storage_download_chunk(storageCtx, cid, (StorageCallback) callback, resp);
}
static int cGoCodexDownloadStream(void* codexCtx, char* cid, size_t chunkSize, bool local, const char* filepath, void* resp) {
return codex_download_stream(codexCtx, cid, chunkSize, local, filepath, (CodexCallback) callback, resp);
static int cGoStorageDownloadStream(void* storageCtx, char* cid, size_t chunkSize, bool local, const char* filepath, void* resp) {
return storage_download_stream(storageCtx, cid, chunkSize, local, filepath, (StorageCallback) callback, resp);
}
static int cGoCodexDownloadCancel(void* codexCtx, char* cid, void* resp) {
return codex_download_cancel(codexCtx, cid, (CodexCallback) callback, resp);
static int cGoStorageDownloadCancel(void* storageCtx, char* cid, void* resp) {
return storage_download_cancel(storageCtx, cid, (StorageCallback) callback, resp);
}
static int cGoCodexDownloadManifest(void* codexCtx, char* cid, void* resp) {
return codex_download_manifest(codexCtx, cid, (CodexCallback) callback, resp);
static int cGoStorageDownloadManifest(void* storageCtx, char* cid, void* resp) {
return storage_download_manifest(storageCtx, cid, (StorageCallback) callback, resp);
}
*/
import "C"
@ -37,7 +37,7 @@ import (
type OnDownloadProgressFunc func(read, total int, percent float64, err error)
// DownloadStreamOptions is used to download a file
// in a streaming manner in Codex.
// in a streaming manner in Logos Storage.
type DownloadStreamOptions = struct {
// Filepath is the path destination used by DownloadStream.
// If it is set, the content will be written into the specified
@ -89,7 +89,7 @@ type DownloadInitOptions = struct {
}
// Manifest is the object containing the information of
// a file in Codex.
// a file in Logos Storage.
type Manifest struct {
// Cid is the content identifier over the network
Cid string
@ -113,18 +113,18 @@ type Manifest struct {
Protected bool `json:"protected"`
}
// DownloadManifest retrieves the Codex manifest from its cid.
// DownloadManifest retrieves the Logos Storage manifest from its cid.
// The session identifier is the cid, i.e you cannot have multiple
// sessions for a cid.
func (node CodexNode) DownloadManifest(cid string) (Manifest, error) {
func (node StorageNode) DownloadManifest(cid string) (Manifest, error) {
bridge := newBridgeCtx()
defer bridge.free()
var cCid = C.CString(cid)
defer C.free(unsafe.Pointer(cCid))
if C.cGoCodexDownloadManifest(node.ctx, cCid, bridge.resp) != C.RET_OK {
return Manifest{}, bridge.callError("cGoCodexDownloadManifest")
if C.cGoStorageDownloadManifest(node.ctx, cCid, bridge.resp) != C.RET_OK {
return Manifest{}, bridge.callError("cGoStorageDownloadManifest")
}
val, err := bridge.wait()
@ -148,7 +148,7 @@ func (node CodexNode) DownloadManifest(cid string) (Manifest, error) {
// If options.writer is set, the data will be written into that writer.
// The options filepath and writer are not mutually exclusive, i.e you can write
// in different places in a same call.
func (node CodexNode) DownloadStream(ctx context.Context, cid string, options DownloadStreamOptions) error {
func (node StorageNode) DownloadStream(ctx context.Context, cid string, options DownloadStreamOptions) error {
bridge := newBridgeCtx()
defer bridge.free()
@ -207,8 +207,8 @@ func (node CodexNode) DownloadStream(ctx context.Context, cid string, options Do
var cLocal = C.bool(options.Local)
if C.cGoCodexDownloadStream(node.ctx, cCid, options.ChunkSize.toSizeT(), cLocal, cFilepath, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexDownloadLocal")
if C.cGoStorageDownloadStream(node.ctx, cCid, options.ChunkSize.toSizeT(), cLocal, cFilepath, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageDownloadLocal")
}
// Create a done channel to signal the goroutine to stop
@ -255,7 +255,7 @@ func (node CodexNode) DownloadStream(ctx context.Context, cid string, options Do
// DownloadInit initializes the download process for a specific CID.
// This method should be used if you want to manage the download session
// and the chunk downloads manually.
func (node CodexNode) DownloadInit(cid string, options DownloadInitOptions) error {
func (node StorageNode) DownloadInit(cid string, options DownloadInitOptions) error {
bridge := newBridgeCtx()
defer bridge.free()
@ -264,8 +264,8 @@ func (node CodexNode) DownloadInit(cid string, options DownloadInitOptions) erro
var cLocal = C.bool(options.Local)
if C.cGoCodexDownloadInit(node.ctx, cCid, options.ChunkSize.toSizeT(), cLocal, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexDownloadInit")
if C.cGoStorageDownloadInit(node.ctx, cCid, options.ChunkSize.toSizeT(), cLocal, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageDownloadInit")
}
_, err := bridge.wait()
@ -277,9 +277,9 @@ func (node CodexNode) DownloadInit(cid string, options DownloadInitOptions) erro
// When using this method, you are managing at your own
// the total size downloaded (use DownloadManifest to get the
// datasetSize).
// When the download is complete, you need to call `CodexDownloadCancel`
// When the download is complete, you need to call `StorageDownloadCancel`
// to free the resources.
func (node CodexNode) DownloadChunk(cid string) ([]byte, error) {
func (node StorageNode) DownloadChunk(cid string) ([]byte, error) {
bridge := newBridgeCtx()
defer bridge.free()
@ -292,8 +292,8 @@ func (node CodexNode) DownloadChunk(cid string) ([]byte, error) {
var cCid = C.CString(cid)
defer C.free(unsafe.Pointer(cCid))
if C.cGoCodexDownloadChunk(node.ctx, cCid, bridge.resp) != C.RET_OK {
return nil, bridge.callError("cGoCodexDownloadChunk")
if C.cGoStorageDownloadChunk(node.ctx, cCid, bridge.resp) != C.RET_OK {
return nil, bridge.callError("cGoStorageDownloadChunk")
}
if _, err := bridge.wait(); err != nil {
@ -306,15 +306,15 @@ func (node CodexNode) DownloadChunk(cid string) ([]byte, error) {
// DownloadCancel cancels a download session.
// It can be only if the download session is managed manually.
// It doesn't work with DownloadStream.
func (node CodexNode) DownloadCancel(cid string) error {
func (node StorageNode) DownloadCancel(cid string) error {
bridge := newBridgeCtx()
defer bridge.free()
var cCid = C.CString(cid)
defer C.free(unsafe.Pointer(cCid))
if C.cGoCodexDownloadCancel(node.ctx, cCid, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexDownloadCancel")
if C.cGoStorageDownloadCancel(node.ctx, cCid, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageDownloadCancel")
}
_, err := bridge.wait()

View File

@ -1,4 +1,4 @@
package codex
package storage
import (
"context"
@ -8,8 +8,8 @@ import (
)
func TestDownloadStream(t *testing.T) {
codex := newCodexNode(t)
cid, len := uploadHelper(t, codex)
storage := newStorageNode(t)
cid, len := uploadHelper(t, storage)
f, err := os.Create("testdata/hello.downloaded.txt")
if err != nil {
@ -33,7 +33,7 @@ func TestDownloadStream(t *testing.T) {
},
}
if err := codex.DownloadStream(context.Background(), cid, opt); err != nil {
if err := storage.DownloadStream(context.Background(), cid, opt); err != nil {
t.Fatal("Error happened:", err.Error())
}
@ -56,8 +56,8 @@ func TestDownloadStream(t *testing.T) {
}
func TestDownloadStreamWithAutosize(t *testing.T) {
codex := newCodexNode(t)
cid, len := uploadHelper(t, codex)
storage := newStorageNode(t)
cid, len := uploadHelper(t, storage)
totalBytes := 0
finalPercent := 0.0
@ -73,7 +73,7 @@ func TestDownloadStreamWithAutosize(t *testing.T) {
},
}
if err := codex.DownloadStream(context.Background(), cid, opt); err != nil {
if err := storage.DownloadStream(context.Background(), cid, opt); err != nil {
t.Fatal("Error happened:", err.Error())
}
@ -87,10 +87,10 @@ func TestDownloadStreamWithAutosize(t *testing.T) {
}
func TestDownloadStreamWithNotExisting(t *testing.T) {
codex := newCodexNode(t, Config{BlockRetries: 1})
storage := newStorageNode(t, Config{BlockRetries: 1})
opt := DownloadStreamOptions{}
if err := codex.DownloadStream(context.Background(), "bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", opt); err == nil {
if err := storage.DownloadStream(context.Background(), "bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", opt); err == nil {
t.Fatal("Error expected when downloading non-existing cid")
}
}
@ -98,12 +98,12 @@ func TestDownloadStreamWithNotExisting(t *testing.T) {
func TestDownloadStreamCancelled(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
codex := newCodexNode(t)
cid, _ := uploadBigFileHelper(t, codex)
storage := newStorageNode(t)
cid, _ := uploadBigFileHelper(t, storage)
channelError := make(chan error, 1)
go func() {
err := codex.DownloadStream(ctx, cid, DownloadStreamOptions{Local: true})
err := storage.DownloadStream(ctx, cid, DownloadStreamOptions{Local: true})
channelError <- err
}()
@ -120,15 +120,15 @@ func TestDownloadStreamCancelled(t *testing.T) {
}
func TestDownloadManual(t *testing.T) {
codex := newCodexNode(t)
cid, _ := uploadHelper(t, codex)
storage := newStorageNode(t)
cid, _ := uploadHelper(t, storage)
if err := codex.DownloadInit(cid, DownloadInitOptions{}); err != nil {
if err := storage.DownloadInit(cid, DownloadInitOptions{}); err != nil {
t.Fatal("Error when initializing download:", err)
}
var b strings.Builder
if chunk, err := codex.DownloadChunk(cid); err != nil {
if chunk, err := storage.DownloadChunk(cid); err != nil {
t.Fatal("Error when downloading chunk:", err)
} else {
b.Write(chunk)
@ -139,16 +139,16 @@ func TestDownloadManual(t *testing.T) {
t.Fatalf("Expected data was \"Hello World!\" got %s", data)
}
if err := codex.DownloadCancel(cid); err != nil {
if err := storage.DownloadCancel(cid); err != nil {
t.Fatalf("Error when cancelling the download %s", err)
}
}
func TestDownloadManifest(t *testing.T) {
codex := newCodexNode(t)
cid, _ := uploadHelper(t, codex)
storage := newStorageNode(t)
cid, _ := uploadHelper(t, storage)
manifest, err := codex.DownloadManifest(cid)
manifest, err := storage.DownloadManifest(cid)
if err != nil {
t.Fatal("Error when downloading manifest:", err)
}
@ -159,9 +159,9 @@ func TestDownloadManifest(t *testing.T) {
}
func TestDownloadManifestWithNotExistingCid(t *testing.T) {
codex := newCodexNode(t, Config{BlockRetries: 1})
storage := newStorageNode(t, Config{BlockRetries: 1})
manifest, err := codex.DownloadManifest("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku")
manifest, err := storage.DownloadManifest("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku")
if err == nil {
t.Fatal("Error when downloading manifest:", err)
}
@ -172,9 +172,9 @@ func TestDownloadManifestWithNotExistingCid(t *testing.T) {
}
func TestDownloadInitWithNotExistingCid(t *testing.T) {
codex := newCodexNode(t, Config{BlockRetries: 1})
storage := newStorageNode(t, Config{BlockRetries: 1})
if err := codex.DownloadInit("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", DownloadInitOptions{}); err == nil {
if err := storage.DownloadInit("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", DownloadInitOptions{}); err == nil {
t.Fatal("expected error when initializing download for non-existent cid")
}
}

View File

@ -1,58 +1,58 @@
package codex
package storage
/*
#include "bridge.h"
#include <stdlib.h>
void libcodexNimMain(void);
void libstorageNimMain(void);
static void codex_host_init_once(void){
static void storage_host_init_once(void){
static int done;
if (!__atomic_exchange_n(&done, 1, __ATOMIC_SEQ_CST)) libcodexNimMain();
if (!__atomic_exchange_n(&done, 1, __ATOMIC_SEQ_CST)) libstorageNimMain();
}
// resp must be set != NULL in case interest on retrieving data from the callback
void callback(int ret, char* msg, size_t len, void* resp);
static void* cGoCodexNew(const char* configJson, void* resp) {
void* ret = codex_new(configJson, (CodexCallback) callback, resp);
static void* cGoStorageNew(const char* configJson, void* resp) {
void* ret = storage_new(configJson, (StorageCallback) callback, resp);
return ret;
}
static int cGoCodexStart(void* codexCtx, void* resp) {
return codex_start(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageStart(void* storageCtx, void* resp) {
return storage_start(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexStop(void* codexCtx, void* resp) {
return codex_stop(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageStop(void* storageCtx, void* resp) {
return storage_stop(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexClose(void* codexCtx, void* resp) {
return codex_close(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageClose(void* storageCtx, void* resp) {
return storage_close(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexDestroy(void* codexCtx, void* resp) {
return codex_destroy(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageDestroy(void* storageCtx, void* resp) {
return storage_destroy(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexVersion(void* codexCtx, void* resp) {
return codex_version(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageVersion(void* storageCtx, void* resp) {
return storage_version(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexRevision(void* codexCtx, void* resp) {
return codex_revision(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageRevision(void* storageCtx, void* resp) {
return storage_revision(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexRepo(void* codexCtx, void* resp) {
return codex_repo(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageRepo(void* storageCtx, void* resp) {
return storage_repo(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexSpr(void* codexCtx, void* resp) {
return codex_spr(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageSpr(void* storageCtx, void* resp) {
return storage_spr(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexPeerId(void* codexCtx, void* resp) {
return codex_peer_id(codexCtx, (CodexCallback) callback, resp);
static int cGoStoragePeerId(void* storageCtx, void* resp) {
return storage_peer_id(storageCtx, (StorageCallback) callback, resp);
}
*/
import "C"
@ -110,11 +110,11 @@ type Config struct {
// Default: 8008
MetricsPort int `json:"metrics-port,omitempty"`
// The directory where codex will store configuration and data
// The directory where Logos Storage will store configuration and data
// Default:
// $HOME\AppData\Roaming\Codex on Windows
// $HOME/Library/Application Support/Codex on macOS
// $HOME/.cache/codex on Linux
// $HOME\AppData\Roaming\Storage on Windows
// $HOME/Library/Application Support/Storage on macOS
// $HOME/.cache/storage on Linux
DataDir string `json:"data-dir,omitempty"`
// Multi Addresses to listen on
@ -146,7 +146,7 @@ type Config struct {
NumThreads int `json:"num-threads,omitempty"`
// Node agent string which is used as identifier in network
// Default: "Codex"
// Default: "Logos Storage"
AgentString string `json:"agent-string,omitempty"`
// Backend for main repo store (fs, sqlite, leveldb)
@ -183,7 +183,7 @@ type Config struct {
LogFile string `json:"log-file,omitempty"`
}
type CodexNode struct {
type StorageNode struct {
ctx unsafe.Pointer
}
@ -201,12 +201,12 @@ func (c ChunkSize) toSizeT() C.size_t {
return C.size_t(c.valOrDefault())
}
// New creates a new Codex node with the provided configuration.
// The node is not started automatically; you need to call CodexStart
// New creates a new Logos Storage node with the provided configuration.
// The node is not started automatically; you need to call StorageStart
// to start it.
// It returns a Codex node that can be used to interact
// with the Codex network.
func New(config Config) (*CodexNode, error) {
// It returns a Logos Storage node that can be used to interact
// with the Logos Storage network.
func New(config Config) (*StorageNode, error) {
bridge := newBridgeCtx()
defer bridge.free()
@ -218,22 +218,22 @@ func New(config Config) (*CodexNode, error) {
cJsonConfig := C.CString(string(jsonConfig))
defer C.free(unsafe.Pointer(cJsonConfig))
ctx := C.cGoCodexNew(cJsonConfig, bridge.resp)
ctx := C.cGoStorageNew(cJsonConfig, bridge.resp)
if _, err := bridge.wait(); err != nil {
return nil, bridge.err
}
return &CodexNode{ctx: ctx}, bridge.err
return &StorageNode{ctx: ctx}, bridge.err
}
// Start starts the Codex node.
func (node CodexNode) Start() error {
// Start starts the Logos Storage node.
func (node StorageNode) Start() error {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexStart(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexStart")
if C.cGoStorageStart(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageStart")
}
_, err := bridge.wait()
@ -241,34 +241,34 @@ func (node CodexNode) Start() error {
}
// StartAsync is the asynchronous version of Start.
func (node CodexNode) StartAsync(onDone func(error)) {
func (node StorageNode) StartAsync(onDone func(error)) {
go func() {
err := node.Start()
onDone(err)
}()
}
// Stop stops the Codex node.
func (node CodexNode) Stop() error {
// Stop stops the Logos Storage node.
func (node StorageNode) Stop() error {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexStop(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexStop")
if C.cGoStorageStop(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageStop")
}
_, err := bridge.wait()
return err
}
// Destroy destroys the Codex node, freeing all resources.
// Destroy destroys the Logos Storage node, freeing all resources.
// The node must be stopped before calling this method.
func (node CodexNode) Destroy() error {
func (node StorageNode) Destroy() error {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexClose(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexClose")
if C.cGoStorageClose(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageClose")
}
_, err := bridge.wait()
@ -276,8 +276,8 @@ func (node CodexNode) Destroy() error {
return err
}
if C.cGoCodexDestroy(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexDestroy")
if C.cGoStorageDestroy(node.ctx, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageDestroy")
}
// We don't wait for the bridge here.
@ -288,58 +288,58 @@ func (node CodexNode) Destroy() error {
return nil
}
// Version returns the version of the Codex node.
func (node CodexNode) Version() (string, error) {
// Version returns the version of the Logos Storage node.
func (node StorageNode) Version() (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexVersion(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexVersion")
if C.cGoStorageVersion(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageVersion")
}
return bridge.wait()
}
func (node CodexNode) Revision() (string, error) {
func (node StorageNode) Revision() (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexRevision(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexRevision")
if C.cGoStorageRevision(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageRevision")
}
return bridge.wait()
}
// Repo returns the path of the data dir folder.
func (node CodexNode) Repo() (string, error) {
func (node StorageNode) Repo() (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexRepo(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexRepo")
if C.cGoStorageRepo(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageRepo")
}
return bridge.wait()
}
func (node CodexNode) Spr() (string, error) {
func (node StorageNode) Spr() (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexSpr(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexSpr")
if C.cGoStorageSpr(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageSpr")
}
return bridge.wait()
}
func (node CodexNode) PeerId() (string, error) {
func (node StorageNode) PeerId() (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexPeerId(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexPeerId")
if C.cGoStoragePeerId(node.ctx, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStoragePeerId")
}
return bridge.wait()

160
storage/node_test.go Normal file
View File

@ -0,0 +1,160 @@
package storage
import (
"fmt"
"testing"
"time"
)
func TestStorageVersion(t *testing.T) {
config := defaultConfigHelper(t)
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Logos Storage node: %v", err)
}
version, err := node.Version()
if err != nil {
t.Fatalf("Failed to get Logos Storage version: %v", err)
}
if version == "" {
t.Fatal("Logos Storage version is empty")
}
t.Logf("Logos Storage version: %s", version)
}
func TestStorageRevision(t *testing.T) {
config := defaultConfigHelper(t)
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Logos Storage node: %v", err)
}
revision, err := node.Revision()
if err != nil {
t.Fatalf("Failed to get Logos Storage revision: %v", err)
}
if revision == "" {
t.Fatal("Logos Storage revision is empty")
}
t.Logf("Logos Storage revision: %s", revision)
}
func TestStorageRepo(t *testing.T) {
node := newStorageNode(t)
repo, err := node.Repo()
if err != nil {
t.Fatalf("Failed to get Logos Storage repo: %v", err)
}
if repo == "" {
t.Fatal("Logos Storage repo is empty")
}
t.Logf("Logos Storage repo: %s", repo)
}
func TestSpr(t *testing.T) {
node := newStorageNode(t)
spr, err := node.Spr()
if err != nil {
t.Fatalf("Failed to get Logos Storage SPR: %v", err)
}
if spr == "" {
t.Fatal("Logos Storage SPR is empty")
}
t.Logf("Logos Storage SPR: %s", spr)
}
func TestPeerId(t *testing.T) {
node := newStorageNode(t)
peerId, err := node.PeerId()
if err != nil {
t.Fatalf("Failed to get Logos Storage PeerId: %v", err)
}
if peerId == "" {
t.Fatal("Logos Storage PeerId is empty")
}
t.Logf("Logos Storage PeerId: %s", peerId)
}
func TestStorageQuota(t *testing.T) {
node := newStorageNode(t, Config{
StorageQuota: 1024 * 1024 * 1024, // 1GB
})
if node == nil {
t.Fatal("expected Logos Storage node to be created")
}
}
func TestCreateAndDestroyMultipleInstancesWithSameDatadir(t *testing.T) {
t.Skip("Enable when the PR https://github.com/logos-storage/logos-storage-nim/pull/1364 is merged into master.")
datadir := fmt.Sprintf("%s/special-test", t.TempDir())
config := Config{
DataDir: datadir,
LogFormat: LogFormatNoColors,
MetricsEnabled: false,
BlockRetries: 5,
Nat: "none",
}
for range 2 {
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Logos Storage node: %v", err)
}
if err := node.Start(); err != nil {
t.Fatalf("Failed to start Logos Storage node: %v", err)
}
if err := node.Stop(); err != nil {
t.Fatalf("Failed to stop Logos Storage node: %v", err)
}
if err := node.Destroy(); err != nil {
t.Fatalf("Failed to stop Logos Storage node after restart: %v", err)
}
time.Sleep(100 * time.Millisecond)
}
}
func TestNumThreads(t *testing.T) {
node := newStorageNode(t, Config{
NumThreads: 1,
})
if node == nil {
t.Fatal("expected Logos Storage node to be created")
}
}
func TestBlockTtl(t *testing.T) {
node := newStorageNode(t, Config{
BlockTtl: "10H",
})
if node == nil {
t.Fatal("expected Logos Storage node to be created")
}
}
func TestBlockMaintenanceInterval(t *testing.T) {
node := newStorageNode(t, Config{
BlockMaintenanceInterval: "10H",
})
if node == nil {
t.Fatal("expected Logos Storage node to be created")
}
}

View File

@ -1,11 +1,11 @@
package codex
package storage
/*
#include "bridge.h"
#include <stdlib.h>
static int cGoCodexConnect(void* codexCtx, char* peerId, const char** peerAddresses, uintptr_t peerAddressesSize, void* resp) {
return codex_connect(codexCtx, peerId, peerAddresses, peerAddressesSize, (CodexCallback) callback, resp);
static int cGoStorageConnect(void* storageCtx, char* peerId, const char** peerAddresses, uintptr_t peerAddressesSize, void* resp) {
return storage_connect(storageCtx, peerId, peerAddresses, peerAddressesSize, (StorageCallback) callback, resp);
}
*/
import "C"
@ -18,8 +18,8 @@ import (
// otherwise the `peerId` is used to invoke peer discovery, if it succeeds
// the returned addresses will be used to dial.
// `peerAddresses` the listening addresses of the peers to dial,
// eg the one specified with `ListenAddresses` in `CodexConfig`.
func (node CodexNode) Connect(peerId string, peerAddresses []string) error {
// eg the one specified with `ListenAddresses` in `StorageConfig`.
func (node StorageNode) Connect(peerId string, peerAddresses []string) error {
bridge := newBridgeCtx()
defer bridge.free()
@ -33,12 +33,12 @@ func (node CodexNode) Connect(peerId string, peerAddresses []string) error {
defer C.free(unsafe.Pointer(cAddresses[i]))
}
if C.cGoCodexConnect(node.ctx, cPeerId, &cAddresses[0], C.uintptr_t(len(peerAddresses)), bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexConnect")
if C.cGoStorageConnect(node.ctx, cPeerId, &cAddresses[0], C.uintptr_t(len(peerAddresses)), bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageConnect")
}
} else {
if C.cGoCodexConnect(node.ctx, cPeerId, nil, 0, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexConnect")
if C.cGoStorageConnect(node.ctx, cPeerId, nil, 0, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageConnect")
}
}

View File

@ -1,4 +1,4 @@
package codex
package storage
import (
"log"
@ -6,27 +6,27 @@ import (
)
func TestConnectWithAddress(t *testing.T) {
var node1, node2 *CodexNode
var node1, node2 *StorageNode
var err error
t.Cleanup(func() {
if node1 != nil {
if err := node1.Stop(); err != nil {
t.Logf("cleanup codex1: %v", err)
t.Logf("cleanup storage1: %v", err)
}
if err := node1.Destroy(); err != nil {
t.Logf("cleanup codex1: %v", err)
t.Logf("cleanup storage1: %v", err)
}
}
if node2 != nil {
if err := node2.Stop(); err != nil {
t.Logf("cleanup codex2: %v", err)
t.Logf("cleanup storage2: %v", err)
}
if err := node2.Destroy(); err != nil {
t.Logf("cleanup codex2: %v", err)
t.Logf("cleanup storage2: %v", err)
}
}
})
@ -39,11 +39,11 @@ func TestConnectWithAddress(t *testing.T) {
Nat: "none",
})
if err != nil {
t.Fatalf("Failed to create codex1: %v", err)
t.Fatalf("Failed to create Logos Storage node 1: %v", err)
}
if err := node1.Start(); err != nil {
t.Fatalf("Failed to start codex1: %v", err)
t.Fatalf("Failed to start Logos Storage node 1: %v", err)
}
node2, err = New(Config{
@ -53,11 +53,11 @@ func TestConnectWithAddress(t *testing.T) {
DiscoveryPort: 8091,
})
if err != nil {
t.Fatalf("Failed to create codex2: %v", err)
t.Fatalf("Failed to create Logos Storage node 2: %v", err)
}
if err := node2.Start(); err != nil {
t.Fatalf("Failed to start codex2: %v", err)
t.Fatalf("Failed to start Logos Storage node 2: %v", err)
}
info2, err := node2.Debug()
@ -70,11 +70,11 @@ func TestConnectWithAddress(t *testing.T) {
}
}
func TestCodexWithPeerId(t *testing.T) {
var bootstrap, node1, node2 *CodexNode
func TestStorageWithPeerId(t *testing.T) {
var bootstrap, node1, node2 *StorageNode
var err error
bootstrap = newCodexNode(t, Config{
bootstrap = newStorageNode(t, Config{
DiscoveryPort: 8092,
})
@ -85,12 +85,12 @@ func TestCodexWithPeerId(t *testing.T) {
bootstrapNodes := []string{spr}
node1 = newCodexNode(t, Config{
node1 = newStorageNode(t, Config{
DiscoveryPort: 8090,
BootstrapNodes: bootstrapNodes,
})
node2 = newCodexNode(t, Config{
node2 = newStorageNode(t, Config{
DiscoveryPort: 8091,
BootstrapNodes: bootstrapNodes,
})

View File

@ -1,4 +1,4 @@
package codex
package storage
import (
"encoding/json"
@ -9,24 +9,24 @@ import (
#include "bridge.h"
#include <stdlib.h>
static int cGoCodexStorageList(void* codexCtx, void* resp) {
return codex_storage_list(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageStorageList(void* storageCtx, void* resp) {
return storage_list(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexStorageFetch(void* codexCtx, char* cid, void* resp) {
return codex_storage_fetch(codexCtx, cid, (CodexCallback) callback, resp);
static int cGoStorageStorageFetch(void* storageCtx, char* cid, void* resp) {
return storage_fetch(storageCtx, cid, (StorageCallback) callback, resp);
}
static int cGoCodexStorageSpace(void* codexCtx, void* resp) {
return codex_storage_space(codexCtx, (CodexCallback) callback, resp);
static int cGoStorageStorageSpace(void* storageCtx, void* resp) {
return storage_space(storageCtx, (StorageCallback) callback, resp);
}
static int cGoCodexStorageDelete(void* codexCtx, char* cid, void* resp) {
return codex_storage_delete(codexCtx, cid, (CodexCallback) callback, resp);
static int cGoStorageStorageDelete(void* storageCtx, char* cid, void* resp) {
return storage_delete(storageCtx, cid, (StorageCallback) callback, resp);
}
static int cGoCodexStorageExists(void* codexCtx, char* cid, void* resp) {
return codex_storage_exists(codexCtx, cid, (CodexCallback) callback, resp);
static int cGoStorageStorageExists(void* storageCtx, char* cid, void* resp) {
return storage_exists(storageCtx, cid, (StorageCallback) callback, resp);
}
*/
import "C"
@ -41,27 +41,27 @@ type Space struct {
TotalBlocks int `json:"totalBlocks"`
// QuotaMaxBytes is the maximum storage space (in bytes) available
// for the node in Codex's local repository.
// for the node in Logos Storage's local repository.
QuotaMaxBytes int64 `json:"quotaMaxBytes"`
// QuotaUsedBytes is the mount of storage space (in bytes) currently used
// for storing files in Codex's local repository.
// for storing files in Logos Storage's local repository.
QuotaUsedBytes int64 `json:"quotaUsedBytes"`
// QuotaReservedBytes is the amount of storage reserved (in bytes) in the
// Codex's local repository for future use when storage requests will be picked
// Logos Storage's local repository for future use when storage requests will be picked
// up and hosted by the node using node's availabilities.
// This does not include the storage currently in use.
QuotaReservedBytes int64 `json:"quotaReservedBytes"`
}
// Manifests returns the list of all manifests stored by the Codex node.
func (node CodexNode) Manifests() ([]Manifest, error) {
// Manifests returns the list of all manifests stored by the Logos Storage node.
func (node StorageNode) Manifests() ([]Manifest, error) {
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexStorageList(node.ctx, bridge.resp) != C.RET_OK {
return nil, bridge.callError("cGoCodexStorageList")
if C.cGoStorageStorageList(node.ctx, bridge.resp) != C.RET_OK {
return nil, bridge.callError("cGoStorageStorageList")
}
value, err := bridge.wait()
if err != nil {
@ -84,15 +84,15 @@ func (node CodexNode) Manifests() ([]Manifest, error) {
}
// Fetch download a file from the network and store it to the local node.
func (node CodexNode) Fetch(cid string) (Manifest, error) {
func (node StorageNode) Fetch(cid string) (Manifest, error) {
bridge := newBridgeCtx()
defer bridge.free()
var cCid = C.CString(cid)
defer C.free(unsafe.Pointer(cCid))
if C.cGoCodexStorageFetch(node.ctx, cCid, bridge.resp) != C.RET_OK {
return Manifest{}, bridge.callError("cGoCodexStorageFetch")
if C.cGoStorageStorageFetch(node.ctx, cCid, bridge.resp) != C.RET_OK {
return Manifest{}, bridge.callError("cGoStorageStorageFetch")
}
value, err := bridge.wait()
@ -111,14 +111,14 @@ func (node CodexNode) Fetch(cid string) (Manifest, error) {
}
// Space returns information about the storage space used and available.
func (node CodexNode) Space() (Space, error) {
func (node StorageNode) Space() (Space, error) {
var space Space
bridge := newBridgeCtx()
defer bridge.free()
if C.cGoCodexStorageSpace(node.ctx, bridge.resp) != C.RET_OK {
return space, bridge.callError("cGoCodexStorageSpace")
if C.cGoStorageStorageSpace(node.ctx, bridge.resp) != C.RET_OK {
return space, bridge.callError("cGoStorageStorageSpace")
}
value, err := bridge.wait()
@ -132,15 +132,15 @@ func (node CodexNode) Space() (Space, error) {
// Deletes either a single block or an entire dataset
// from the local node. Does nothing if the dataset is not locally available.
func (node CodexNode) Delete(cid string) error {
func (node StorageNode) Delete(cid string) error {
bridge := newBridgeCtx()
defer bridge.free()
var cCid = C.CString(cid)
defer C.free(unsafe.Pointer(cCid))
if C.cGoCodexStorageDelete(node.ctx, cCid, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexStorageDelete")
if C.cGoStorageStorageDelete(node.ctx, cCid, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageStorageDelete")
}
_, err := bridge.wait()
@ -148,15 +148,15 @@ func (node CodexNode) Delete(cid string) error {
}
// Exists checks if a given cid exists in the local storage.
func (node CodexNode) Exists(cid string) (bool, error) {
func (node StorageNode) Exists(cid string) (bool, error) {
bridge := newBridgeCtx()
defer bridge.free()
var cCid = C.CString(cid)
defer C.free(unsafe.Pointer(cCid))
if C.cGoCodexStorageExists(node.ctx, cCid, bridge.resp) != C.RET_OK {
return false, bridge.callError("cGoCodexStorageExists")
if C.cGoStorageStorageExists(node.ctx, cCid, bridge.resp) != C.RET_OK {
return false, bridge.callError("cGoStorageStorageExists")
}
result, err := bridge.wait()

View File

@ -1,11 +1,11 @@
package codex
package storage
import "testing"
func TestManifests(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
manifests, err := codex.Manifests()
manifests, err := storage.Manifests()
if err != nil {
t.Fatal(err)
}
@ -14,9 +14,9 @@ func TestManifests(t *testing.T) {
t.Fatal("expected manifests to be empty")
}
cid, _ := uploadHelper(t, codex)
cid, _ := uploadHelper(t, storage)
manifests, err = codex.Manifests()
manifests, err = storage.Manifests()
if err != nil {
t.Fatal(err)
}
@ -33,9 +33,9 @@ func TestManifests(t *testing.T) {
}
func TestSpace(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
space, err := codex.Space()
space, err := storage.Space()
if err != nil {
t.Fatal(err)
}
@ -56,9 +56,9 @@ func TestSpace(t *testing.T) {
t.Fatal("expected quota reserved bytes to be non-zero")
}
uploadHelper(t, codex)
uploadHelper(t, storage)
space, err = codex.Space()
space, err = storage.Space()
if err != nil {
t.Fatal(err)
}
@ -73,31 +73,31 @@ func TestSpace(t *testing.T) {
}
func TestFetch(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
cid, _ := uploadHelper(t, codex)
cid, _ := uploadHelper(t, storage)
_, err := codex.Fetch(cid)
_, err := storage.Fetch(cid)
if err != nil {
t.Fatal("expected error when fetching non-existent manifest")
}
}
func TestFetchCidDoesNotExist(t *testing.T) {
codex := newCodexNode(t, Config{BlockRetries: 1})
storage := newStorageNode(t, Config{BlockRetries: 1})
_, err := codex.Fetch("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku")
_, err := storage.Fetch("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku")
if err == nil {
t.Fatal("expected error when fetching non-existent manifest")
}
}
func TestDelete(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
cid, _ := uploadHelper(t, codex)
cid, _ := uploadHelper(t, storage)
manifests, err := codex.Manifests()
manifests, err := storage.Manifests()
if err != nil {
t.Fatal(err)
}
@ -105,12 +105,12 @@ func TestDelete(t *testing.T) {
t.Fatal("expected manifests to be empty after deletion")
}
err = codex.Delete(cid)
err = storage.Delete(cid)
if err != nil {
t.Fatal(err)
}
manifests, err = codex.Manifests()
manifests, err = storage.Manifests()
if err != nil {
t.Fatal(err)
}
@ -121,11 +121,11 @@ func TestDelete(t *testing.T) {
}
func TestExists(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
cid, _ := uploadHelper(t, codex)
cid, _ := uploadHelper(t, storage)
exists, err := codex.Exists(cid)
exists, err := storage.Exists(cid)
if err != nil {
t.Fatal(err)
}
@ -133,12 +133,12 @@ func TestExists(t *testing.T) {
t.Fatal("expected cid to exist")
}
err = codex.Delete(cid)
err = storage.Delete(cid)
if err != nil {
t.Fatal(err)
}
exists, err = codex.Exists(cid)
exists, err = storage.Exists(cid)
if err != nil {
t.Fatal(err)
}

View File

@ -1,4 +1,4 @@
package codex
package storage
import (
"bytes"
@ -18,7 +18,7 @@ func defaultConfigHelper(t *testing.T) Config {
}
}
func newCodexNode(t *testing.T, opts ...Config) *CodexNode {
func newStorageNode(t *testing.T, opts ...Config) *StorageNode {
config := defaultConfigHelper(t)
if len(opts) > 0 {
@ -63,33 +63,33 @@ func newCodexNode(t *testing.T, opts ...Config) *CodexNode {
node, err := New(config)
if err != nil {
t.Fatalf("Failed to create Codex node: %v", err)
t.Fatalf("Failed to create Logos Storage node: %v", err)
}
err = node.Start()
if err != nil {
t.Fatalf("Failed to start Codex node: %v", err)
t.Fatalf("Failed to start Logos Storage node: %v", err)
}
t.Cleanup(func() {
if err := node.Stop(); err != nil {
t.Logf("cleanup codex: %v", err)
t.Logf("cleanup storage: %v", err)
}
if err := node.Destroy(); err != nil {
t.Logf("cleanup codex: %v", err)
t.Logf("cleanup storage: %v", err)
}
})
return node
}
func uploadHelper(t *testing.T, codex *CodexNode) (string, int) {
func uploadHelper(t *testing.T, storage *StorageNode) (string, int) {
t.Helper()
buf := bytes.NewBuffer([]byte("Hello World!"))
len := buf.Len()
cid, err := codex.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf)
cid, err := storage.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf)
if err != nil {
t.Fatalf("Error happened during upload: %v\n", err)
}
@ -97,13 +97,13 @@ func uploadHelper(t *testing.T, codex *CodexNode) (string, int) {
return cid, len
}
func uploadBigFileHelper(t *testing.T, codex *CodexNode) (string, int) {
func uploadBigFileHelper(t *testing.T, storage *StorageNode) (string, int) {
t.Helper()
len := 1024 * 1024 * 50
buf := bytes.NewBuffer(make([]byte, len))
cid, err := codex.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf)
cid, err := storage.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf)
if err != nil {
t.Fatalf("Error happened during upload: %v\n", err)
}

View File

@ -1,27 +1,27 @@
package codex
package storage
/*
#include "bridge.h"
#include <stdlib.h>
static int cGoCodexUploadInit(void* codexCtx, char* filepath, size_t chunkSize, void* resp) {
return codex_upload_init(codexCtx, filepath, chunkSize, (CodexCallback) callback, resp);
static int cGoStorageUploadInit(void* storageCtx, char* filepath, size_t chunkSize, void* resp) {
return storage_upload_init(storageCtx, filepath, chunkSize, (StorageCallback) callback, resp);
}
static int cGoCodexUploadChunk(void* codexCtx, char* sessionId, const uint8_t* chunk, size_t len, void* resp) {
return codex_upload_chunk(codexCtx, sessionId, chunk, len, (CodexCallback) callback, resp);
static int cGoStorageUploadChunk(void* storageCtx, char* sessionId, const uint8_t* chunk, size_t len, void* resp) {
return storage_upload_chunk(storageCtx, sessionId, chunk, len, (StorageCallback) callback, resp);
}
static int cGoCodexUploadFinalize(void* codexCtx, char* sessionId, void* resp) {
return codex_upload_finalize(codexCtx, sessionId, (CodexCallback) callback, resp);
static int cGoStorageUploadFinalize(void* storageCtx, char* sessionId, void* resp) {
return storage_upload_finalize(storageCtx, sessionId, (StorageCallback) callback, resp);
}
static int cGoCodexUploadCancel(void* codexCtx, char* sessionId, void* resp) {
return codex_upload_cancel(codexCtx, sessionId, (CodexCallback) callback, resp);
static int cGoStorageUploadCancel(void* storageCtx, char* sessionId, void* resp) {
return storage_upload_cancel(storageCtx, sessionId, (StorageCallback) callback, resp);
}
static int cGoCodexUploadFile(void* codexCtx, char* sessionId, void* resp) {
return codex_upload_file(codexCtx, sessionId, (CodexCallback) callback, resp);
static int cGoStorageUploadFile(void* storageCtx, char* sessionId, void* resp) {
return storage_upload_file(storageCtx, sessionId, (StorageCallback) callback, resp);
}
*/
import "C"
@ -45,7 +45,7 @@ type UploadOptions struct {
// It is used to detect the mimetype.
Filepath string
// ChunkSize is the size of each upload chunk, passed as `blockSize` to the Codex node
// ChunkSize is the size of each upload chunk, passed as `blockSize` to the Logos Storage node
// store. Default is to 64 KB.
ChunkSize ChunkSize
@ -82,26 +82,26 @@ func getReaderSize(r io.Reader) int64 {
// It returns a session ID that can be used for subsequent upload operations.
// This function is called by UploadReader and UploadFile internally.
// You should use this function only if you need to manage the upload session manually.
func (node CodexNode) UploadInit(options *UploadOptions) (string, error) {
func (node StorageNode) UploadInit(options *UploadOptions) (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
var cFilename = C.CString(options.Filepath)
defer C.free(unsafe.Pointer(cFilename))
if C.cGoCodexUploadInit(node.ctx, cFilename, options.ChunkSize.toSizeT(), bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexUploadInit")
if C.cGoStorageUploadInit(node.ctx, cFilename, options.ChunkSize.toSizeT(), bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageUploadInit")
}
return bridge.wait()
}
// UploadChunk uploads a chunk of data to the Codex node.
// UploadChunk uploads a chunk of data to the Logos Storage node.
// It takes the session ID returned by UploadInit
// and a byte slice containing the chunk data.
// This function is called by UploadReader internally.
// You should use this function only if you need to manage the upload session manually.
func (node CodexNode) UploadChunk(sessionId string, chunk []byte) error {
func (node StorageNode) UploadChunk(sessionId string, chunk []byte) error {
bridge := newBridgeCtx()
defer bridge.free()
@ -113,8 +113,8 @@ func (node CodexNode) UploadChunk(sessionId string, chunk []byte) error {
cChunkPtr = (*C.uint8_t)(unsafe.Pointer(&chunk[0]))
}
if C.cGoCodexUploadChunk(node.ctx, cSessionId, cChunkPtr, C.size_t(len(chunk)), bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexUploadChunk")
if C.cGoStorageUploadChunk(node.ctx, cSessionId, cChunkPtr, C.size_t(len(chunk)), bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageUploadChunk")
}
_, err := bridge.wait()
@ -125,15 +125,15 @@ func (node CodexNode) UploadChunk(sessionId string, chunk []byte) error {
// It takes the session ID returned by UploadInit.
// This function is called by UploadReader and UploadFile internally.
// You should use this function only if you need to manage the upload session manually.
func (node CodexNode) UploadFinalize(sessionId string) (string, error) {
func (node StorageNode) UploadFinalize(sessionId string) (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
var cSessionId = C.CString(sessionId)
defer C.free(unsafe.Pointer(cSessionId))
if C.cGoCodexUploadFinalize(node.ctx, cSessionId, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexUploadFinalize")
if C.cGoStorageUploadFinalize(node.ctx, cSessionId, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageUploadFinalize")
}
return bridge.wait()
@ -142,31 +142,31 @@ func (node CodexNode) UploadFinalize(sessionId string) (string, error) {
// UploadCancel cancels an ongoing upload session.
// It can be only if the upload session is managed manually.
// It doesn't work with UploadFile.
func (node CodexNode) UploadCancel(sessionId string) error {
func (node StorageNode) UploadCancel(sessionId string) error {
bridge := newBridgeCtx()
defer bridge.free()
var cSessionId = C.CString(sessionId)
defer C.free(unsafe.Pointer(cSessionId))
if C.cGoCodexUploadCancel(node.ctx, cSessionId, bridge.resp) != C.RET_OK {
return bridge.callError("cGoCodexUploadCancel")
if C.cGoStorageUploadCancel(node.ctx, cSessionId, bridge.resp) != C.RET_OK {
return bridge.callError("cGoStorageUploadCancel")
}
_, err := bridge.wait()
return err
}
// UploadReader uploads data from an io.Reader to the Codex node.
// UploadReader uploads data from an io.Reader to the Logos Storage node.
// It takes the upload options and the reader as parameters.
// It returns the CID of the uploaded file or an error.
//
// Internally, it calls:
// - UploadInit to create the upload session.
// - UploadChunk to upload a chunk to codex.
// - UploadChunk to upload a chunk to storage.
// - UploadFinalize to finalize the upload session.
// - UploadCancel if an error occurs.
func (node CodexNode) UploadReader(ctx context.Context, options UploadOptions, r io.Reader) (string, error) {
func (node StorageNode) UploadReader(ctx context.Context, options UploadOptions, r io.Reader) (string, error) {
sessionId, err := node.UploadInit(&options)
if err != nil {
return "", err
@ -235,20 +235,20 @@ func (node CodexNode) UploadReader(ctx context.Context, options UploadOptions, r
}
// UploadReaderAsync is the asynchronous version of UploadReader using a goroutine.
func (node CodexNode) UploadReaderAsync(ctx context.Context, options UploadOptions, r io.Reader, onDone func(cid string, err error)) {
func (node StorageNode) UploadReaderAsync(ctx context.Context, options UploadOptions, r io.Reader, onDone func(cid string, err error)) {
go func() {
cid, err := node.UploadReader(ctx, options, r)
onDone(cid, err)
}()
}
// UploadFile uploads a file to the Codex node.
// UploadFile uploads a file to the Logos Storage node.
// It takes the upload options as parameter.
// It returns the CID of the uploaded file or an error.
//
// The options parameter contains the following fields:
// - filepath: the full path of the file to upload.
// - chunkSize: the size of each upload chunk, passed as `blockSize` to the Codex node
// - chunkSize: the size of each upload chunk, passed as `blockSize` to the Logos Storage node
// store. Default is to 64 KB.
// - onProgress: a callback function that is called after each chunk is uploaded with:
// - read: the number of bytes read in the last chunk.
@ -262,7 +262,7 @@ func (node CodexNode) UploadReaderAsync(ctx context.Context, options UploadOptio
// is sent to the stream.
//
// Internally, it calls UploadInit to create the upload session.
func (node CodexNode) UploadFile(ctx context.Context, options UploadOptions) (string, error) {
func (node StorageNode) UploadFile(ctx context.Context, options UploadOptions) (string, error) {
bridge := newBridgeCtx()
defer bridge.free()
@ -303,8 +303,8 @@ func (node CodexNode) UploadFile(ctx context.Context, options UploadOptions) (st
var cSessionId = C.CString(sessionId)
defer C.free(unsafe.Pointer(cSessionId))
if C.cGoCodexUploadFile(node.ctx, cSessionId, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoCodexUploadFile")
if C.cGoStorageUploadFile(node.ctx, cSessionId, bridge.resp) != C.RET_OK {
return "", bridge.callError("cGoStorageUploadFile")
}
// Create a done channel to signal the goroutine to stop
@ -349,7 +349,7 @@ func (node CodexNode) UploadFile(ctx context.Context, options UploadOptions) (st
}
// UploadFileAsync is the asynchronous version of UploadFile using a goroutine.
func (node CodexNode) UploadFileAsync(ctx context.Context, options UploadOptions, onDone func(cid string, err error)) {
func (node StorageNode) UploadFileAsync(ctx context.Context, options UploadOptions, onDone func(cid string, err error)) {
go func() {
cid, err := node.UploadFile(ctx, options)
onDone(cid, err)

View File

@ -1,4 +1,4 @@
package codex
package storage
import (
"bytes"
@ -11,13 +11,13 @@ import (
const expectedCID = "zDvZRwzmAkhzDRPH5EW242gJBNZ2T7aoH2v1fVH66FxXL4kSbvyM"
func TestUploadReader(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
totalBytes := 0
finalPercent := 0.0
buf := bytes.NewBuffer([]byte("Hello World!"))
len := buf.Len()
cid, err := codex.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt", OnProgress: func(read, total int, percent float64, err error) {
cid, err := storage.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt", OnProgress: func(read, total int, percent float64, err error) {
if err != nil {
log.Fatalf("Error happened during upload: %v\n", err)
}
@ -46,12 +46,12 @@ func TestUploadReader(t *testing.T) {
func TestUploadReaderCancel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
codex := newCodexNode(t)
storage := newStorageNode(t)
buf := bytes.NewBuffer(make([]byte, 1024*1024*10))
channelErr := make(chan error, 1)
go func() {
_, e := codex.UploadReader(ctx, UploadOptions{Filepath: "hello.txt"}, buf)
_, e := storage.UploadReader(ctx, UploadOptions{Filepath: "hello.txt"}, buf)
channelErr <- e
}()
@ -68,7 +68,7 @@ func TestUploadReaderCancel(t *testing.T) {
}
func TestUploadFile(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
totalBytes := 0
finalPercent := 0.0
@ -86,7 +86,7 @@ func TestUploadFile(t *testing.T) {
finalPercent = percent
}}
cid, err := codex.UploadFile(context.Background(), options)
cid, err := storage.UploadFile(context.Background(), options)
if err != nil {
t.Fatalf("UploadReader failed: %v", err)
}
@ -119,11 +119,11 @@ func TestUploadFileCancel(t *testing.T) {
}
tmpFile.Close()
codex := newCodexNode(t)
storage := newStorageNode(t)
channelError := make(chan error, 1)
go func() {
_, err := codex.UploadFile(ctx, UploadOptions{Filepath: tmpFile.Name()})
_, err := storage.UploadFile(ctx, UploadOptions{Filepath: tmpFile.Name()})
channelError <- err
}()
@ -140,11 +140,11 @@ func TestUploadFileCancel(t *testing.T) {
}
func TestUploadFileNoProgress(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
options := UploadOptions{Filepath: "./testdata/doesnt_exist.txt"}
cid, err := codex.UploadFile(context.Background(), options)
cid, err := storage.UploadFile(context.Background(), options)
if err == nil {
t.Fatalf("UploadReader should have failed")
}
@ -155,24 +155,24 @@ func TestUploadFileNoProgress(t *testing.T) {
}
func TestManualUpload(t *testing.T) {
codex := newCodexNode(t)
storage := newStorageNode(t)
sessionId, err := codex.UploadInit(&UploadOptions{Filepath: "hello.txt"})
sessionId, err := storage.UploadInit(&UploadOptions{Filepath: "hello.txt"})
if err != nil {
log.Fatal("Error happened:", err.Error())
}
err = codex.UploadChunk(sessionId, []byte("Hello "))
err = storage.UploadChunk(sessionId, []byte("Hello "))
if err != nil {
log.Fatal("Error happened:", err.Error())
}
err = codex.UploadChunk(sessionId, []byte("World!"))
err = storage.UploadChunk(sessionId, []byte("World!"))
if err != nil {
log.Fatal("Error happened:", err.Error())
}
cid, err := codex.UploadFinalize(sessionId)
cid, err := storage.UploadFinalize(sessionId)
if err != nil {
log.Fatal("Error happened:", err.Error())
}

1
vendor/logos-storage-nim vendored Submodule

@ -0,0 +1 @@
Subproject commit 60861d6af841d96085db366d44c1d543b7659fa5

1
vendor/nim-codex vendored

@ -1 +0,0 @@
Subproject commit 2b9fc1eb554e5eee43b8a815084fb8c61687ada9