- 投稿日:2020-07-30T22:37:10+09:00
Goでドメインの名前解決を強制的に行う(curl –resolveに相当することを行う)方法
やりたいこと
Goでドメインの名前解決を強制的に行う。
ドメインの名前解決を外部DNSを通して行うのではなくて自分でIPアドレスを指定して解決したい場合は、通常はローカルマシンのhostsファイルに以下のように記述すればよい。
203.0.113.0 google.com # google.comを 203.0.113.0 に解決させる例hostsファイルを使用する以外だと、
curl
コマンドに--resolve
オプションというのがあり、以下のように指定することでコマンド実行時に直接名前解決を行わせることが可能だ。curl https://google.com --resolve "google.com:443:203.0.113.0"今回はこのcurlの場合と同様に、hostsファイルを使わずにリクエスト実行時に強制的にドメインにIPアドレスを与えるということをGoでやりたかった。
そもそも可能なのか、可能だとしたらどういう方法でできるのか分からず色々と検索していたら、まさに同じことをやろうとしてた人のstack overflowの質問ページを見つけて無事解決した。
方法
上記のリンク先に投稿されている回答の通りなのだが、http接続時に使用する
http.Transport.DialContext
をカスタマイズすることで実現できた。func main() { dialer := &net.Dialer{ Timeout: 30 * time.Second, // このへんのタイムアウト設定はこれがデフォルト値 KeepAlive: 30 * time.Second, DualStack: true, } http.DefaultTransport.(*http.Transport).DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { if addr == "google.com:443" { // 接続先が google.com:443 の場合に、203.0.113.0:443 に解決する。ドメインだけでなく、「:443」とport番号の指定が必要な事に注意。 addr = "203.0.113.0:443" } return dialer.DialContext(ctx, network, addr) } resp, err := http.Get("https://google.com") log.Println(resp.Header, err) }
- 投稿日:2020-07-30T18:19:33+09:00
React Nativeで作ったアプリをリリースしてから1年経ったので振り返ってみる
React Native製、予定作成アプリ「ペペロミア」を公開しました
以前記事にしたペペロミアが公開してから1年経ったので振り返りも兼ねて記事にまとめてみました。
個人プロダクトのアーキテクトとかの参考になれば良いかなと思います。主に使用している技術
- アプリ
- Backend
- Web版
- ヘルプサイト
- LPページ
- その他の使用技術 /ツール
GitHub
前はモノレポで1つのRepositoryで全Sサービス管理していたが、各サービスごとにわけるようにしたので以下の通りです。
リリースノート
今までの主な更新リリース内容は、こちらで確認できます。
https://peperomia.app/information
ペペロミアとは
プロジェクトの概要は、こちらを参照
アプリ
https://github.com/wheatandcat/Peperomia
■ Apple Store
https://itunes.apple.com/us/app/%E3%83%9A%E3%83%9A%E3%83%AD%E3%83%9F%E3%82%A2/id1460583871?l=ja#?platform=iphone■ Google Play
https://play.google.com/store/apps/details?id=com.wheatandcat.peperomia概要
スケジュール管理アプリ。
アカウント登録すると、Push通知、Web版、シェア機能など利用できるようになります。使用技術 / ツール
デザイン設計
Figamaを使用しています。
https://www.figma.com/Figmaについては以下で公開しています。
ペペロミア FigmaFigmaに関しては前に記事にしているので以下を参照
エンジニアでも出来る!Figmaを使って自作アプリをリニューアルアプリ作成
アプリはExpoを使用しています。
https://expo.io/データベース
アカウント認証前は、SQLiteを使用、
アカウント認証後はWeb版でもデータ同期ができるようにFirestoreを使用する実装になっています。認証
認証はFirebase Authenticationを使用しています。
GoogleログインとSign in with Appleで登録できるようになっています。主なリリース内容
Expo SDKのバージョンアップ
リリース当初がExpo SDK v32でしたが、現在はExpo SDK v38で実装しています。
各SDKのバージョンアップのPull Requestがこちら
- Expo SDK v33にバージョンアップ
- Expo SDK v34にバージョンアップ
- Expo SDK v35 バージョンアップ
- Expo SDK v36 バージョンアップ
- Expo SDK v37 バージョンアップ
- Expo SDK v38 バージョンアップ
主なバージョンアップ変更は以下の通り
- React Native v0.61以降になりFast refreshが導入されたので開発時に高速でリフレッシュできる
- 元々expo内部に入っていたモジュールが別モジュールに分割
- webサポートされた(けど、他ライブラリの影響でペペロミアでは、ビルドでコケるので使えていない )
ダークモードの実装
以下で解説しているのが細かい実装は省略しますが、
React Native製の公開しているアプリにダークモードを実装してみた現状は、端末の設定を見て通常モード、ダークモードの切り替えを行う実装になっています。
ホーム画面の比較をすると、こんな感じです。
カレンダー機能の実装
- スケジュールに日付入力をできるようにしてカレンダーUIで表示するように変更
- 実装はreact-native-calendarsを使用
Sign in with Appleの実装
- Sign in with Appleを実装
- Apple storeの規約でサードパーティのログインを形式の場合はSign in with Appleの実装は必須になったのでFirebase Authenticationに追加
- ExpoでのSign in with Appleは以下の通りに実
Expo Push通知の実装
- Push通知を開いた時に指定の画面を開く機能を実装
- ExpoでのPush通知は以下の通りに実装
Backend
https://github.com/wheatandcat/PeperomiaBackend
概要
言語はGo言語で実装
主にアカウント認証後のデータのやり取りのAPIを実装しています。使用技術 / ツール
フレームワーク
Ginを利用して実装
https://github.com/gin-gonic/ginGraphQLはgqlgenで実装
https://github.com/99designs/gqlgenデプロイ先
GCPのGAEにデプロイしています。
API設計書
RESTful APIのドキュメントはSwaggerHubで実装しています。
以下で、ドキュメントを公開しています。
https://app.swaggerhub.com/apis-docs/wheatandcat/peperomia/1.0.0主なリリース内容
gomockでのHTTP Requestのテストの実装
Goでテストを書く際にFirestoreにアクセスさせたくなかったのでgomockでメソッドをモック化してテストコードを作成しました。
https://github.com/golang/mock実装の詳しい内容は以下の記事参照
GoMockを使ってHTTP Requestのテストを書いてみるExpoでPush通知を実装
ExpoのPush通知のSDKがあるので、こちらを使用して実装
https://github.com/oliveroneill/exponent-server-sdk-golangカレンダーに合わせてPush通知を送るようにしており、GAEのcron.yamlのジョブのスケジューリングで定期実行しています。
実装の詳しい内容は以下の記事参照
ExpoでPush通知を実装してみたgqlgenの実装
gqlgenを実装
gqlgenのベースになっているGraphQL Schemaファイルをgraphql-codegenに渡すことでTypeScriptのtypeファイルを自動生成するようにしています。
実装の詳しい内容は以下の記事参照
gqlgenとgraphql-codegenでGraphQLのtypeを自動生成してフロントエンドのコード作成するWeb版
https://github.com/wheatandcat/PeperomiaWeb
■ URL
https://app.peperomia.info/login
※アプリでアカウント作成していないと利用できません概要
Nuxt.js で実装しています。
使用技術 / ツール
UIライブラリ
Vuetifyで実装
https://vuetifyjs.com/jaデプロイ先
こちらもGCPのGAEにデプロイしています。
主なリリース内容
Firebase Authenticationでサードパーティクッキーの対応
Safariでサードパーティクッキーをデフォルトでブロックされるようになったので、Firebase Authenticationを素で組み込むとエラーになるようになっていたので、そちらの対応
実装の詳しい内容は以下の記事参照
Firebase Authenticationの「This browser is not supported or 3rd party cookies and data may be disabled. 」の解決方法Composition API + TypeScriptの導入
Vue 3.0で導入されるComposition APIを導入
合わせてComposition APIと相性の良いTypeScriptも導入しました。導入前に以下の3パターンの実装方式を検証
- パターン①. Composition API + TSXファイル + CSS Modules
- パターン②. Composition API + Vueファイル + <script lang="tsx">
- パターン③. Composition API + Vueファイル + <script lang="ts">
検証の結果、1番シンプルなパターン③で実装しました。
実装 + 検証の詳しい内容は以下の記事参照
NuxtでComposition API とTSとTSX + CSS Modulesの組み合わせについて考えてみる@nuxt/http導入 + スケジュール修正機能の実装
ペペロミアのWeb版でのAPIアクセスは@nuxt/httpで実装
https://github.com/nuxt/httpWeb側でスケジュール内容の編集の際は@nuxt/httpでAPIにアクセスしてデータ変更を行っている
ヘルプサイト
https://github.com/wheatandcat/PeperomiaHelp
■ URL
https://amazing-hawking-a280c3.netlify.app/概要
GatsbyJSで実装
GatsbyJSはMDXをサポートしているのヘルプ記事の中身はMDXで記載しています。使用技術 / ツール
デプロイ先
Netlifyにデプロイしています。
GatsbyJSでのNetlifyデプロイ方法は以下を参照
https://www.gatsbyjs.org/docs/deploying-to-netlify/主なリリース内容
GatsbyJS + MDXでヘルプサイトを作成
なるべく手をかからず、zendeskやIntercomみたいにお金のかからない方式でヘルプサイトを作りたかったので作成。
実装の詳しい内容は以下の記事参照
Gatsby.js + mdxでヘルプサイトを作ってみるちなみに今だとGatsby CloudでMDXも使えるみたいなので、こちらの選択式もありかなと思います
https://www.gatsbyjs.com/LPページ
https://github.com/wheatandcat/PeperomiaLandingPage
■ URL
https://peperomia.app/概要
Reactで実装しています
使用技術 / ツール
デプロイ先
Netlifyにデプロイしています。
主なリリース内容
LPサイトにアニメーションを追加
react-inview-monitorを使ってスクロールに入ったタイミングアニメーションするように修正
実装の詳しい内容は以下の記事参照
Reactで作成したLPサイトにアニメーションを追加してみたRSS経由からリリースノートを表示
リリースノートを自動生成するスクリプトを作成してブログに投稿
タグを付けてRSS経由で取得して、LPページに表示させています。リリースノートの自動生成については以下の記事参照
リリースノートを自動生成するスクリプトを書いてみた今年〜来年への開発予定
Firestoreの設計見直し
実装時はFirestoreへの理解が浅かったのもあり、RDBっぽい設計になっているので、見直し & 新設計にマイグレーション予定
CollectionGroupを使えば、ある程度柔軟に設計できるかな模索中。whereのinに取得制限があったりもするのでFirestoreは設計は、すごく重要だなと実感
https://firebase.google.com/docs/firestore/query-data/queries#limitationsAPIのrequestの型を自動生成してフロントエンドで使用
現状GraphQLに関してはgqlgenとgraphql-codegenの組み合わせで型を自動生成している。
だが、RESTful APIの方は特にやっていないので、こちらを型安全の状態にしたい。以下のどちらかのパターンで実装しようかなと検討中
案1. swagger-to-tsを使って型を自動生成
swagger-to-tsでswaggerからtypeファイルを生成できるので、こちらを使用する
https://github.com/manifoldco/swagger-to-tsただ、これだとswaggerの方がミスっていた時に検知できないので、さらにswaggerのテストツールのdreddを実装する
https://github.com/apiaryio/dredd案2. 現状のRESTful APIをGraphQLのmutationに移行する
mutationに移行するれば、gqlgenとgraphql-codegenの組み合わせで型を自動生成できるので、こちらを使用する
こちらの方がシンプルになりそうだけど、移行するのに時間がかかりそうな予感。最後に
リリースノートを自動生成するようにしたのを、きっかけに振り返りの記事を書いて見ました。
振り返ると1年間で結構開発していたんだなーと思いました。また、なにかの区切りに振り返りの記事を書こうと思います
- 投稿日:2020-07-30T16:52:48+09:00
Featherweight GoをScalaで実装した
はじめに
arXivにFeatherweight Goの論文が投稿されていた。この論文ではGo言語から機能を大きく取り去ったモデル言語を作り、それ振る舞いを定義したり型システムを与えている。さらにはFeatherweight Go(FG)にジェネリクスを搭載したFeatherweight Go with Generics (FGG)というものを定義し、FGGからFGへの変換を与えることでGo言語へのジェネリクス追加が安全であろうことを述べていると思われる。このように、FGは実際のところは型システムなどの議論のために生まれたものであり、処理系などを実装することは恐らく意図されてはいないが、小さくて実装が容易だったのでScalaで実装した。この記事ではまずFeatherweight Goでできることやプログラム例を示し、その後にScala実装について軽く解説する。
また今回の実装は下記のGitHubリポジトリにある。この記事について、疑問点や誤りなどがあれば気軽にコメントなどで教えてほしい。
発表スライド
この内容を一部社内で発表したが、そのときの資料が下記にある。
Featherweight Goの機能
Featherweight Goは次のようプログラム言語となっている。
int
などのプリミティブ型はない- 構造体(
struct
)とインターフェース(interface
)の定義- 構造体のフィールドアクセス
- メソッドの定義
- メソッド呼び出し
このように極めて限定された機能しか有しないが、それでも実はそこそこのプログラムを書くことができる。例として下記のプログラムがある1。
package main; type Nat interface { plus(a Nat) Nat } type Zero struct { } type Succ struct { pred Nat } func (this Zero) plus(a Nat) Nat { return a } func (this Succ) plus(a Nat) Nat { return Succ{this.pred.plus(a)} } func main() { _ = Succ{Succ{Zero{}}}.plus(Succ{Succ{Zero{}}}) }このように、自然数をつくったうえで足し算
plus
を作り、それで$2 + 2$を計算している。これの結果はSucc{Succ{Succ{Succ{Zero{}}}}}
となり、正しく$4$を計算できる。あとはたとえば文字が作りたい場合はこの自然数と文字コードを対応させることができるし、リストを作れば文字列も生み出さる。このようにFeatherweight Goは実用が困難なほど何も搭載していないが、こういうところをいちいち作っていけば同じ表現力になる。
Featherweight Goの実装
ここからは実装について述べていくが、だいたいのところはコードを読んでも分かると思うので、実装上のポイントなどを中心に解説しようと思う。
パーザー
- パーザーは今回の実装で最も苦労した。パージングについてもっと色々な知識があればこうはならなかったのかもしれないが、具象構文から意図したASTが得られるようになるまで色々頭を悩ませた
- 特に型システムを実装したあとで、そのテストのために入力した具象構文がパーズできないなどもあり、相当に時間がかかった
- もしプログラム言語を作りたいけどパーザーに興味がないなら、具象構文をJSONなどにしてしまう(?)という方法もありかもしれない
- ただ、最初からテストを与えながら作ったことはデグレ防止に非常に役だった。複雑な例で壊れるケースを修正したら、その修正で別の部分が壊れているということにすぐ気がつけた
- 特に今回はインタープリターを作ったため、引数から先に評価させるため、そこを優先でパーズするというのも注意しなければならなかった
型チェッカー
- 基本的には論文の型検査ルールをひたすらプログラムしていくだけであり、かなり簡単に実装できた
- また型チェッカーを作ることで生成されるべき型から実はFeatherweight Goの具象構文を勘違いしていたといったところが出てくるなどした
エバリュエーター
- こちらもひたすら論文どおりに実装するだけであった
Scala.jsでWebアプリ化
また、Slackで @xuwei_k さんなどに教えてもらってWebアプリにした。
上記のURLから試してみることができる。
まとめ
実装の解説はあまりしなかったが、Featherweight Goは小さく言語実装にそこまでの手間がかからないのですごく経験が豊富でなくても取り組みやすいと思う。まだやっていないが、いずれはFGGの実装とFGへの変換も着手したい。これらの実装を通して、Go言語にジェネリクスを搭載すると速度が変化するのか?という論争に終止符を打ってほしい。
https://y-yu.github.io/featherweight_go/ にWeb(Scala.js)の実装があるので、そこで試すことができる。 ↩
- 投稿日:2020-07-30T12:33:28+09:00
HTTPでrobocopyやrsyncみたいなの!オレトラストネットワークでちゃっちゃとファイル共有Ⅱ
前回
の続きです。前回の載せたら、
「Syncthingに似てる気がするけど知ってる?参考になるかもよー見てみたら??」
というありがたいレスが。
知らないので調べてみますわーってレス書いた後で過去にQiitaのSyncthin記事にがっつりLGTM入れてた!Syncthingつよい
僕のツールのがニッチで良い部分もありつつ見習いたい点が多々出てくる出てくる
- 同期状況とか完了したかどうかサーバー、クライアント両方で見れる
- 接続中のサーバーを見れる
- 全通信をプロトコルで暗号化したり効率化してる
- 同期対象のディレクトリ対応
- 中継SaaS持ってるのでinbound通信を開放しなくていい
- GUI持ってるので操作が分かりやすい
- バックグラウンドで同期してくれる
- 設定が保存できるので前回と同じ同期がやりやすい
洗い出しできたところで、ワイツールも既存のHTTP Proxy挟めるなど利点があるので
- 同期状況とか完了したかどうかサーバー、クライアント両方で見れる
- 接続中のサーバーを見れる
- 同期対象のディレクトリ対応
- 設定が保存できるので前回と同じ同期がやりやすい
これを盛り込んで改良することにした!機能以外にUXも必要だよね、とか勉強になるね!
Go言語つえー
絞り込んで改良する事にしたーで、4日で実装できた!やっぱGo言語サイコーや!!
使い方は前回記事やリポジトリを参考にしてほしいですが、
要するにCUIでHTTP(S)使ってフォルダを同期してくれる君というやつです。
強みとしてはバイナリいっこで動くし、マルチOS対応だし、、推し
自動同期モードというのが目玉?でして。
マルチキャスト通信で同期先を見つけてくれます!これで同期先のIPとポートを調べてみたいな手間なく、ツールを動かせばあとはよしなに同期してくれます
やったね!
いいわけ
前回のツールがよわかったのはスマホ版の実装がうまくいかんかったので、
機能制限かけたってのが大きい。でも、色々弄ってたら今回の機能拡張に追従できるっぽい事が分かってきた。意気込み
続いてスマホ用クライアントもバージョンアップすっぞ!
前回開発みたいにスマホ版にここから数倍の時間がかかりそうだけどここまできたらやるっきゃないっと次号、スマホ用クライアント開発編Ⅱに続く!
- 投稿日:2020-07-30T02:43:19+09:00
GCPを使って、できるだけ楽してGo言語のgoroutineのリークを監視する
ゴルーチン リーク
Go言語はめちゃめちゃ簡単にゴルーチン(スレッドのようなもの)を作れるのが魅力です。
ゴルーチンはメインフローとは別に切り離されて実行されるので、デッドロックなどでゴルーチンの処理が途中で止まっていても気づかず、「終了したと思っていたが、実は実行中で残っていました」ということがありました。
それ以来、ゴルーチンの起動数を定期的にログに出力して、ゴルーチンのリークが起こっていないかチェックしているのですが、その作業が面倒くさくなってきました。
もっと楽したい
GCPのCloud Monitoringは主に、GCPの各種サービスの状態モニタリングを行う機能なのですが、アプリの状態モニタリングも行えるので、それを使ってゴルーチンの起動数を監視することにしました。
方針
Cloud Monitoringに、Go言語のpprofの値を送るようにして、Cloud Monitoring上でゴルーチンの起動数をグラフ表示します。
プログラムからCloud Monitoringに値を送るには、OpenCensusというオープンソースのライブラリを使うのですが、色々お膳立てが必要で、ちょっとした値を送りたい場合でも、結構コードを書く必要があります。
しかし、OpenCensusのGo言語のライブラリには、pprofの値をよしなに取得して送る機能があり、それを使えば数行のコードでできるので、今回はそれをそのまま使いました。
手順
権限設定
Cloud Monitoringにデータを送るには、「モニタリング管理者」権限が必要なので、アプリに付与しておきます。
サンプルプログラム
package main import ( "context" "log" "os" "time" "contrib.go.opencensus.io/exporter/stackdriver" "go.opencensus.io/metric/metricexport" "go.opencensus.io/plugin/runmetrics" ) func main() { ////////////////////////////////////////////////// // Cloud Monitoringにpprofを送る ////////////////////////////////////////////////// os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "./service-account-key.json") // exporter(Cloud Monitoring) exporter, err := stackdriver.NewExporter(stackdriver.Options{ // Cloud Montoringからの検索用文字列 MetricPrefix: "test-app-go-pprof", // データ送信頻度(60秒以上) ReportingInterval: 120 * time.Second, }) if err != nil { log.Fatal(err) } defer exporter.Flush() exporter.StartMetricsExporter() defer exporter.StopMetricsExporter() // metrics(pprof) err = runmetrics.Enable(runmetrics.RunMetricOptions{ EnableCPU: true, EnableMemory: true, }) if err != nil { log.Fatal(err) } // metrics -> exporter metricexport.NewReader().ReadAndExport(exporter) ////////////////////////////////////////////////// // ゴルーチン リーク テスト ////////////////////////////////////////////////// ctx := context.Background() for { go func() { var a [1000 * 1000 * 10]byte // メモリも消費 _ = a <-ctx.Done() // 停止 }() time.Sleep(60 * time.Second) } }補足説明
- OpenCensusはデータ部分(metrics)と送信部分(exporter)に分かれています。
- exporterをCloud Monitoring(旧名stackdriver)にして、runmetricsでpprofからmetrictを生成するようにします。
- exporter(Cloud Monitoring)がmetrics(pprof)を読み込んで出力するよう紐付けします。
- Cloud Monitoringには色んな種類のデータが送られているので、識別しやすいように「MetricPrefix」を付けます。
Cloud Monitoring
プログラムを実行すると、Cloud Monitoringに
custom.googleapis.com/opencensus/test-app-go-pprof/process/cpu_goroutines
という名前で、ゴルーチン数が記録されるので、
[Cloud Monitoring]-[Metrics Explorer]
で見ることができます。応用
他のpprofの値も送られるので、ダッシュボードでゴルーチン数とメモリの使用量をならべて表示するといったことも、プログラムの修正無しにできます。
ゴルーチンの数がしきい値を超えたら、Slackに通知などもできます。
感想など
これでゴルーチンのリーク監視作業から解放されました。
元記事・関連記事