Compare commits

..

No commits in common. "master" and "v0.0.26" have entirely different histories.

30 changed files with 483 additions and 828 deletions

View File

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

View File

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

6
.gitignore vendored
View File

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

6
.gitmodules vendored
View File

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

88
.vscode/launch.json vendored
View File

@ -1,88 +0,0 @@
{
// 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": "Debug Current Test",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": [
"-test.v",
"-test.run",
"^${selectedText}$"
],
"env": {
"CGO_ENABLED": "1"
}
},
{
"name": "Debug Current Test Function",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"env": {
"CGO_ENABLED": "1"
}
},
{
"name": "Debug All Tests in Current File",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": [
"-test.v"
],
"env": {
"CGO_ENABLED": "1"
}
},
{
"name": "Debug All Tests in Current Package",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": [
"-test.v",
"-count=1"
],
"env": {
"CGO_ENABLED": "1"
}
},
{
"name": "Debug Logos Storage Tests",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${workspaceFolder}/storage",
"args": [
"-test.v"
],
"env": {
"CGO_ENABLED": "1"
}
},
{
"name": "Debug Specific Test (e.g., TestUpload)",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${workspaceFolder}/storage",
"args": [
"-test.v",
"-test.run",
"TestUpload"
],
"env": {
"CGO_ENABLED": "1"
}
}
]
}

View File

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

View File

@ -1,37 +1,3 @@
## v0.0.30 (2026-01-26)
### Notes
- Fix tests long path on Windows
## v0.0.29 (2026-01-26)
### Notes
- Fix: use Nat: "none" in recently added tests
- Build: small updates to dev env: debugging, gotestsum and makefile
- Chore: rename Codex to Logos
## v0.0.28 (2026-01-23)
### Notes
- chore: rename `Codex` to `Storage`
## v0.0.28 (2025-11-14)
### Notes
- fix: bump nim codex to prevent datastore lock when closing the Codex client
- fix: configuration duration for block-ttl, block-mi and int for num-threads
## v0.0.27 (2025-11-11)
### Notes
- Enhance release note in
- Bump nim-codex to prototype release branch
## v0.0.26 (2025-11-03)
### Notes
- Bump `nim-codex` to prototype release branch
## v0.0.25 (2025-11-03) ## v0.0.25 (2025-11-03)
### Notes ### Notes

View File

@ -1,13 +1,13 @@
# Makefile for Logos Storage Go Bindings # Makefile for Codex Go Bindings
LOGOS_STORAGE_NIM_DIR := vendor/logos-storage-nim NIM_CODEX_DIR := vendor/nim-codex
LOGOS_STORAGE_NIM_LIB_DIR := $(abspath $(LOGOS_STORAGE_NIM_DIR)/library) NIM_CODEX_LIB_DIR := $(abspath $(NIM_CODEX_DIR)/library)
LOGOS_STORAGE_NIM_BUILD_DIR := $(abspath $(LOGOS_STORAGE_NIM_DIR)/build) NIM_CODEX_BUILD_DIR := $(abspath $(NIM_CODEX_DIR)/build)
CGO_CFLAGS := -I$(LOGOS_STORAGE_NIM_LIB_DIR) CGO_CFLAGS := -I$(NIM_CODEX_LIB_DIR)
CGO_LDFLAGS := -L$(LOGOS_STORAGE_NIM_BUILD_DIR) -lstorage -Wl,-rpath,$(LOGOS_STORAGE_NIM_BUILD_DIR) CGO_LDFLAGS := -L$(NIM_CODEX_BUILD_DIR) -lcodex -Wl,-rpath,$(NIM_CODEX_BUILD_DIR)
.PHONY: all clean update libstorage build test .PHONY: all clean update libcodex build test
all: build all: build
@ -16,33 +16,22 @@ submodules:
@git submodule update --init --recursive @git submodule update --init --recursive
update: | submodules update: | submodules
@echo "Updating logos-storage-nim..." @echo "Updating nim-codex..."
@$(MAKE) -C $(LOGOS_STORAGE_NIM_DIR) update @$(MAKE) -C $(NIM_CODEX_DIR) update
libstorage: libcodex:
@echo "Building libstorage..." @echo "Building libcodex..."
@$(MAKE) -C $(LOGOS_STORAGE_NIM_DIR) libstorage @$(MAKE) -C $(NIM_CODEX_DIR) libcodex
libstorage-with-debug-api:
@echo "Building libstorage..."
@$(MAKE) -C $(LOGOS_STORAGE_NIM_DIR) libstorage STORAGE_LIB_PARAMS="-d:storage_enable_api_debug_peers"
build: build:
@echo "Building Logos Storage Go Bindings..." @echo "Building Codex Go Bindings..."
CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go build -o storage-go ./storage CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go build -o codex-go ./codex
test: test:
@echo "Running tests..." @echo "Running tests..."
CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOTESTFLAGS="-timeout=2m" gotestsum --packages="./..." -f testname -- $(if $(filter-out test,$(MAKECMDGOALS)),-run "$(filter-out test,$(MAKECMDGOALS))") CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOTESTFLAGS="-timeout=2m" go test ./...
test-with-params:
@echo "Running tests..."
CGO_ENABLED=1 CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOTESTFLAGS="-timeout=2m" gotestsum --packages="./..." -f testname -- $(ARGS)
%:
@:
clean: clean:
@echo "Cleaning up..." @echo "Cleaning up..."
@git submodule deinit -f $(LOGOS_STORAGE_NIM_DIR) @git submodule deinit -f $(NIM_CODEX_DIR)
@rm -f storage-go @rm -f codex-go

109
README.md
View File

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

View File

@ -23,74 +23,7 @@ git push --tags
Once published, the artifacts can be downloaded using the `version`, example: Once published, the artifacts can be downloaded using the `version`, example:
`https://github.com/logos-storage/logos-storage-go-bindings/releases/download/v0.0.16/storage-linux-amd64.zip` `https://github.com/codex-storage/codex-go-bindings/releases/download/v0.0.16/codex-linux-amd64.zip`
It is not recommended to use the `latest` URL because you may face cache issues. It is not recommended to use the `latest` URL because you may face cache issues.
## Integration
Once released, you can integrate it into your Go project using:
```bash
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)
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-libstorage:
mkdir -p $(LIBS_DIR); \
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;
```
`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/logos-storage/logos-storage-go-bindings/releases/download/v0.0.26/storage-macos-arm64.zip | jq -r .hash
# [10.4 MiB DL] sha256-3CHIWoSjo0plsYqzXQWm1EtY1STcljV4yfXTPon90uE=
```
Then include this hash in your Nix configuration. For example:
```nix
let
optionalString = pkgs.lib.optionalString;
storageVersion = "v0.0.26";
arch =
if stdenv.hostPlatform.isx86_64 then "amd64"
else if stdenv.hostPlatform.isAarch64 then "arm64"
else stdenv.hostPlatform.arch;
os = if stdenv.isDarwin then "macos" else "Linux";
hash =
if stdenv.hostPlatform.isDarwin
# 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/logos-storage/logos-storage-go-bindings/releases/download/v0.0.26/storage-Linux-amd64.zip | jq -r .hash
else "sha256-YxW2vFZlcLrOx1PYgWW4MIstH/oFBRF0ooS0sl3v6ig=";
# 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="${storageLib}"
# Build something cool with Logos Storage
'';
```

View File

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

View File

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

View File

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

81
codex/codex_test.go Normal file
View File

@ -0,0 +1,81 @@
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)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package storage package codex
import ( import (
"bytes" "bytes"
@ -14,11 +14,11 @@ func defaultConfigHelper(t *testing.T) Config {
LogFormat: LogFormatNoColors, LogFormat: LogFormatNoColors,
MetricsEnabled: false, MetricsEnabled: false,
BlockRetries: 3000, BlockRetries: 3000,
Nat: "none", LogLevel: "ERROR",
} }
} }
func newStorageNode(t *testing.T, opts ...Config) *StorageNode { func newCodexNode(t *testing.T, opts ...Config) *CodexNode {
config := defaultConfigHelper(t) config := defaultConfigHelper(t)
if len(opts) > 0 { if len(opts) > 0 {
@ -43,53 +43,37 @@ func newStorageNode(t *testing.T, opts ...Config) *StorageNode {
if c.DiscoveryPort != 0 { if c.DiscoveryPort != 0 {
config.DiscoveryPort = c.DiscoveryPort config.DiscoveryPort = c.DiscoveryPort
} }
if c.StorageQuota != 0 {
config.StorageQuota = c.StorageQuota
}
if c.NumThreads != 0 {
config.NumThreads = c.NumThreads
}
if c.BlockTtl != "" {
config.BlockTtl = c.BlockTtl
}
if c.BlockMaintenanceInterval != "" {
config.BlockMaintenanceInterval = c.BlockMaintenanceInterval
}
} }
node, err := New(config) node, err := New(config)
if err != nil { if err != nil {
t.Fatalf("Failed to create Logos Storage node: %v", err) t.Fatalf("Failed to create Codex node: %v", err)
} }
err = node.Start() err = node.Start()
if err != nil { if err != nil {
t.Fatalf("Failed to start Logos Storage node: %v", err) t.Fatalf("Failed to start Codex node: %v", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
if err := node.Stop(); err != nil { if err := node.Stop(); err != nil {
t.Logf("cleanup storage: %v", err) t.Logf("cleanup codex: %v", err)
} }
if err := node.Destroy(); err != nil { if err := node.Destroy(); err != nil {
t.Logf("cleanup storage: %v", err) t.Logf("cleanup codex: %v", err)
} }
}) })
return node return node
} }
func uploadHelper(t *testing.T, storage *StorageNode) (string, int) { func uploadHelper(t *testing.T, codex *CodexNode) (string, int) {
t.Helper() t.Helper()
buf := bytes.NewBuffer([]byte("Hello World!")) buf := bytes.NewBuffer([]byte("Hello World!"))
len := buf.Len() len := buf.Len()
cid, err := storage.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf) cid, err := codex.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf)
if err != nil { if err != nil {
t.Fatalf("Error happened during upload: %v\n", err) t.Fatalf("Error happened during upload: %v\n", err)
} }
@ -97,13 +81,13 @@ func uploadHelper(t *testing.T, storage *StorageNode) (string, int) {
return cid, len return cid, len
} }
func uploadBigFileHelper(t *testing.T, storage *StorageNode) (string, int) { func uploadBigFileHelper(t *testing.T, codex *CodexNode) (string, int) {
t.Helper() t.Helper()
len := 1024 * 1024 * 50 len := 1024 * 1024 * 50
buf := bytes.NewBuffer(make([]byte, len)) buf := bytes.NewBuffer(make([]byte, len))
cid, err := storage.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf) cid, err := codex.UploadReader(context.Background(), UploadOptions{Filepath: "hello.txt"}, buf)
if err != nil { if err != nil {
t.Fatalf("Error happened during upload: %v\n", err) t.Fatalf("Error happened during upload: %v\n", err)
} }

View File

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

View File

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

2
go.mod
View File

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

View File

@ -1,158 +0,0 @@
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) {
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")
}
}

@ -1 +0,0 @@
Subproject commit 3c09f008bb5266a669fd19f18368f9e8b861b664

1
vendor/nim-codex vendored Submodule

@ -0,0 +1 @@
Subproject commit 480bd3b65917da0f90ea43146bd73986ef5272e0