ngrepでリクエストだけ出力する

ngrepで3000番ポートに対する通信を見る場合こんな感じで見れるけど

$ sudo ngrep -W byline -q -d any port 3000

レスポンスはいらないのでリクエストだけみたい、という場合はdst portにすればよい。

$ sudo ngrep -W byline -q -d any '' dst port 3000

'' を入れないとdstがmatchingのキーワードに認識されてしまった。

レスポンスだけみたい場合はsrcにする。

$ sudo ngrep -W byline -q -d any '' src port 3000

RailsのAPI onlyでOmniAuthがエラる

RailsAPI onlyのアプリケーションだとセッションが無効化されているのでOmniAuthを使おうとするとOmniAuth::NoSessionErrorで落ちる。

READMEに書いてあった。 https://github.com/omniauth/omniauth/blob/650943c16de33c7cdf16708b74766e95ad369610/README.md#integrating-omniauth-into-your-rails-api

config/application.rbとかにこんな感じの設定を足せばよいらしい。

config.session_store :cookie_store, key: '_interslice_session'
config.middleware.use ActionDispatch::Cookies # Required for all session management
config.middleware.use ActionDispatch::Session::CookieStore, config.session_options

OmniAuthがセッションを必要とする理由は、ログイン前のURLとかparamsを保存してcallbackフェーズで復元できるようにしているためっぽいので、これらが必要ない場合はセッション無効でも動くようにしたいなと一瞬思った。

が、omniauth-oauth2はstateというパラメータを保存するのにセッションを使っていて、これはOAuthプロバイダへのリクエストパラメータにstateを渡すことでcallbackにもそのstateを渡してくれ、その値をアプリケーション側でセッションなりに保存しておいて検証することでCSRFを防ぐというものらしい。

https://auth0.com/docs/protocols/oauth2/oauth-state

この検証機構も無効にすることはできるけど、そこまでしてセッションを無効にするモチベーションもないので諦めてAPI onlyでもセッションを有効にすることにした。

頑張らないeslint

自分で頑張って真心込めて設定書いてたけどメンテ不可能なので頑張らないことにした。

  • フォーマット系はprettierに委ねる
    • printWidthだけ120にして後は委ねる
  • 基本設定はrecommendedに委ねる
    • eslint:recommendedは控えめな感じでよい
  • 本当にほしいやつだけ追加で設定する
    • eqeqeqprefer-constだけにした
    • eqeqeqは他の言語と行き来してるとたまに間違えるから、prefer-constconst使うという意思表示
    • 他にも便利な設定いっぱいあるし今後も増えるんだろうけど頑張らない

こんな感じです。

env:
  browser: true
  es6: true
  node: true
  mocha: true

parserOptions:
  sourceType: module
  ecmaFeatures:
    jsx: true

plugins:
  - react

extends:
  - eslint:recommended
  - plugin:react/recommended
  - prettier
  - prettier/react

rules:
  eqeqeq: [error, allow-null]
  prefer-const: error

TypeScriptのLint

JavaScriptもTypeScriptも混じっているプロジェクトで、Lintのルールをなるべく共通化して運用したいというモチベーションがある。

JavaScriptのLinterはESLintを使いたい。TypeScriptのLinterはTSLintがデファクトだが、TSLintはESLintと比べて実装されているルールがだいぶ少なかったり、同じルールでも名前が違ったりする。

解決するアプローチは以下の二つがある。

typescript-eslint-parser

https://github.com/eslint/typescript-eslint-parser

ESLintのパーサーにTypeScriptを使うことでTypeScriptのLintをESLintで行う。JSもTSも同じ設定でいけるので最高便利。なんだけどREADMEに

Important: This parser is not fully compatible with all ESLint rules and plugins. Some rules will improperly mark source code as failing or not find problems where it should.

とあるように対応が不完全なところもあるのが難点。

現状で一番致命的なのは未定義の変数を検出するno-undefを有効にしていると、以下の箇所でエラーになるというバグもの。

class Foo {
  a: string; //=> error  'a' is not defined  no-undef

  constructor() {
    this.a = "a";
  }
}

ワークアラウンドな対応として、TypeScriptのときだけno-undefoffにすればいい。未定義な変数はTypeScriptのコンパイラで検出できるし。

overrides:
  files: ['**/*.ts', '**/*.tsx']
  parser: typescript-eslint-parser
  rules:
    no-undef: off

こういう感じで。

また、TypeScript specificなルールを使うには以下のようなプラグインがあるが、TSLintには及ばないので型情報が必要なLintはある程度諦めが必要になる。 https://github.com/nzakas/eslint-plugin-typescript

tslint-eslint-rules

https://github.com/buzinas/tslint-eslint-rules

もう一つがTSLintをESLintに寄せるためのモジュール。ESLintにあってTSLintにないルールを補完する*1。方向性としてはよいんだけど、現時点では対応していないルールもかなり多い。あと、TSLint本体のルールがESLintのルールと名前が違う問題は解決されない。

どっちを使うか

状況にもよると思うけどtypescript-eslint-parserを使ってESLintに寄せるようにした。ESLintとTSLintを併用しないで済むし、ESLintの豊富なルールも使える(使うかどうかは置いといて)ので、多少バグっていることを差し引いてもこちらのアプローチのほうが運用が楽そうだった。

*1:なんでTSLint本体にコントリビュートしないのかよくわからない

BdashというBIツールをリリースしました

BdashというアプリケーションをElectronで作りました。

bdash-app/bdash: A simple business intelligence application.

以下からダウンロードしてインストールできます(現状まだMac版だけ)。

https://github.com/bdash-app/bdash/releases

ざっくりとこんな感じのことができる。

  • SQLを書いて保存&実行できる
  • 結果を元にグラフを書ける
  • gistで共有できる
  • 現状で対応しているデータソースはMySQLPostgreSQL(Redshift含む)、BigQuery

仕事でRedshiftを使って分析SQLを書くことが増えて、手元ではJupyter Notebookを使ってたんだけど、SQL書いてグラフを書くだけの用途には若干オーバースペックでもうちょっと簡単にできるといいなと思ったのがきっかけで去年から作り始めたのがようやく形になったので1.0.0をリリースした。

社内でしばらくベータ版を使ってもらっていたので、まともに使えるぐらいのクオリティにはなっていると思う。(ただしBigQueryは1.0.0リリース直前に実装してまだ使い込まれてないので完成度は低いかもしれない)

利用例

例えば僕が運用しているAdventarの、年ごとのエントリ数と、実際にエントリした人が記事(URL)を投稿したかどうかの割合を出してみる。

こんな感じでクエリを書いて実行できて

f:id:hokaccha:20170207221708p:plain

フォームちょいちょいといじるとグラフが書ける。年々エントリ数は増えているものの記事の投稿率が下がっているのがわかる。改善しよう。

f:id:hokaccha:20170207221712p:plain

そして結果をこんな感じでgistにワンクリックで共有できる。

https://gist.github.com/hokaccha/e128e1c3a68527ebf2c50d5e95a089b1

自画自賛だけどこのgist共有が本当に便利。

まだまだ実装したい機能はたくさんあってこれからガシガシ開発していくので興味がある人は使ってみてフィードバックもらえると嬉しいです。

element.querySelectorで直下の要素を指定する

例えばel(DOM Element)の直下の.fooを取りたいときに、以下のようにしたい。

el.querySelectorAll('> .foo');

これだとエラーになるんだけど:scopeを使えばいける。

el.querySelectorAll(':scope > .foo');

ChromeFirefoxでは動いた。

macOSでアプリケーションが署名されてるかどうか確認する

codesignコマンドで確認できる。

$ codesign -vd /Applications/Hyper.app
Executable=/Applications/Hyper.app/Contents/MacOS/Hyper
Identifier=co.zeit.hyper
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20200 size=269 flags=0x0(none) hashes=3+3 location=embedded
Signature size=8917
Timestamp=Oct 18, 2016, 10:48:57 AM
Info.plist entries=22
TeamIdentifier=JW6Y669B67
Sealed Resources version=2 rules=12 files=2345
Internal requirements count=1 size=176