Yumeville

Hello Holoチュートリアル

Hello Holoチュートリアル

おなじみのHello World Holoからチュートリアルをはじめしょう!

Holochainを使用すれば分散型アプリケーションを作成するのが非常に簡単なことが分かります。

セットアップ

  1. まずはインストールガイド(Mac/LinuxはこちらWindowsはこちら)を参照してHolochainツール一式をインストールしましょう。これにより、Holochain開発者ツールであるhcを含むアプリ開発環境が取得できます。
  2. 次にターミナルを開いてください(Windowsではコマンドプロンプト)。
  3. 開発環境に入ります。本来であれば、https://holochain.loveというコマンドを使用するのですが、このチュートリアルシリーズでは、ある特定のHolochainのリリースバージョン(0.0.29-alpha2)を使用するため、そのリリースバージョンのダウンロードリンクで開発環境に入ります。ちなみに、Holochainの全てのリリースバージョンは、https://github.com/holochain/holonix/releasesにあります。
    macOS / Linux(これは、インストールチュートリアルでのnix-shell https://holochain.loveと同様のコマンドで、今回はある特定のholochainリリースをダウンロードしています。):
    nix-shell https://github.com/holochain/holonix/archive/v0.0.31.tar.gz
    Windowsの場合はHolochainをインストールした場所で以下のコマンドを実行してください。
    vagrant up
    vagrant ssh
    nix-shell https://github.com/holochain/holonix/archive/v0.0.31.tar.gz

新しいアプリの初期化

これから読者が開発するすべてのHolochainアプリケーションが格納される場所を選んでください。 home_directory/holochain/のようなものです。

次にそのフォルダにcore conceptsという名前で、このチュートリアルシリーズのフォルダーを作成します。

cd ~
mkdir holochain
cd holochain
mkdir core concepts
cd core concepts

さて、早速holochainコマンドラインツール(hc)を使ってアプリを作成してみましょう。

以下のコマンドで新しいアプリを初期化した後に、そのアプリディレクトリに入りましょう。

<code>nix-shell</code>で実行

hc init cc_tuts
cd cc_tuts

コンパイル

アプリを頻繁にコンパイルすることは常に良いことです。そうすれば、早い段階でバグを発見できます。

試しにhcを使ってアプリをコンパイルしてみましょう。

<code>nix-shell</code>で実行
hc package

アプリをパッケージ化するということは、コードをコンパイルしてDNAファイルに変換し、アプリ実行のための準備をするということです。

次のようなメッセージが表示されればコンパイル成功です:
Created DNA package file at “/Users/username/holochain/testing_tuts/hello_holo/dist/hello_holo.dna.json” DNA hash: QmY7rhg4sf6xqQMRL1u1CnXVgmamTfxC59c9RaoFqM2eRs

Zome(染色体)を生成する

あなたのアプリはHolochainアプリの構成品であるZome(染色体)がまだ生成されていないので、現在は特に何もしていません。Zome(染色体)とは、アプリのソースコードを特定のタスク(Hello Worldなど)を実行する構成品の様なユニットに編成する方法です。

まずはHelloという名前でzomeのフォルダー内にzomeを生成しましょう。

<code>nix-shell</code>で実行
hc generate zomes/hello rust-proc

コンパイル

<code>nix-shell</code>で実行
hc package

注:Zomeは初めてコンパイルするのに少し時間がかかります。次回のコンパイル時には、コンパイルがはるかに速くなるので安心してください。アプリのコンパイル中に、次のステップに進みましょう。
<strong>すべてうまくいった場合は、次のように表示されます:</strong>

> cargo build –release –target=wasm32-unknown-unknown –target-dir=target Compiling hello v0.1.0 (/Users/username/holochain/core_concepts/hello_hollo/zomes/hello/code) Finished release [optimized] target(s) in 11.95s > cargo build –release –target=wasm32-unknown-unknown –target-dir=target Finished release [optimized] target(s) in 0.50s Created DNA package file at “/Users/username/holochain/core_concepts/hello_hollo/dist/hello_hollo.dna.json” DNA hash: QmdNyxke1Z9Kunws4WUXHnt4cdKQnPogC7YPpfQx67fo1z

フォルダーのレイアウト

フォルダーのレイアウトを見てみましょう。

Folder Layout

ZomeはRustプロジェクトであり、Rustの強力なマクロを使用したため、定型文的なコードを書く手間が大いに省けます。

読者が編集するメインのファイルはhello_hollo/zomes/code/src/lib.rsになります。

lib.rsエディターでファイルを開き、生成されたコードを見てみましょう。

下記にあるのは先ほどhc generate zomes/hello rust-procのコマンドでインポートされたすべてのRustクレートです。

あなたはRustに、「ねえ、私が仕事をするためにこれらすべてのクレートが必要だ」と宣言しました。

#![feature(proc_macro_hygiene)]
extern crate hdk;
extern crate hdk_proc_macros;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate holochain_json_derive;

次はuseキーワードです。これらのキーワードは、「上記のクレートからこれらの特定のものを使いたい」と言っています。このチュートリアルではいくつかのアイテムのみが必要なので、先に他のアイテムを削除しましょう。

#![feature(proc_macro_hygiene)]

– #[macro_use]

extern crate hdk;
extern crate hdk_proc_macros;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

– #[macro_use]

extern crate holochain_json_derive;
use hdk::{
–   entry_definition::ValidatingEntryType,
    error::ZomeApiResult,
};
– use hdk::holochain_core_types::{
– entry::Entry,
– dna::entry_types::Sharing,
– };

– use hdk::holochain_json_api::{
– json::JsonString,
– error::JsonError
– };

– use hdk::holochain_persistence_api::{
– cas::content::Address
– };

use hdk_proc_macros::zome;

上記の赤になっているものを削除すると下記のものが残るはずです。

use hdk::{
    error::ZomeApiResult,
};

use hdk_proc_macros::zome;

また、このチュートリアルでは、生成されたコードの中で不必要な部分がいくつかあるのでそれも削除しましょう。

まずは、次のコードを削除します。

– #[derive(Serialize, Deserialize, Debug, DefaultJson,Clone)]
– pub struct MyEntry {
– content: String,
– }

my_zomeという名前のモジュールがあると思いますが、これは読者のZomeコードが格納される場所です。#[zome]は、「下記のモジュールはこのZomeについてHolochainが知っておくべきすべてのことを定義していますよ」ということを示すプロシージャル・マクロです。このプロシージャルマクロのおかげでたくさんのコードを書く手間が省けます。

さあ、my_zomeをこのチュートリアル用にhello_zomeにまず変更しましょう。

#[zome]
– mod my_zome {
+ mod hello_zome {

下記のinit関数は、読者が開発したアプリのユーザーがアプリを初めて起動したときに実行されます。すべてのZomeは、いくつかの初期設定タスクを実行するためにこの関数を常に定義しています。今回のチュートリアルでは何もしないので特に追加するものはないです。また、このinit()関数は今回はResult型の空の値でOk(())を返しましょう。Ok()の中にある()はRustのユニット型と呼ばれるもので、同一ではありませんが、他の言語のvoid型に似ています。

#[init]
fn init() {
      Ok(())
}

下記の#[validate_agent]もまた、アプリケーションの起動時に実行されます。この関数は新しいユーザーが1回、そして既存のユーザーがもう1回実行します。この関数では、ユーザーがネットワークに参加できるための条件を定義することが出来、読者が自由に条件を設定することが可能です。今回は、全員に条件なしでネットワークへの参加を許可しましょう。

#[validate_agent] pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
     Ok(())
}

そして下記のテンプレートコードを削除しましょう。

– #[entry_def]
– fn my_entry_def() -> ValidatingEntryType {
– entry!(
– name: “my_entry”,
– description: “this is a same entry defintion”,
– sharing: Sharing::Public,
– validation_package: || {
– hdk::ValidationPackageDefinition::Entry
– },
– validation: | _validation_data: hdk::EntryValidationData<MyEntry>| {
– Ok(())
– }
– )
– }

– #[zome_fn(“hc_public”)]
– fn create_my_entry(entry: MyEntry) -> ZomeApiResult<Address> {
– let entry = Entry::App(“my_entry”.into(), entry.into());
– let address = hdk::commit_entry(&entry)?;
– Ok(address)
– }

– #[zome_fn(“hc_public”)]
– fn get_my_entry(address: Address) -> ZomeApiResult<Option<Entry>> {
– hdk::get_entry(&address)
– }

戻り値に関する注意事項

Rust言語では関数が何らかのResult値を返すことがよくあります。これは関数が成功したことを示すためのOk(some_value)、またはエラーを報告するためErr(some_error)を返す特別なRustの型です。先ほどのinitやvalidate_agentなど、必須であるHolochain関数は、アプリとコンダクターの間でデータを往復させるZomeApiResultと呼ばれる特別なresult型を返します。また、データを自動的にJSONに変換したり、JSONからRustの型に変換したりするため、Zomeのパブリック関数で使用するのにもふさわしい型です。

Helloを返す関数を追加しましょう :) 

次にHello Holoという文字列をパブリック関数から返すようにZomeに指示しましょう。

まずは先ほどのvalidate_agent関数を見つけてください。

pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
    Ok(())
}

この関数の後に、パブリックZome関数を定義します。

hc_publicというプロシージャルマクロは、その直下にある関数をGUIや他のZome、およびDNAから呼び出すことを可能にするマクロです。関数の名前、受け取るパラメーター、および返される値の型を記録し、Holochainがこの関数を適切に呼び出せるようにします。

では、hc_publicマクロを追加しましょう。

#[zome_fn(“hc_public”)]

次にhello_holoの関数を付け足しましょう。この関数hello_holoは引数が無く、HolochainのResult型であるZomeApiResultを返します。また、Holochainに、結果がOkであれば、そのOkに文字列を含むことを定義します。

さあ関数を追加しましょう。この関数はOk()の値を返し、その中にあいさつ文のHello Holoを注入します。into()というのは、Rust特有のトレイトで、ある型を定義された型に自動変換する役目があります。この場合では、関数で定義されている返り値の型がStringなので、strである”Hello Holo”をString型に変換します。

fn hello_holo() -> ZomeApiResult<String> {
    Ok(“Hello Holo”.into())
}

コンパイル

今のところこのようなコードになっているはずです。

コードのチェック

#![feature(proc_macro_hygiene)]
extern crate hdk;
extern crate hdk_proc_macros;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate holochain_json_derive;
use hdk::{
    error::ZomeApiResult,
};
use hdk_proc_macros::zome;

#[zome]
mod hello_zome {
    #[init]
    fn init() {
        Ok(())
    }
    #[validate_agent]
    pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
        Ok(())
    }
    #[zome_fn(“hc_public”)]
    fn hello_holo() -> ZomeApiResult<String> {
        Ok(“Hello Holo”.into())
    }
}

注:もしエラーが出た場合は、先に進む前に必ず修正してください。また、解決できない問題があれば常にこちらのフォーラムで助けを得ることができます。日本語で質問しても大丈夫なのでどんどん質問してください。
<code>nix-shell</code>で実行
hc package

HTTPを介してアプリと通信する

アプリケーションと通信するには、アプリをHTTPモードで実行しましょう。

<code>nix-shell</code>で実行
hc run -i http

TTP要求を作成するためのcurlを使用して、アプリにPOSTメッセージを送信しましょう。(curlはHolochain開発環境に含まれています。)

新しいターミナルウィンドウを開いて、nix-shellに再度入る必要があります。

nix-shell https://github.com/holochain/holonix/archive/v0.0.31.tar.gz

hello_holo関数を呼び出し、その返り値を返す下記のリクエストを入力しましょう。

<code>nix-shell</code>で実行

curl -X POST -H “Content-Type: application/json” -d ‘{“id”: “0”, “jsonrpc”: “2.0”, “method”: “call”, “params”: {“instance_id”: “test-instance”, “zome”: “hello”, “function”: “hello_holo”, “args”: {} }}’ http://127.0.0.1:8888

<strong>上手くいけば、hello_holo関数が返す文字列が下記のように表示されるはずです</strong>

{“jsonrpc”:“2.0”,“result”:“{\”Ok\”:\”Hello Holo\”}”,“id”:“0”}

おめでとう!これであなたの最初の分散型Holochainアプリケーションが作れました!