Rust HyperBEAM チュートリアル完全ガイド
HyperBEAM M3 ベータ版を使用した Rust デバイスの構築: mini-Roam API (Vol. 1)
この記事は、
をベースにチュートリアルしたものを日本語で書いたものです。著者: ラニ・エルフセイニ
公開日: 2025年6月16日
はじめに
ar.io のroam(パーマウェブコンテンツを見つけるためのツール)にヒントを得て、roamのミニバージョンを例に、カスタムRustデバイスを構築する新しいHyperBEAM開発者向けのガイドを作成しました。
HyperBEAMの最大の強みの1つは、ほぼすべてのコードをノード内にネイティブにラップし、合理的なREST標準とaoネットワークとの相互運用性を実現できることです。
このチュートリアルでは、最初から最後まで解説します。最後には、HyperBEAMノード内で動作するカスタムRustデバイスが完成します。これは、任意のデバイスをHyperBEAMに組み込むための基盤となるはずです。
前提条件
HyperBEAMノードを実行するには、以下のソフトウェアが必要です:
- Rust
- rebar3
- Erlang OTP27
- その他の依存関係
注意: インストールに必要なすべての前提条件とセットアップ方法については、hyperbeam.ar.ioにあるHyperBEAMの公式ドキュメントを参照してください。
インストールと初期化
1. リポジトリのクローンと実行
git clone -b edge https://github.com/permaweb/HyperBEAM
cd HyperBEAM
rebar3 compile
rebar3 shell
ノードはhttp://localhost:8734/
で実行されるはずです。
2. トラブルシューティング
動作しない場合は(特にUbuntuを使用している場合)、以下の手順を試してください:
erl -pa _build/default/lib/*/ebin
Erlangシェルで以下のコマンドを実行:
application:ensure_all_started(hb).
my_device Rustデバイス: ~roam@1.0 API
1. Rustクレートの初期化
cd native
cargo new my_device --lib
cd my_device
touch .gitignore
2. Cargo.tomlの設定
[package]
name = "my_device"
version = "0.1.0"
edition = "2024"
[lib]
name = "my_device"
path = "src/lib.rs"
crate-type = ["cdylib"]
[dependencies]
anyhow = "1.0.98"
rustler = "0.29.1"
ureq = {version = "3.0.11", features = ["json"]}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
3. .gitignoreの設定
/target
.env
4. 基本的なNIF関数の実装
lib.rs
に以下のコードを追加:
use rustler::NifResult;
mod atoms {
rustler::atoms! {
ok,
}
}
#[rustler::nif]
fn hello() -> NifResult<String> {
Ok("Hello world!".to_string())
}
rustler::init!(
"my_device_nif",
[hello]
);
ミニロームAPI機能の実装
1. コアディレクトリの作成
mkdir src/core
cd src/core
touch arweave.rs mod.rs
2. モジュールの設定
mod.rs
に以下を追加:
pub mod arweave;
lib.rs
のヘッダーに以下を追加:
pub mod core;
3. Arweaveクエリ機能の実装
arweave.rs
に以下のコードを追加:
use anyhow::Error;
use serde_json::Value;
use ureq;
pub fn query_permaweb() -> Result<String, Error> {
let url = "https://arweave-search.goldsky.com/graphql/graphql";
let query = r#"
query {
transactions(
first: 1
sort: HEIGHT_DESC
tags: [
{
name: "Content-Type"
values: [
"image/png"
"image/jpeg"
"image/webp"
"image/gif"
"image/svg+xml"
"image/avif"
]
op: EQ
match: EXACT
}
]
) {
edges {
node {
id
tags {
name
value
}
block {
id
height
timestamp
previous
}
}
}
}
}
"#;
let body = serde_json::json!({ "query": query });
let response = ureq::post(url)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("DNT", "1")
.header("Origin", "https://arweave-search.goldsky.com")
.send_json(body)?;
let json: Value = response.into_body().read_json()?;
let tx_id = &json["data"]["transactions"]["edges"][0]["node"]["id"];
let tx_id = tx_id.as_str().unwrap_or("No ID found").to_string();
Ok(tx_id)
}
4. テストの追加
lib.rs
の末尾に以下のテストコードを追加:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_query_permaweb() {
let id = query_permaweb().unwrap();
println!("TXID: {:?}", id);
assert_eq!(id.len(), 43);
}
}
5. DirtyCpuスケジューラの実装
lib.rs
に以下の関数を追加:
#[rustler::nif(schedule = "DirtyCpu")]
fn query() -> NifResult<String> {
query_permaweb().map_err(|err| Error::Term(Box::new(err.to_string())))
}
rustler::init!("my_device_nif", [hello, query]);
ビルドスクリプトの作成
ルートディレクトリにbuild.sh
を作成:
#!/bin/bash
set -e # Exit on any error
# Function to build and copy NIF
build_nif() {
local nif_name=$1
echo "Building ${nif_name}..."
cd native/${nif_name}
cargo build --release
mkdir -p ../../priv/crates/${nif_name}
cp target/release/lib${nif_name}.so ../../priv/crates/${nif_name}/${nif_name}.so
cd ../..
}
# Main script
echo "Starting deployment..."
# Build all NIFs
build_nif "my_device"
echo "All NIFs built and copied successfully"
実行権限を付与して実行:
chmod +x build.sh
./build.sh
Erlangインターフェースの実装
1. 必要なモジュールの作成
cd src
touch my_device_nif.erl dev_roam.erl
2. my_device_nif.erlの実装
-module(my_device_nif).
-export([hello/0, query/0]).
-on_load(init/0).
-define(NOT_LOADED, not_loaded(?LINE)).
-spec hello() -> binary().
hello() ->
?NOT_LOADED.
-spec query() -> binary().
query() ->
?NOT_LOADED.
init() ->
{ok, Cwd} = file:get_cwd(),
io:format("Current directory: ~p~n", [Cwd]),
PrivDir = case code:priv_dir(hb) of
{error, _} -> "priv";
Dir -> Dir
end,
NifPath = filename:join([PrivDir, "crates", "my_device", "my_device"]),
io:format("NIF path: ~p~n", [NifPath]),
NifSoPath = NifPath ++ ".so",
io:format("NIF .so exists: ~p~n", [filelib:is_file(NifSoPath)]),
Result = erlang:load_nif(NifPath, 0),
io:format("Load result: ~p~n", [Result]),
Result.
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
3. dev_roam.erlの実装
-module(dev_roam).
-export([info/1, info/3, query_permaweb/3, hello/3]).
info(_) ->
#{
<<"default">> => dev_message,
handlers => #{
<<"info">> => fun info/3,
<<"query_permaweb">> => fun query_permaweb/3,
<<"hello">> => fun hello/3
}
}.
info(_Msg1, _Msg2, _Opts) ->
InfoBody = #{
<<"description">> => <<"Roam device for interacting with my_device_nif">>,
<<"version">> => <<"1.0">>,
<<"paths">> => #{
<<"info">> => <<"Get device info">>,
<<"query_permaweb">> => <<"Query the Arweave permaweb">>,
<<"hello">> => <<"Simple hello world test">>
}
},
{ok, #{<<"status">> => 200, <<"body">> => InfoBody}}.
hello(_Msg1, _Msg2, _Opts) ->
try
Result = my_device_nif:hello(),
{ok, #{<<"status">> => 200, <<"body">> => Result}}
catch
error:Error:Stack ->
io:format("~nError: ~p~n", [Error]),
io:format("Stack: ~p~n", [Stack]),
{error, #{
<<"status">> => 500,
<<"body">> => #{
<<"error">> => <<"Failed to call hello">>,
<<"details">> => Error
}
}}
end.
query_permaweb(_Msg1, _Msg2, _Opts) ->
try
Result = my_device_nif:query(),
{ok, #{<<"status">> => 200, <<"body">> => Result}}
catch
error:Error:Stack ->
io:format("~nError: ~p~n", [Error]),
io:format("Stack: ~p~n", [Stack]),
{error, #{
<<"status">> => 500,
<<"body">> => #{
<<"error">> => <<"Failed to query permaweb">>,
<<"details">> => Error
}
}}
end.
4. 設定ファイルの更新
rebar3.config
に以下を追加:
{cargo_opts, [
{src_dir, "native/dev_snp_nif"},
{src_dir, "native/my_device"}
]}.
hb_opts.erl
のpreloaded_devices
リストに以下を追加:
#{<<"name">> => <<"roam@1.0">>, <<"module">> => dev_roam}
5. コンパイルと実行
rebar3 compile
rebar3 shell
動作確認
ブラウザで以下のURLにアクセスして動作確認ができます:
http://localhost:8734/~roam@1.0/query_permaweb
http://localhost:8734/~roam@1.0/hello
まとめ
このチュートリアルでは、roam.ar.ioに類似した機能を持つ基本的なAPIを構築しました。次のシリーズでは以下の内容を扱います:
- HyperBEAM内UIの開発方法
- GQLのさらなるカスタマイズ
- ブラウザ内データレンダリング
- クラウドでのHyperBEAMノードのホスティング方法
参考リソース
このデモのソースコードは以下のリポジトリで入手できます:
load_hb/edge-roam-demo
Discussion