ぶろぐ

日記です

Go reflectを使ってstructの値全てに処理を行う

例えばstructのfieldに `null` という文字が含まれていたら空文字に変換する処理

package main

import (
	"fmt"
	"reflect"
)

func main() {
	h := Hoge{
		Foo:     "null",
		Bar:     "aaa",
		Integer: 2,
	}
	fmt.Println("before:", h)
	ReplaceNullStringToEmpty(&h)
	fmt.Println("after :", h)
}

type Hoge struct {
	Foo     string
	Bar     string
	Integer int64
}

func ReplaceNullStringToEmpty(s interface{}) {
	val := reflect.ValueOf(s).Elem()

	for i := 0; i < val.NumField(); i++ {
		if val.Field(i).Kind() == reflect.String {
			if val.Field(i).String() == "null" {
				val.Field(i).SetString("")
			}
		}
	}
}
go run main.go
before: {null aaa 2}
after : { aaa 2}

curlでcognito oauth2認証

久しぶり、かつpythonで実装して超めんどくさかったのでメモ。
はまらなければすぐできると思う。

Authorization Code Grantの流れ
  • cognito hosted uiでログイン
  • サーバーのアプリでredirectを受け付ける
  • 認可コードをtoken endpoint(xxxx.amazoncognito.com/oauth2/token)に送る
  • id_token, refresh_token, access_tokenを取得
  • 有効期限が切れたら refresh_token を使用して token をrefresh

docs.aws.amazon.com

この辺を見れば分かる

token取得
curl -X "POST" "https://{domain}.auth.us-east-1.amazoncognito.com/oauth2/token" \
     -H 'Content-Type: application/x-www-form-urlencoded' \
     --data-urlencode "grant_type=authorization_code" \
     --data-urlencode "client_id=xxxxx" \
     --data-urlencode "client_secret=xxx" \
     --data-urlencode "code=xxxx" \
     --data-urlencode "redirect_uri=https://{redirect_url}"
token refresh
curl -X "POST" "https://{domain}.auth.us-east-1.amazoncognito.com/oauth2/token" \
     -H 'Content-Type: application/x-www-form-urlencoded' \
     --data-urlencode "grant_type=refresh_token" \
     --data-urlencode "client_id=xxxx" \
     --data-urlencode "client_secret=xxxx" \
     --data-urlencode "refresh_token=xxxx"

optionalでnonceも送る。

Amazon SNS Mobile PushでPUSH通知

予めAWSでやっておくこと

  • アプリケーションプラットホームを作成しておく。APNsやFCMの情報を登録する。
    • ここに端末のdevice tokenを登録することでendpointを取得できる。
    • サーバーではこのendpoint arnをDBに保存しておく。
      • ユーザー(端末)を指定して個別にpush通知を送りたいときに使う
  • 全体PUSH通知用にTOPICを作成
    • endpoint arnを作成したらこのTOPICをsubscribeしておく
    • TOPICにmessageをpublishしたらsubscriberに伝播して全端末にpush通知が飛ぶ
    • 端末個別にpush通知が飛ばせればいいのであれば作らなくてもいい。

コードサンプル

コピペで動くはず

<?php
$client = new SnsClient([
    'profile' => 'dev_sns',
    'region'  => 'ap-northeast-1',
    'version' => 'latest',
]);

// アプリケーションプラットホームのエンドポイントを作成
// このendpointにpublishすることで端末指定でpush通知が可能
$result = $client->createPlatformEndpoint([
    'Token'                  => $token,
    'CustomUserData'         => $studentId,
    'PlatformApplicationArn' => 'arn:aws:sns:ap-northeast-1:xxxxxxxxxxxxxx:app-push-notification-dev'
]);
$endpoint = $result['EndpointArn'];

// 全体通知用のトピックをsubscribeする
$client->subscribe([
    'Protocol'   => 'application',
    'Endpoint'   => $endpoint,
    'TopicArn'   => 'arn:aws:sns:ap-northeast-1:xxxxxxxxxxxxxx:app/GCM/app-android-dev',
    'Attributes' => [], // android/ios指定でフィルタできるように設定してもいいかも
]);

// endpointを指定して個別にpush通知
$client->publish([
    'Subject'   => 'title',
    'Message'   => 'message',
    'TargetArn' => $endpoint,
]);

// topicを指定して全体にpush通知
$client->publish([
    'Subject'   => 'title',
    'Message'   => 'message',
    'TargetArn' => 'arn:aws:sns:ap-northeast-1:xxxxxxxxxxxxxx:app/GCM/app-android-dev',
]);

CannotStartContainerError: Error response from daemon: failed to initialize logging driver: failed to create Cloudwatch log stream: ResourceNotFoundException: The specified log group does not exist. status code: 400, request id: xxx

  • タスクロール ecsTaskExecutionRole はCloudwatchLogsのグループを作成する権限がないっぽい
    • こういうのが出る CannotStartContainerError: Error response from daemon: failed to initialize logging driver: failed to create Cloudwatch log stream: ResourceNotFoundException: The specified log group does not exist. status code: 400, request id:
    • 初回だけ手動で作ればOK
  • 起動タイプをEC2にした場合、自分でEC2を起動してクラスタにjoinさせる手順が必要

いろいろ知らなくてハマったのでメモ