Skip to content

Storage Module Tutorial

In this tutorial, you will build a simple CLI application that uploads and downloads files over the Logos Storage network using the Logos Storage Module API.

We provide a Logos Storage App Skeleton that gives you a ready-made entry point with access to the LogosModules object (m_logos) and Qt-compatible synchronization utilities.

Prerequisites

  • Nix package manager
  • Git

Building the Skeleton App

  1. Clone the skeleton repository:

    Terminal window
    git clone https://github.com/logos-storage/logos-storage-app-skeleton.git
    cd logos-storage-app-skeleton
  2. Build with Nix:

    Terminal window
    nix build
  3. The compiled binary will be at ./result/bin/storage-app.

The skeleton provides an app_main entry point with access to the LogosModules object (referred to as m_logos in the API documentation). It also provides Qt-compatible synchronization utilities for blocking on asynchronous operations.

Initializing the Module

Before performing any operations, initialize the storage module with a JSON configuration string. See the Configuration Reference for all available options.

const QString jsonConfig = "{}";
bool result = m_logos->storage_module.init(jsonConfig);

Starting the Node

Start the node and listen for the completion event:

m_logos->storage_module.on("storageStart", [this](const QVariantList& data) {
bool success = data[0].toBool();
if (!success) {
QString error = data[1].toString();
// Handle error
}
});
bool result = m_logos->storage_module.start();

Uploading a File

The simplest way to upload a file is with uploadUrl:

// Subscribe to events
m_logos->storage_module.on("storageUploadDone", [this](const QVariantList& data) {
bool success = data[0].toBool();
QString sessionId = data[1].toString();
QString cidOrError = data[2].toString();
if (success) {
qDebug() << "Upload complete. CID:" << cidOrError;
} else {
qDebug() << "Upload failed:" << cidOrError;
}
});
m_logos->storage_module.on("storageUploadProgress", [this](const QVariantList& data) {
bool success = data[0].toBool();
QString sessionId = data[1].toString();
int bytes = data[2].toInt();
qDebug() << "Uploaded" << bytes << "bytes";
});
// Start the upload
QUrl fileUrl = QUrl::fromLocalFile("/path/to/myfile");
LogosResult result = m_logos->storage_module.uploadUrl(fileUrl);

The upload returns a CID (Content Identifier) — a string that uniquely identifies the file within the network.

Streaming Upload

For more control, use the streaming upload API:

// 1. Initialize the session
LogosResult result = m_logos->storage_module.uploadInit(filename);
QString sessionId = result.getValue<QString>();
// 2. Upload chunks
QFile file(filepath);
file.open(QIODevice::ReadOnly);
int chunkSize = 1024 * 64;
while (!file.atEnd()) {
QByteArray chunk = file.read(chunkSize);
result = m_logos->storage_module.uploadChunk(sessionId, chunk);
if (!result.success) {
// Handle error
break;
}
}
// 3. Finalize
result = m_logos->storage_module.uploadFinalize(sessionId);
if (result.success) {
QString cid = result.getValue<QString>();
qDebug() << "CID:" << cid;
}

Downloading a File

To download content, you need the CID and the Signed Peer Record (SPR) of a node that has the content:

// Subscribe to events
m_logos->storage_module.on("storageDownloadDone", [this](const QVariantList& data) {
bool success = data[0].toBool();
QString message = data[1].toString();
if (success) {
qDebug() << "Download complete";
} else {
qDebug() << "Download failed:" << message;
}
});
m_logos->storage_module.on("storageDownloadProgress", [this](const QVariantList& data) {
bool success = data[0].toBool();
QString sessionId = data[1].toString();
int size = data[2].toInt();
qDebug() << "Downloaded" << size << "bytes";
});
// Start the download
QUrl destination = QUrl::fromLocalFile("/path/to/output");
LogosResult result = m_logos->storage_module.downloadToUrl(cid, destination);

Cleaning Up

Always stop the node before destroying resources:

LogosResult result = m_logos->storage_module.stop();
// Wait for storageStop event...
result = m_logos->storage_module.destroy();

Headless Mode

The storage module can also be run from the command line without a UI:

Terminal window
./logos/bin/logoscore -m ./modules --load-modules storage_module \
-c "storage_module.init(@config.json)" \
-c "storage_module.start()" \
-c "storage_module.importFiles(/path/to/files)"

Next Steps