20200730のGoに関する記事は5件です。

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)
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Nativeで作ったアプリをリリースしてから1年経ったので振り返ってみる

Frame 1.png

React Native製、予定作成アプリ「ペペロミア」を公開しました

以前記事にしたペペロミアが公開してから1年経ったので振り返りも兼ねて記事にまとめてみました。
個人プロダクトのアーキテクトとかの参考になれば良いかなと思います。

主に使用している技術

GitHub

前はモノレポで1つのRepositoryで全Sサービス管理していたが、各サービスごとにわけるようにしたので以下の通りです。

リリースノート

今までの主な更新リリース内容は、こちらで確認できます。

https://peperomia.app/information

ペペロミアとは

プロジェクトの概要は、こちらを参照

https://peperomia.app/about

アプリ

https://github.com/wheatandcat/Peperomia

スクリーンショット 2020-07-27 23.09.57.png

■ 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については以下で公開しています。
ペペロミア Figma

Figmaに関しては前に記事にしているので以下を参照
エンジニアでも出来る!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がこちら

主なバージョンアップ変更は以下の通り

  • React Native v0.61以降になりFast refreshが導入されたので開発時に高速でリフレッシュできる
  • 元々expo内部に入っていたモジュールが別モジュールに分割
  • webサポートされた(けど、他ライブラリの影響でペペロミアでは、ビルドでコケるので使えていない :sweat:

ダークモードの実装

以下で解説しているのが細かい実装は省略しますが、
React Native製の公開しているアプリにダークモードを実装してみた

現状は、端末の設定を見て通常モード、ダークモードの切り替えを行う実装になっています。
ホーム画面の比較をすると、こんな感じです。
darkmode.png

カレンダー機能の実装

calendar001.png

  • スケジュールに日付入力をできるようにしてカレンダー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通知の実装

Backend

https://github.com/wheatandcat/PeperomiaBackend

概要

言語はGo言語で実装
主にアカウント認証後のデータのやり取りのAPIを実装しています。

使用技術 / ツール

フレームワーク

Ginを利用して実装
https://github.com/gin-gonic/gin

GraphQLは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
web001.png

■ 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/http

Web側でスケジュール内容の編集の際は@nuxt/httpでAPIにアクセスしてデータ変更を行っている

ヘルプサイト

https://github.com/wheatandcat/PeperomiaHelp
スクリーンショット 2020-07-28 22.58.52.png

■ 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
スクリーンショット 2020-07-28 23.25.26.png

■ URL
https://peperomia.app/

概要

Reactで実装しています

使用技術 / ツール

デプロイ先

Netlifyにデプロイしています。

主なリリース内容

LPサイトにアニメーションを追加

Jul-22-2020 01-20-20

react-inview-monitorを使ってスクロールに入ったタイミングアニメーションするように修正

実装の詳しい内容は以下の記事参照
Reactで作成したLPサイトにアニメーションを追加してみた

RSS経由からリリースノートを表示

スクリーンショット 2020-07-22 19 12 00

リリースノートを自動生成するスクリプトを作成してブログに投稿
タグを付けてRSS経由で取得して、LPページに表示させています。

リリースノートの自動生成については以下の記事参照
リリースノートを自動生成するスクリプトを書いてみた

今年〜来年への開発予定

Firestoreの設計見直し

実装時はFirestoreへの理解が浅かったのもあり、RDBっぽい設計になっているので、見直し & 新設計にマイグレーション予定
CollectionGroupを使えば、ある程度柔軟に設計できるかな模索中。

whereのinに取得制限があったりもするのでFirestoreは設計は、すごく重要だなと実感
https://firebase.google.com/docs/firestore/query-data/queries#limitations

APIの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年間で結構開発していたんだなーと思いました。また、なにかの区切りに振り返りの記事を書こうと思います :bow:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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アプリにした。

:point_up_2:上記のURLから試してみることができる。

まとめ

実装の解説はあまりしなかったが、Featherweight Goは小さく言語実装にそこまでの手間がかからないのですごく経験が豊富でなくても取り組みやすいと思う。まだやっていないが、いずれはFGGの実装とFGへの変換も着手したい。これらの実装を通して、Go言語にジェネリクスを搭載すると速度が変化するのか?という論争に終止符を打ってほしい。


  1. https://y-yu.github.io/featherweight_go/ にWeb(Scala.js)の実装があるので、そこで試すことができる。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTTPでrobocopyやrsyncみたいなの!オレトラストネットワークでちゃっちゃとファイル共有Ⅱ

前回

オレトラストネットワークでちゃっちゃとファイル共有

の続きです。前回の載せたら、

「Syncthingに似てる気がするけど知ってる?参考になるかもよー見てみたら??」

というありがたいレスが。知らないので調べてみますわーってレス書いた後で過去にQiitaのSyncthin記事にがっつりLGTM入れてた!

Syncthingつよい

僕のツールのがニッチで良い部分もありつつ見習いたい点が多々出てくる出てくる

  • 同期状況とか完了したかどうかサーバー、クライアント両方で見れる
  • 接続中のサーバーを見れる
  • 全通信をプロトコルで暗号化したり効率化してる
  • 同期対象のディレクトリ対応
  • 中継SaaS持ってるのでinbound通信を開放しなくていい
  • GUI持ってるので操作が分かりやすい
  • バックグラウンドで同期してくれる
  • 設定が保存できるので前回と同じ同期がやりやすい

洗い出しできたところで、ワイツールも既存のHTTP Proxy挟めるなど利点があるので

  • 同期状況とか完了したかどうかサーバー、クライアント両方で見れる
  • 接続中のサーバーを見れる
  • 同期対象のディレクトリ対応
  • 設定が保存できるので前回と同じ同期がやりやすい

これを盛り込んで改良することにした!機能以外にUXも必要だよね、とか勉強になるね!

Go言語つえー

絞り込んで改良する事にしたーで、4日で実装できた!やっぱGo言語サイコーや!!

yasutakatou/doukie2 - GitHub

使い方は前回記事やリポジトリを参考にしてほしいですが、

要するにCUIHTTP(S)使ってフォルダを同期してくれる君というやつです。
強みとしてはバイナリいっこで動くし、マルチOS対応だし、、

推し

自動同期モードというのが目玉?でして。
マルチキャスト通信で同期先を見つけてくれます!

autosync.gif

これで同期先のIPとポートを調べてみたいな手間なく、ツールを動かせばあとはよしなに同期してくれます

やったね!

いいわけ

前回のツールがよわかったのはスマホ版の実装がうまくいかんかったので、
機能制限かけたってのが大きい。でも、色々弄ってたら今回の機能拡張に追従できるっぽい事が分かってきた。

意気込み

続いてスマホ用クライアントもバージョンアップすっぞ!
前回開発みたいにスマホ版にここから数倍の時間がかかりそうだけどここまできたらやるっきゃないっと

次号、スマホ用クライアント開発編Ⅱに続く!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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]で見ることができます。

Art076.png

応用

他のpprofの値も送られるので、ダッシュボードでゴルーチン数とメモリの使用量をならべて表示するといったことも、プログラムの修正無しにできます。

Art078.png

ゴルーチンの数がしきい値を超えたら、Slackに通知などもできます。

out_Art075.png

感想など

これでゴルーチンのリーク監視作業から解放されました。

元記事・関連記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む