LoginSignup
7

YetAnotherHttpHandlerを利用してUnityでgRPC通信を行う

Last updated at Posted at 2023-09-27

はじめに

CysharpからYetAnotherHttpHandlerがリリースされたので、
これを使ってgRPCでの通信ができるかどうか試してみました!

0. 実行環境

M1 Mac

$ sw_vers
ProductName:		macOS
ProductVersion:		13.5.2
BuildVersion:		22G91

Unityのバージョン
(2021.3以降であれば、YetAnotherHttpHandlerがサポートしているので問題ないと思います)

$ cat ProjectSettings/ProjectVersion.txt
m_EditorVersion: 2022.3.10f1
m_EditorVersionWithRevision: 2022.3.10f1 (ff3792e53c62)

1. CloudRunの設定 (Server設定)

1-1. localでサーバの動作確認

確認用のサーバはGCPのCloud Runで動かします.
公式にhelloworldのサンプルがあるので、これ利用しました.

ただ、Cloud Runで動かすにはhealth checkを通す必要があるので若干の修正が必要です.
上記コードに少しパッチを当てたものをforkして用意しました.

パッチを当てた内容は下記のような感じです.

  • go.modの追加、proto生成後のpackage参照を変更 (ビルド時の依存更新)
  • PORTを環境変数で指定可能にした (Cloud Run対応)
  • サーバ起動時のコードにhealth checkのコードを追記 (Cloud Run対応)
  • リフレクションの導入 (提供するメソッド、型、その他のメタデータを公開)
  • Dockerfileの追加 (ArtifactRegistoryへの登録用)
$ git clone https://github.com/mattak/grpc-go.git -b cloudrun --depth 1
$ cd grpc-go/examples/helloworld

これをcloud runで動く形にビルド.

$ docker build --platform linux/amd64 -t grpc_sample -f Dockerfile .

試しにlocalで動かしてみて、通信に成功すればOKです!

server

$ docker run --rm -p 50051:50051 -it grpc_sample
2023/09/26 11:06:57 server listening at [::]:50051

health check

$ grpcurl -plaintext localhost:50051 grpc.health.v1.Health.Check
{
  "status": "SERVING"
}

request check

$ go mod download
$ go run greeter_client/main.go
2023/09/26 20:08:37 Greeting: Hello world

1-2. Cloud Runにimageアップロードして確認

先程のdocker imageをGCPのArtifact Registoryにpushします.
(事前にGCPのproject作成やartifact registroyへのレポジトリ作成はしておく)

# 定義:
# PROJECT=FIXME
# REPOSITORY=FIXME
# IMAGE=FIXME
# URI=asia-northeast1-docker.pkg.dev/$PROJECT/$REPOSITORY/$IMAGE:latest

docker tag grpc_sample $URI
docker push $URI

CloudRunのページからサービスを作成.

  • 既存のコンテナイメージから1つのリビジョンをデプロイする (先程のURIを指定)
  • リージョン: asia-northeast1
  • 認証: 未認証の呼出を許可
  • コンテナポート: 50051
  • ヘルスチェック
    • 種類: 起動時チェック
    • プローブタイプ: gRPC
    • 初期遅延: 0
  • ネットワーキング
    • HTTP/2 エンドツーエンドを使用する

下記のようにヘルスチェックが通っていれば成功です!

ここで表示されるURLはメモっておきます。

2. Unityでの設定

2-1. プロジェクトの設定

適当にUnityの新規プロジェクトを作成.

YetAnotherHttpHandlerをInstallするが、
デフォルトだとSystem.IO.Pipelineなどがmissingになるので事前に必要となる依存を追加する.

上記ページから下記2つのunitypackageをDLして、プロジェクトにインストールする.

  • Cysharp.Net.Http.YetAnotherHttpHandler.Dependencies.unitypackage
  • Grpc.Net.Client.Dependencies.unitypackage

Packages/manifest.json にYetAnotherHttpHandlerの依存を追加する.

Packages/manifest.json
    "com.cysharp.yetanotherhttphandler": "https://github.com/Cysharp/YetAnotherHttpHandler.git?path=src/YetAnotherHttpHandler",

また、生成後のファイルでGoogle.Protobufが必要となるのでこれのdllも追加しておく.

$ curl -Lo protobuf.zip https://www.nuget.org/api/v2/package/Google.Protobuf/3.24.3
$ unzip protobuf.zip -d protobuf
$ mkdir -p Assets/Plugins/Google.Protobuf
$ cp protobuf/lib/net45/Google.Protobuf.dll Assets/Plugins/Google.Protobuf/

2-2. protoファイルからC#コードを生成する

nugetのGrpc.Toolsから必要なコマンドを抜き出す.

$ curl -Lo grpctools.zip https://www.nuget.org/api/v2/package/Grpc.Tools/2.58.0
$ unzip grpctools.zip -d grpctools

梱包されている下記2つの実行バイナリを利用する.

grpctools/tools/macosx_x64/grpc_csharp_plugin
grpctools/tools/macosx_x64/protoc

実行バイナリに実行権限をつけておく.

$ chmod +x grpctools/tools/macosx_x64/protoc
$ chmod +x grpctools/tools/macosx_x64/grpc_csharp_plugin

serverで利用しているprotoをDL

$ curl -L -O https://raw.githubusercontent.com/mattak/grpc-go/cloudrun/examples/helloworld/helloworld/helloworld.proto

出力先を作っておく

$ mkdir -p Assets/Scripts/Protos

protocを使ってコード生成する

PROTOC=$PWD/grpctools/tools/macosx_x64/protoc
GRPC_PLUGIN=$PWD/grpctools/tools/macosx_x64/grpc_csharp_plugin

$PROTOC -I ./ \
  --csharp_out=./Assets/Scripts/Protos \
  --grpc_out=./Assets/Scripts/Protos \
  --plugin=protoc-gen-grpc=$GRPC_PLUGIN \
  ./helloworld.proto

下記ファイルが生成されていればOK

$ find Assets/Scripts/Protos -type f
Assets/Scripts/Protos/Helloworld.cs
Assets/Scripts/Protos/HelloworldGrpc.cs

2-3. Unity上からリクエストを呼び出してみる

シンプルなスクリプトを記述して、適当にGameObjectにつける.

using Cysharp.Net.Http;
using Cysharp.Threading.Tasks;
using Grpc.Net.Client;
using Helloworld;
using UnityEngine;

namespace GrpcSample
{
    public class SampleRequestRunner : MonoBehaviour
    {
        private const string URL = "https://FIXME.a.run.app"; // FIXME: 先ほどメモったCloudRunのURLを入力する

        private void Start()
        {
            Request();
        }

        private void Request()
        {
            using var handler = new YetAnotherHttpHandler();
            using var channel = GrpcChannel.ForAddress(URL, new GrpcChannelOptions
            {
                HttpHandler = handler,
                DisposeHttpClient = true,
            });
            var client = new Greeter.GreeterClient(channel);

            var reply = client.SayHello(new HelloRequest {Name = "UnityClient"});
            Debug.Log("Greeting: " + reply.Message);
        }
    }
}

ログに下記のようにメッセージが表示されていれば、疎通成功!

表示されない場合は一度cloud runをデプロイし直して、サーバが立ち上がっていることを確認してから再度リクエストするとうまくいく.

感想

一昔前だと、macではC# + gRPC環境構築するのが難しかったりしたが、けっこう楽ちんに構築できた!
YetAnotherHttpHandlerをOSSで公開してくれたCysharpさんに圧倒的感謝!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7