GoLangでAPIサーバを建てる

GoLangでAPIサーバを建てる

まずはHTTP要求マルチプレクサと呼ばれるmuxを入れる。
やれることは本家のHPで書いてあるので参考にする。

ひとまずGOに入れる。

go get github.com/gorilla/mux

単純なHTTPレスポンスサーバは検索すれば山のように出てくるのでそちらを参考にすればいいだろう。

サーバ側でもFirebaseを活用したい。
ユーザのID管理とFCM(サーバPush通知)を使いたいからだ。

UnityのID取得に関してはあるにはあるが、GoogleとAppleの規約変更に振り回された経験があるため
こちらは使用する気にならない。

go get firebase.google.com/go

これらは以下から確認できる。
https://console.firebase.google.com/project/プロジェクト名/settings/serviceaccounts/adminsdk

GoLangでは以下の方法でログインできれば成功だと思われる。(main.go)


package main

import (
  "fmt"
  "golang.org/x/net/context"
  firebase "firebase.google.com/go"
  "google.golang.org/api/option"
)

func main() {
  ctx := context.Background()
  app := initFirebase()
  client, err := app.Firestore(ctx)
  if err != nil {
    fmt.Errorf("error app.Firestore: %v", err)
  }
  // build error 回避
  var _ = client
}
func initFirebase() *firebase.App {
  opt := option.WithCredentialsFile("path/to/xxx.json")
  app, err := firebase.NewApp(context.Background(), nil, opt)
  if err != nil {
    fmt.Errorf("error initializing app: %v", err)
  }
  return app
}

うーんGoLangキモい。出来る限り触れないようにしたいが覚えないとなぁ。

Firebaseの匿名認証では、UserIdが発行される。


UnityEditor(2018.3.6)でも出来るかなぁと淡い期待をして実行したところ、
firebaseAuth.SignInAnonymouslyAsync().ContinueWith から帰ってこないのでひとまず諦める。

とりあえずソースは以下のもので、ボタン押下時にAnonimusLoginが実行されるようにしている。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirebaseAnonimusLogin : MonoBehaviour
{
  public void AnonimusLogin()
  {
    Login();
  }
  private void Login()
  {
    Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
    auth.SignInAnonymouslyAsync().ContinueWith(task => {
      if (task.IsCanceled)
      {
        Debug.LogError("SignInAnonymouslyAsync was canceled.");
        return;
      }
      if (task.IsFaulted)
      {
        Debug.LogError("SignInAnonymouslyAsync encountered an error: " + task.Exception);
        return;
      }
      Firebase.Auth.FirebaseUser newUser = task.Result;
      Debug.LogFormat("User signed in successfully: {0} ({1})",
        newUser.DisplayName, newUser.UserId);
    });
  }
}

ひとまずAndroidアプリで実行確認。

02-25 18:36:54.306 5466 5523 I Unity : Firebase App initializing app jp.hoge.fuga (default 1).
02-25 18:36:54.306 5466 5523 I Unity :
02-25 18:36:54.306 5466 5523 I Unity : (Filename: ./Runtime/Export/Debug.bindings.h Line: 45)
02-25 18:36:54.306 5466 5523 I Unity :
02-25 18:36:56.008 5466 5775 I Unity : User signed in successfully: (a-zA-z0-9 28文字)
02-25 18:36:56.008 5466 5775 I Unity : System.Threading.Tasks.Task:Execute()
02-25 18:36:56.008 5466 5775 I Unity : System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)
02-25 18:36:56.008 5466 5775 I Unity : System.Threading.Tasks.Task:ExecuteWithThreadLocal(Task&)
02-25 18:36:56.008 5466 5775 I Unity : System.Threading.Tasks.Task:ExecuteEntry(Boolean)
02-25 18:36:56.008 5466 5775 I Unity : System.Threading.ThreadPoolWorkQueue:Dispatch()
02-25 18:36:56.008 5466 5775 I Unity :
02-25 18:36:56.008 5466 5775 I Unity : (Filename: ./Runtime/Export/Debug.bindings.h Line: 45)
02-25 18:36:56.008 5466 5775 I Unity :

よしよし、出来ている。
これは匿名認証するたびにユニークな値が発行されると思っておいたほうがいいのかな。
以下の文言が書いてあるから。

プロジェクトを不正行為から守るため、Firebase では同じ IP アドレスでアプリケーションが短時間に使用できる新しいメールとパスワード、匿名での申し込みの数を制限しています。

一度アプリ終了させたあともう一度やっても同じIDが発行された。

プロジェクトを不正行為から守るため、同じ IP アドレスでアプリケーションが使用できる新しいメールとパスワード、匿名での申し込みの数を制限しています。ここで、この割り当てを一時的に変更するようリクエストしたり、スケジュール設定したりできます。

と書いてあるので、1時間以内だったら同じIDが出るのかなぁ。
というわけで1時間後にもう一度実行してみよう。別のIDが出れば予想通りだ。

2時間後にアプリ再起動して実行すると同じIDだった。
これは内部で保存されているのだろうか。

ちなみにPCのFirebaseのAnonymousLoginでAuthenticationユーザを確認すると毎回新規ユーザが作成されていた。挙動的にはPC版のほうが予想通りだが…

試しにローカルの保存データを全削除後に再度AnonymousLoginをすると別のIDで登録された。
Android(たぶんiOSも?)は内部的に保存しているようだ。というわけでadbで中身を見ようとするとパーミッションエラー。Androidも少しずつセキュアになってきたなぁ。android:debuggableをtrueにすれば確認できるかもしれないが色々プラグイン入れたことでAndroidManifestが乱立しているので諦める。

永続化したい、という情報はあるが永続化されているかどうかは怪しい。やはり別のUserIDが来ることを想定したほうがいいだろう。

Android版のようにmAuth.getCurrentUserで存在チェックとかあると楽だけどやはりsignInAnonymouslyもしくはsignoutのタイミングで変わることがあるようだ。

なのでこういう設計にする。

新規作成

ローカルのデータにユーザデータが
存在しない場合かつそのままゲームログイン。
これは完全新規ユーザとして認識する。
signInAnonymouslyでログイン後、
与えられたユニークなIDを元に
自分のサーバに対してregist処理をする。
サーバではクライアントに必要な情報の作成、
サーバID、セッションID(24時間まで。NoSQLで保存しといて
放置してからログインする場合はセッションエラーでタイトルに戻す)を発行、それを返す。
クライアント側はその情報を取得したらサーバIDの保存、
クライアントに必要な情報とセッションIDの取得を行う。

ログイン

セーブデータが存在するためサーバIDとユニークなIDの取得が可能。
与えられたユニークなIDを元にlogin処理を実行し、
クライアントに必要な情報とセッションIDの取得を行う。

上記以外のAPI

サーバIDとセッションIDを元に処理を実行する。
セッションIDは1APIごとに変わるため、
同じAPIを同時呼び出しされた際は先のほうが
優先されあとのほうはセッションエラーとなる。
セッションエラー時はタイトルに戻され、ログインからやり直し。

例外のAPI

バナー情報を取得、や表示するHTML表示など
ユーザ関わらず返すAPIも有りうる。
その場合は引き渡すパラメータなど必要なく、
そのまま値を返すものもある。

引き継ぎのAPI

ユニークなIDもしくはサーバIDを
ベースに引き継ぎIDは表示され、
ユーザ入力の引き継ぎパスワードを発行する。
乗っ取り被害が出ないように表示箇所は公開しないよう明示する。

とりあえずこんな感じで組んでみるか。

あとは今日はFirebaseでのCloudMessage送信を実装してチェックするまでで終了。
Android版は簡単に出来た。GCMからFCMへ移行しただけのことはある。
この辺りもデファクトスタンダードが出来たらワンボタンでちょちょいのちょいとなっていくんだろうけどなぁ。はやくSiriにお金稼いで、と言ったら指定額稼いでくれる時代にならないものか。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください