コベリンの最近の取り組みとして、業務などで役立ちそうな知見を共有する会を開催することになりました。 そのついでに発表に使ったアジェンダもそのまま公開してしまおうという豪快な企画です。
※ アジェンダをそのままコピペして公開したものなので若干見にくい箇所もあるかもしれませんが、ご了承ください。
マイクラのログをDiscordに通知するスクリプト @takkumattsu
結論
やりたいこと
会社のみんなでやっているマイクラサーバーは id:takkumattsu のラズパイで動かしていてログを見るのは id:takkumattsu しか見れなかったので落ちてたりする時に困っていた
なので Discord にマイクラサーバーのログを垂れ流すようにしたかった
ハマったこと
基本的にはマインクラフトのログから特定の文字列が入っていたらディスコードに流すシェルスクリプトとtailf と grep を組合せて Slackにログを通知する。パイプでワンライナーの記事を参考にしたけどそのままだと動かなかった
シングルクォートのエスケープ
マイクラのログの中に'
が含まれているとcurlに渡す部分でエラーになるのでsed
でエスケープ処理をした
sed -e 's/'\''/\\'\''/g'
sed(やgrep)はデフォルトでバッファリングするのでパイプで流れない
デフォルトだとバッファするのでパイプに流れなかったので-u
オプションをつける
sed -u -e 's/'\''/\\'\''/g'
シングルクォートの中でシェル変数を使いたい
"'"
でくくる
curl -H "Content-Type: application/json" X POST -d '{"username": "'"$BOT_NAME"'", "content": "XXX" }'
最後に
久しぶりにシェルスクリプト触ったけどエスケープ処理とか毎回調べている気がする
Cloud Functionsに呼び出し回数制限を設けたい @numa08 id:numanuma08
背景
最近個人的に作っているChrome拡張のバックエンドにCloud Functionsを採用しているが、リリース後もしもバズったら(多分無い)Functionsの呼び出し回数がエライことになってクラウド破産するかもしれないので、事前に対策をした。
やりたいこと
- Cloud Functionsのhttps呼び出しエンドポイントは認証不要で不特定多数のユーザーからアクセスできるようにしたい
- Chrome拡張を使うに当たり、インストールをしたらそのまま使えるようにしたいので
- 1分あたりのリクエストに上限を設定したい
- バズったとき(たぶんない)や悪意を持ったユーザーが異常なリクエストを出したときにクラウド破産しないため
どうやるか
API Gatewayを使う
GCPが提供するフルマネージドなAPIゲートウェイサービス。API GatewayからAPIキーを発行するとAPIキーに対してアクセス制限の設定を実施できる。Cloud FunctionsのゲートウェイとしてAPI Gatewayをデプロイし、クライアント(Chrome拡張)向けAPIキーを発行、呼び出し回数制限を行えば良い。
余談
- API Gateway VS Cloud Endpoint
GCPが提供する似たようなフルマネージドサービスにCloud Endpointsがある。Cloud EndpointsもAPI Gatewayと同様、APIキー発行やアクセス制限などできるが、実行はCloud Runが必須となる。API GatewayはCloud Runの実行が不要なので、どちらかと言うとAPI Gatewayを選んでおくと良い。
- API Gateway VS Apigee
GCPが提供する似たようなフルマネージドサービスにApigeeがある。こちらもAPI Gatewayと似たような機能を提供するが、その目的がエンタープライズ向けAPIの提供をするためのゲートウェイとなっている。大規模バックエンドをクライアント組織に向けて公開するときの制御・制限に向いているが今回のような小規模なクライアントサーバーシステムの場合は適さない。
API Gatewayの概念
- API
- プロジェクト内で作られるAPI Gateway群の塊
- Open API
- みんな大好きSwagger。OpenAPI記法で記述したyamlファイルを元にAPI Gatewayが構成される
- API Config
- OpenAPIファイルを元に作られる構成の設定。Gatewayとは1対多関係を持っている。Gatewayを更新するときはまずAPI Configを更新する。1つのAPI Configに複数のGatewayを作って、それぞれ制限を別にすることもできる
- Gateway
- クライアントに公開されるURL。API Configから生成する
感想
API Gatewayを作成してgcloud services enable
で認証とかの情報を使えるようにすると、他のGCPフルマネージドサービスと同じようにコンソールに表示されて面白い。
最近の知見
UIGestureRecognizer の velocity が0になる不具合
今まで発生していなかったが、以下の環境でなる。
- Xcode 13.1
- iOS Simulator
実機では発生しない.
以下のようなコードで水平にスワイプしたかを検出していたが、いつの間にかできなくなっていて気がついた。
CGPoint velocity = [(UIPanGestureRecognizer *)gestureRecognizer velocityInView:self.tableView]; BOOL isSwipeHorizontally = ABS(velocity.x) / ABS(velocity.y) > kHorizontalPanThreshold;
translation
を使うようにして解決した.
CGPoint translation = [(UIPanGestureRecognizer *)gestureRecognizer translationInView:self.tableView]; BOOL isSwipeHorizontally = ABS(translation.x) > ABS(translation.y);
なんでやねんってなった.
Swift: enum v.s. OptionSet
enum はよく使うけど OptionSet はあんまり使わないなと思った。でもこの前使ったのでその時の知見. 最初に言っておくけど基本は enum を検討すべきだと思う.
OptionSet
- AND や OR など計算したい
- bit 演算的なことをしたい
- 同時に複数の状態を取りたい
- 空の状態(どのオプションでもない)を取りたい
- でもあんまり出番はない
struct Options: OptionSet { let rawValue: Int static let a = Options(rawValue: 1 << 0) static let b = Options(rawValue: 1 << 1) } // 空の状態や一つ以上の状態を管理できる let options = [] // 空 let options = [.a] // 一つ let options = [.a, .b] // 複数
また OptionSet は SetAlgebra を実装しているので色々演算ができる. option.contains(.a)
など
演算例
ある Optoin を toggle したいといは XOR したいけど、 SetAlgebra
のメソッドでは formSymmetricDifference
で宣言されている(長い)
var options = [.a, .b] // の .a を除去して [.b] にしたい = .a を toggle したい options.formSymmetricDifference(.a) // [.a]
enum
- OptionSet のような機能がいらないのなら
- どれか一つの値にしたいのなら enum
- 基本はこっち
enum Hoge { case a case b } // 変数 hoge は .a or .b という状態に絶対にならない // .a でも .b でもないという状態にもならない let hoge: Hoge = .a
要検討なシチュエーション
OptionSet は enum EnumType
を Set<EnumType>
で管理する状態に近いので enum でも同じことはできる.
ただし値を保存 or API に投げるときには enum + Set なのか OptionSet でいくのか要検討.
OptionSet のほうが心理的に安全?
NSCoding とかで値が保存される場合、 enum だとうっかりミスで値が変わってしまいそう
enum Hoge: Int { case a case b } // 間違ってこういう変更するとすべてが終わる enum Hoge: Int { case zero case a case b } // 以下のようにしておけば安全かも. enum Hoge: Int { case a = 0 case b = 1 }
一方 OptionSet はコードがごちゃごちゃしてるので、比較的いじるのに慎重になると思う.
なので安全かも...?
struct Options: OptionSet { let rawValue: Int static let a = Options(rawValue: 1 << 0) static let b = Options(rawValue: 1 << 1) }