---
title: "Handling Large Payloads with Binary Cache"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Handling Large Payloads with Binary Cache}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE
)
```

## Introduction

The Binary Cache is a temporary workspace provided by the MultiChain node. It allows R users to bypass memory limits by streaming data into the node in small pieces, publishing it as a single unit, and retrieving large outputs efficiently.

```{r setup}
library(multichainr)

# Set the path to your MultiChain binaries
mc_set_path(Sys.getenv("MULTICHAIN_PATH"))
```

## 1. Node Initialization

We start by initializing a local node and a temporary blockchain.

```{r init}
chain_name <- "cache_demo_chain"

# Create and start the node
mc_node_init(chain_name)
mc_node_start(chain_name)

# Wait for the node to initialize
Sys.sleep(3) 

# Connect to the local node
config <- mc_get_config(chain_name)
conn <- mc_connect(config)
```

## 2. Creating and Appending to Cache

When dealing with large data, you create a cache item and append data to it. This is more memory-efficient than creating one massive string in R.

```{r create_cache}
# 1. Create a new empty binary cache item
cache_id <- mc_create_binary_cache(conn)
cat("Binary Cache Identifier:", cache_id, "\n")

# 2. Append data in chunks (simulating a large file upload)
chunk1 <- "Binary-part-1-xyz-"
chunk2 <- "Binary-part-2-abc"

size1 <- mc_append_binary_cache(conn, cache_id, chunk1)
size2 <- mc_append_binary_cache(conn, cache_id, chunk2)

cat("Final size in cache:", size2, "bytes\n")
```

## 3. Publishing Off-chain Data

Once the data is assembled in the cache, we can publish it to a stream. By using the `offchain` option, the data remains in the node's local storage, and only its hash is recorded on the blockchain.

```{r publish_offchain}
# Create a stream and subscribe to it
mc_create_stream(conn, "large_files", open = TRUE)
mc_subscribe(conn, "large_files")

# Publish the data from the cache to the stream
# We pass the cache_id as the data parameter
txid <- mc_publish(conn, "large_files", "doc_01", cache_id, options = "offchain")

cat("Published off-chain item. Transaction ID:", txid, "\n")
```

## 4. Retrieving Data to a New Cache

When you need to read a large item published by another node, you can copy it directly from the transaction output into a *new* binary cache item.

```{r retrieve_cache}
# 1. Create a new cache item for the downloaded data
download_id <- mc_create_binary_cache(conn)

# 2. Copy the data from the blockchain transaction to the new cache
# MultiChain identifies stream data in the first output (vout = 0)
new_size <- mc_txout_to_binary_cache(conn, download_id, txid, vout = 0)

cat("Data successfully retrieved to cache item:", download_id, "(Size:", new_size, ")\n")
```

## 5. Inspecting and Deleting Cache

Finally, we can extract the hex data from the cache (or a specific part of it) and then delete the temporary items to free up disk space.

```{r cleanup_cache}
# Retrieve the full hex string from the output
# For extremely large items, you would use count_bytes and start_byte to read in chunks
hex_data <- mc_get_tx_out_data(conn, txid, vout = 0)

# Delete the cache items manually (important for long-running nodes)
mc_delete_binary_cache(conn, cache_id)
mc_delete_binary_cache(conn, download_id)

cat("Binary cache cleaned up.\n")
```

## 6. Cleanup

Always stop the node and remove the temporary data directory.

```{r cleanup}
# Stop the node
mc_node_stop(conn)
Sys.sleep(2)

# Determine data directory
if (.Platform$OS.type == "windows") {
  base_dir <- file.path(Sys.getenv("APPDATA"), "MultiChain")
} else if (Sys.info()["sysname"] == "Darwin") {
  base_dir <- file.path(Sys.getenv("HOME"), "Library/Application Support/MultiChain")
} else {
  base_dir <- file.path(Sys.getenv("HOME"), ".multichain")
}

chain_dir <- file.path(base_dir, chain_name)
if (dir.exists(chain_dir)) {
  unlink(chain_dir, recursive = TRUE)
}
```

## Summary

In this vignette, we demonstrated how to:

1.  **Initialize Binary Cache**: Creating a new temporary data item with `mc_create_binary_cache`.
2.  **Append Data**: Uploading data in chunks with `mc_append_binary_cache`.
3.  **Publish Off-chain**: Recording only a hash on the blockchain while keeping the large payload locally with `mc_publish`.
4.  **Retrieve to Cache**: Moving data from a transaction output directly back into a cache item with `mc_txout_to_binary_cache`.
5.  **Examine and Cleanup**: Reading the final data and deleting the temporary cache items with `mc_get_tx_out_data` and `mc_delete_binary_cache`.
