<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: voluntas</title>
    <description>The latest articles on Forem by voluntas (@voluntas).</description>
    <link>https://forem.com/voluntas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F41972%2F39a72f12-de3e-4a91-92f5-02397b295ac7.jpeg</url>
      <title>Forem: voluntas</title>
      <link>https://forem.com/voluntas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/voluntas"/>
    <language>en</language>
    <item>
      <title>Released a TOML library with zero dependencies in Rust.</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Sat, 07 Mar 2026 05:38:59 +0000</pubDate>
      <link>https://forem.com/shiguredo/released-a-toml-library-with-zero-dependencies-in-rust-1boe</link>
      <guid>https://forem.com/shiguredo/released-a-toml-library-with-zero-dependencies-in-rust-1boe</guid>
      <description>&lt;p&gt;Shiguredo has begun shifting its development focus from C++ to Rust. As part of this transition, we've been implementing various libraries in Rust, and this time we've released a TOML library.&lt;/p&gt;

&lt;p&gt;By default, Shiguredo uses the JSONC format when developing applications in Rust. JSONC is an incompatible extension of JSON that allows comments and trailing commas, making it convenient to use.&lt;/p&gt;

&lt;p&gt;Additionally, the nojson dependency-free JSON library supports it.&lt;br&gt;
However, Rust is primarily designed for TOML usage. Despite this, the default library does not include TOML support, and most major TOML libraries have significant dependencies. Therefore, we decided to develop our own TOML implementation with minimized dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  shiguredo/toml-rs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dependencies: 0&lt;/li&gt;
&lt;li&gt;Supports TOML v1.0.0 and v1.1.0 specifications&lt;/li&gt;
&lt;li&gt;Compatible with toml-test&lt;/li&gt;
&lt;li&gt;Fuzzing support&lt;/li&gt;
&lt;li&gt;Rewriting functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;toml-test is a testing suite officially provided by the TOML project. A score of 100% indicates full compatibility, making this product technically "fully compatible."&lt;/p&gt;

&lt;p&gt;We have prioritized robustness by thoroughly implementing fuzzing and ensuring the code remains stable under unexpected inputs.&lt;/p&gt;

&lt;p&gt;Following user requests, we've added rewriting functionality. We implemented this feature by adapting nojson's positional tracking mechanism. After addressing several identified bugs, we've released this version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/shiguredo/toml-rs" rel="noopener noreferrer"&gt;https://github.com/shiguredo/toml-rs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;While we strive to minimize dependencies by building our own libraries, the result is both comfortable to use and highly maintainable. The reduced dependency footprint makes maintenance easier, and having our own libraries provides the advantage of complete control.&lt;/p&gt;

</description>
      <category>rust</category>
    </item>
    <item>
      <title>Netlify で WebAssembly バイナリを Git LFS 経由でデプロイして配信する</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Tue, 03 Nov 2020 13:56:54 +0000</pubDate>
      <link>https://forem.com/voluntas/netlify-webassembly-1648</link>
      <guid>https://forem.com/voluntas/netlify-webassembly-1648</guid>
      <description>&lt;p&gt;Netlify は静的ファイルを配信する素敵サービスです。Git 連携してくれるので Git に Push するだけで、ビルドしてデプロイしてくれたりします。&lt;/p&gt;

&lt;p&gt;無料で使えるので、触ったことない人は触ってみることをおすすめします。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.netlify.com/"&gt;https://www.netlify.com/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  WebAssembly バイナリを Netlify にデプロイして配信したい
&lt;/h2&gt;

&lt;p&gt;Go 経由で出力した WebAssembly バイナリを Netlify にデプロイしてみたのですが、自分がやりたいことを満たしていたので簡単にまとめておきます。&lt;/p&gt;

&lt;p&gt;やったことは dist/ というフォルダに Git LFS を利用して WebAssembly バイナリを追加し、 dist/ をデプロイしてみました。&lt;/p&gt;

&lt;p&gt;利用した機能は Netlify Large Media という機能です。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.netlify.com/products/large-media/"&gt;https://www.netlify.com/products/large-media/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;簡単に言えば Git LFS で登録しておいた大きめのバイナリデータを配信してくれる機能です。&lt;/p&gt;

&lt;p&gt;使い方はドキュメントを読めばそのままなので解説は特にしません。&lt;br&gt;
ただ Git LFS と netlify-cli というコマンドが必要になります。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.netlify.com/large-media/overview"&gt;https://docs.netlify.com/large-media/overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;結果、配信されたファイルを&lt;a href="https://twitter.com/xcir"&gt;キャッシュに詳しい人&lt;/a&gt;にチェックしてもらったところ ...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;content-type は application/wasm で問題ない&lt;/li&gt;
&lt;li&gt;content-encoding は br で brotli で圧縮されて配信されていた&lt;/li&gt;
&lt;li&gt;cache-control は public, max-age=0, must-revalidate でキャッシュされるけど即座に入れ替わる(max-age=0)し仮に取得できなくてもすでに持ってるキャッシュを再利用しない(must-revalidate)&lt;/li&gt;
&lt;li&gt;age が増えてるのでキャッシュが挟まっていそう&lt;/li&gt;
&lt;li&gt;容量が 2.9 MB 近いが問題なくデプロイされた&lt;/li&gt;
&lt;li&gt;Pro プランであれば 400G 転送量があるのでよほどのことがない限り困らなさそう&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;無事 WebAssembly バイナリが Netlify にがデプロイされ配信できました。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NpiSNJln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.gyazo.com/b993de3ef916922d7b5d469dec8694cf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NpiSNJln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.gyazo.com/b993de3ef916922d7b5d469dec8694cf.png" alt="image" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>netlify</category>
      <category>git</category>
    </item>
    <item>
      <title>GitHub Actions で Erlang/OTP なクローズドソースのミドルウェアのテストをする</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Sat, 31 Oct 2020 10:34:04 +0000</pubDate>
      <link>https://forem.com/voluntas/github-actions-erlang-otp-4hlo</link>
      <guid>https://forem.com/voluntas/github-actions-erlang-otp-4hlo</guid>
      <description>&lt;p&gt;CircleCI から GitHub に移行するにあたって試行錯誤したのでメモとして残しておきます。&lt;/p&gt;

&lt;h2&gt;
  
  
  結論
&lt;/h2&gt;

&lt;p&gt;テスト用の Docker コンテナを利用せず Github Actions の action/cache を活用するのがメンテナンス的にも楽。&lt;/p&gt;

&lt;h2&gt;
  
  
  利用した actions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/actions/checkout"&gt;https://github.com/actions/checkout&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;v2 がでているので v2 を使うようにしましょう。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$GITHUB_WORKSPACE&lt;/code&gt; が使えるようになっています、便利。&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/actions/cache"&gt;https://github.com/actions/cache&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;今回のメインはこの cache です。&lt;/p&gt;

&lt;p&gt;GitHub Actions で Erlang を自分設定したビルドで利用する場合は Docker を使うよりこの cache 機能を使うことをおすすめします。&lt;/p&gt;

&lt;p&gt;このキャッシュ機能は本当に優秀です。&lt;/p&gt;

&lt;p&gt;まず OS は ubuntu-latest で env で OpenSSL と Erlang/OTP のバージョンを指定するようにしました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;OPENSSL_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.1.1h&lt;/span&gt;
  &lt;span class="na"&gt;ERLANG_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;23.1.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;あとはキャッシュを活用します。Linux 以外では想定していないため key からプラットフォーム指定は外しています。キャッシュがなかったらビルドする、キャッシュがあったらそれを使うといったシンプルなものです。&lt;/p&gt;

&lt;p&gt;シンプルに書いたので、メンテコストもとても軽めです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v2&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openssl-cache&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/opt/openssl/${{ env.OPENSSL_VERSION }}&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openssl-${{ env.OPENSSL_VERSION }}&lt;/span&gt;
    &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;openssl-&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.openssl-cache.outputs.cache-hit != 'true'&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;curl -LO https://www.openssl.org/source/openssl-${{ env.OPENSSL_VERSION }}.tar.gz&lt;/span&gt;
    &lt;span class="s"&gt;tar xvfz openssl-${{ env.OPENSSL_VERSION }}.tar.gz&lt;/span&gt;
    &lt;span class="s"&gt;cd openssl-${{ env.OPENSSL_VERSION }}&lt;/span&gt;
    &lt;span class="s"&gt;./config --prefix=/opt/openssl/${{ env.OPENSSL_VERSION }}&lt;/span&gt;
    &lt;span class="s"&gt;make -j&lt;/span&gt;
    &lt;span class="s"&gt;sudo make install&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v2&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;erlang-cache&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/opt/erlang/${{ env.ERLANG_VERSION }}&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;erlang-${{ env.ERLANG_VERSION }}&lt;/span&gt;
    &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;erlang-&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.erlang-cache.outputs.cache-hit != 'true'&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;git clone https://github.com/erlang/otp&lt;/span&gt;
    &lt;span class="s"&gt;cd otp&lt;/span&gt;
    &lt;span class="s"&gt;git checkout OTP-${{ env.ERLANG_VERSION }}&lt;/span&gt;
    &lt;span class="s"&gt;./otp_build autoconf&lt;/span&gt;
    &lt;span class="s"&gt;./configure --prefix=/opt/erlang/${{ env.ERLANG_VERSION }} \&lt;/span&gt;
                &lt;span class="s"&gt;--enable-kernel-poll \&lt;/span&gt;
                &lt;span class="s"&gt;--enable-dirty-schedulers \&lt;/span&gt;
                &lt;span class="s"&gt;--disable-sctp \&lt;/span&gt;
                &lt;span class="s"&gt;--disable-dynamic-ssl-lib \&lt;/span&gt;
                &lt;span class="s"&gt;--disable-sharing-preserving \&lt;/span&gt;
                &lt;span class="s"&gt;--disable-hipe \&lt;/span&gt;
                &lt;span class="s"&gt;--disable-native-libs \&lt;/span&gt;
                &lt;span class="s"&gt;--with-ssl=/opt/openssl/${{ env.OPENSSL_VERSION }} \&lt;/span&gt;
                &lt;span class="s"&gt;--without-javac \&lt;/span&gt;
                &lt;span class="s"&gt;--without-odbc&lt;/span&gt;
    &lt;span class="s"&gt;make -j&lt;/span&gt;
    &lt;span class="s"&gt;make install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;キャッシュ容量は 5G まで使えるので本当に助かります。&lt;/p&gt;

&lt;h4&gt;
  
  
  rebar3 キャッシュ
&lt;/h4&gt;

&lt;p&gt;rebar3 で依存ライブラリを引っ張ってくるコストもばかにならないのでキャッシュしてしまっています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v2&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rebar3-deps-cache&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$GITHUB_WORKSPACE/_build&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rebar3-deps-${{ hashFiles('~/$GITHUB_WORKSPACE/rebar.lock') }}&lt;/span&gt;
    &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;rebar3-deps-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;キャッシュがなかったら引っ張ってくるようになっています。&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/actions/setup-node"&gt;https://github.com/actions/setup-node&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;E2E テストとして &lt;a href="https://www.cypress.io/"&gt;cypress&lt;/a&gt; を利用しています。 cypress を EUnit から呼び出しています。&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/webfactory/ssh-agent"&gt;https://github.com/webfactory/ssh-agent&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Erlang を利用している場合に課題になるのは rebar3 経由でプライベートリポジトリを持ってくる部分です。色々苦労したくないので素直に ssh-agent を利用することにしました。&lt;/p&gt;

&lt;p&gt;SSH_PRIVATE_KEY を設定することで rebar3 の設定は一切変更する必要はありません。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webfactory/ssh-agent@v0.4.1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ssh-private-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_PRIVATE_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://github.com/rtCamp/action-slack-notify"&gt;https://github.com/rtCamp/action-slack-notify&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Slack 通知はこれが一番無難です。ただ Fixed (失敗の後の成功通知）ができないのが残念なところです。&lt;br&gt;
成功時は通知せず、失敗時だけ通知するという方針なので SLACK_COLOR は danger にしています。&lt;/p&gt;

&lt;p&gt;失敗したらこれが呼ばれます。通知をもっと詳細にしてもいいかもしれません。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Slack Notification&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure()&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rtCamp/action-slack-notify@v2.1.0&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SLACK_CHANNEL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sora&lt;/span&gt;
    &lt;span class="na"&gt;SLACK_COLOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;danger&lt;/span&gt;
    &lt;span class="na"&gt;SLACK_TITLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Failure test&lt;/span&gt;
    &lt;span class="na"&gt;SLACK_WEBHOOK&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Erlang ライブラリ
&lt;/h2&gt;

&lt;p&gt;パブリック、プライベートに関わらずコンテナを利用してビルド、テストしています。&lt;/p&gt;

&lt;h2&gt;
  
  
  費用
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/features/actions"&gt;https://github.com/features/actions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Actions (プライベートリポジトリ利用) は Team を契約しているためデフォルトで 3000 分ついています。&lt;/p&gt;

&lt;p&gt;それを超えたら 1 分あたり $0.008 です。うちのプッシュ単位で 4 分、デイリーで 14 分くらいです。ざっくり 1 分 1 円くらいのようです。&lt;/p&gt;

&lt;h2&gt;
  
  
  CircleCI からの移行理由
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;UI/UX があまりにも使いにくい&lt;/li&gt;
&lt;li&gt;OSS 関連を全て GitHub Actions に移行した&lt;/li&gt;
&lt;li&gt;actions が便利になってきた&lt;/li&gt;
&lt;li&gt;CircleCI にあまり未来を感じない&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>erlang</category>
      <category>github</category>
    </item>
    <item>
      <title>WebRTC iOS/Android ドキュメント</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Wed, 07 Oct 2020 03:38:14 +0000</pubDate>
      <link>https://forem.com/voluntas/webrtc-ios-android-4oca</link>
      <guid>https://forem.com/voluntas/webrtc-ios-android-4oca</guid>
      <description>&lt;p&gt;公式ページからは消えてソースコードの中の docs/native-code/ 以下にある。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webrtc.googlesource.com/src/+/refs/heads/master/docs/native-code/ios/index.md"&gt;WebRTC iOS development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webrtc.googlesource.com/src/+/refs/heads/master/docs/native-code/android/index.md"&gt;WebRTC Android development&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ちなみに WebRTC native code のドキュメントトップページはここ。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://webrtc.googlesource.com/src/+/refs/heads/master/docs/native-code/index.md"&gt;WebRTC native code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>cowboy_static で application/wasm を返す</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 30 Jul 2020 03:38:32 +0000</pubDate>
      <link>https://forem.com/voluntas/cowboystatic-application-wasm-9li</link>
      <guid>https://forem.com/voluntas/cowboystatic-application-wasm-9li</guid>
      <description>&lt;p&gt;この記事は &lt;a href="https://github.com/ninenines/cowboy"&gt;Cowboy&lt;/a&gt; を利用していて、 static で wasm ファイルを返したいが cowlib に用意されている mimetype にはデフォルトでは入っていないので、自前でやりたいというマニアックな内容です。&lt;/p&gt;

&lt;p&gt;これは検証や開発向けで、そもそも本番では CDN や Nginx で返すべきです。&lt;/p&gt;

&lt;h3&gt;
  
  
  cowboy_static
&lt;/h3&gt;

&lt;p&gt;cowboy_static には priv_file があるので、それを使います。&lt;br&gt;
複数の wasm というのはここでは取り扱っていません。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test アプリケーションの priv/ に wasm.wasm が置いてある&lt;/li&gt;
&lt;li&gt;URL は /test/wasm.wasm でアクセス
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"/test/wasm.wasm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cowboy_static&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;priv_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"wasm.wasm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;mimetypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;"application"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;"wasm"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}}]}},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  参考
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ninenines.eu/docs/en/cowboy/2.8/manual/cowboy_static/"&gt;https://ninenines.eu/docs/en/cowboy/2.8/manual/cowboy_static/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webassembly.org/docs/web/"&gt;https://webassembly.org/docs/web/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>erlang</category>
      <category>cowboy</category>
      <category>webassembly</category>
    </item>
    <item>
      <title>DTLS の誤解</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 23 Jul 2020 13:08:56 +0000</pubDate>
      <link>https://forem.com/voluntas/dtls-159</link>
      <guid>https://forem.com/voluntas/dtls-159</guid>
      <description>&lt;p&gt;DTLS は順序保証や再送などもうまいことやってくれると誤解されがちです。&lt;/p&gt;

&lt;p&gt;DTLS が順序保証や再送をやってくれるのは DTLS の Handshake の最中のみで、Application Data 部分は上に乗っかるプロトコルが全部頑張る必要があります。&lt;/p&gt;

&lt;p&gt;たとえば WebRTC の DataChannel であれば SCTP が再送やら順序保証をがんばります。&lt;/p&gt;

&lt;p&gt;まとめ: DTLS は順序保証や再送は一切やってくれませんので、その上に乗っかるプロトコルが全部面倒見る必要があります。&lt;/p&gt;

</description>
      <category>dtls</category>
      <category>udp</category>
    </item>
    <item>
      <title>GitHub Actions 利用時に misc/wasm にパスを通す</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 09 Jul 2020 03:07:57 +0000</pubDate>
      <link>https://forem.com/voluntas/github-actions-misc-wasm-30ef</link>
      <guid>https://forem.com/voluntas/github-actions-misc-wasm-30ef</guid>
      <description>&lt;p&gt;Go で "syscall/js" を利用してるとテストを実行したときに &lt;code&gt;$GOROOT/misc/wasm&lt;/code&gt; 以下にパスが通ってる必要があります。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go env GOROOT&lt;/code&gt; を活用すれば簡単です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-go@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;go-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.14&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;export PATH=$(go env GOROOT)/misc/wasm:$PATH&lt;/span&gt;
          &lt;span class="s"&gt;make test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;一応 makefile も載せておきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;js &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wasm go build &lt;span class="nt"&gt;-o&lt;/span&gt; wasm.wasm


&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;js &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wasm go &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
      <category>webassembly</category>
      <category>github</category>
    </item>
    <item>
      <title>VSCode で Go の syscall/js を利用する場合</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Mon, 06 Jul 2020 04:42:15 +0000</pubDate>
      <link>https://forem.com/voluntas/vscode-go-syscall-js-23mm</link>
      <guid>https://forem.com/voluntas/vscode-go-syscall-js-23mm</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"settings": {
    "go.toolsEnvVars": {
        "GOARCH":"wasm",
        "GOOS":"js",
    },
    "go.testEnvVars": {
        "GOARCH":"wasm",
        "GOOS":"js",
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GOARCHに wasm 、GOOS に js を設定しないといつまでも認識してくれずエラーになる。&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>webassembly</category>
    </item>
    <item>
      <title>Chrome 利用時に WebRTC の暗号を外したい場合</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 04 Jun 2020 15:18:28 +0000</pubDate>
      <link>https://forem.com/voluntas/chrome-webrtc-41gn</link>
      <guid>https://forem.com/voluntas/chrome-webrtc-41gn</guid>
      <description>&lt;p&gt;Chrome には様々なオプションがあり、その一つとして &lt;code&gt;-disable-webrtc-encryption&lt;/code&gt; が提供されています。&lt;/p&gt;

&lt;p&gt;これは DTLS-SRTP の SRTP/SRTCP の暗号を外した状態にしてくれるオプションです。&lt;/p&gt;

&lt;p&gt;Chrome のオプションは以下からどうぞ。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://peter.sh/experiments/chromium-command-line-switches/"&gt;List of Chromium Command Line Switches « Peter Beverloo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>dtls</category>
      <category>srtp</category>
      <category>chrome</category>
    </item>
    <item>
      <title>TURN の DTLS 機能について</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 04 Jun 2020 15:15:23 +0000</pubDate>
      <link>https://forem.com/voluntas/turn-dtls-2266</link>
      <guid>https://forem.com/voluntas/turn-dtls-2266</guid>
      <description>&lt;p&gt;TURN と WebRTC 端末が hop-by-hop で接続する部分に DTLS が利用されます。 TURN-DTLS と呼ばれます。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tools.ietf.org/html/rfc7350"&gt;RFC 7350 - Datagram Transport Layer Security (DTLS) as Transport for Session Traversal Utilities for NAT (STUN)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DataChannel を例に取ると SCTP over DTLS over TURN over DTLS over UDP というミルフィーユになります。&lt;/p&gt;

&lt;p&gt;ちなみに TURN-TLS は SCTP over DTLS over TURN over TLS over TCP となります。&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>turn</category>
      <category>dtls</category>
    </item>
    <item>
      <title>WebRTC 利用時に TURN サーバのみ使いたい場合</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 04 Jun 2020 15:12:20 +0000</pubDate>
      <link>https://forem.com/voluntas/webrtc-turn-4idd</link>
      <guid>https://forem.com/voluntas/webrtc-turn-4idd</guid>
      <description>&lt;p&gt;iceTransportPolicy に 'relay' を指定することで利用可能です。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/RTCConfiguration#RTCIceTransportPolicy_enum"&gt;https://developer.mozilla.org/en-US/docs/Web/API/RTCConfiguration#RTCIceTransportPolicy_enum&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>turn</category>
    </item>
    <item>
      <title>Electron で gRPC を動かす</title>
      <dc:creator>voluntas</dc:creator>
      <pubDate>Thu, 07 May 2020 05:46:23 +0000</pubDate>
      <link>https://forem.com/voluntas/electron-grpc-41dh</link>
      <guid>https://forem.com/voluntas/electron-grpc-41dh</guid>
      <description>&lt;p&gt;Electron で gRPC を動かしたときのメモです。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Electron のバージョンは 8.2.5&lt;/li&gt;
&lt;li&gt;Node.js のバージョンは 13.13&lt;/li&gt;
&lt;li&gt;npm のバージョンは 6.14.4&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;思ってる以上にサクッと動きます。&lt;/p&gt;

&lt;h2&gt;
  
  
  インストール
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add electron electron-rebuild grpc @grpc/proto-loader --dev 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  再ビルドする
&lt;/h2&gt;

&lt;p&gt;gRPC を使うには再ビルドが必要ですが、 electron-rebuild という便利ツールでサクッとできます。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/electron/electron-rebuild"&gt;electron/electron-rebuild: Package to rebuild native Node.js modules against the currently installed Electron version&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./node_modules/.bin/electron-rebuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  以下動かしたときの主なコード
&lt;/h2&gt;

&lt;h3&gt;
  
  
  echo.proto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".;echo"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;EchoRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;EchoReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Echo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EchoReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  main.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BrowserWindow&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;protoLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@grpc/proto-loader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PROTO_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/echo.proto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packageDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;protoLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PROTO_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;keepCase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;longs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;enums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;oneofs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;echoProto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;grpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadPackageDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packageDefinition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;echoProto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;127.0.0.1:50051&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;grpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createInsecure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Echo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello!!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mainWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BrowserWindow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;webPreferences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;nodeIntegration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webContents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openDevTools&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;whenReady&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createWindow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;window-all-closed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;darwin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;activate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BrowserWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAllWindows&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;createWindow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>electron</category>
      <category>grpc</category>
    </item>
  </channel>
</rss>
