その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

linenotcatをhomebrewでインストール出来るようにした

この前書いたlinenotcatをhomebrew経由でインストール出来るようにしました.そうすると便利だと思ったからです.
linenotcatはこんなの.

要はコマンドラインからLINE Notifyにメッセージを投げつけられるツールです.

もともとはGitHub Releasesにビルド済みバイナリをポンと置いていたのですが,それをbrewで引っ張ってこれるようにしましたという話.
こんな感じでインストールが出来るようになって楽ちん.

$ brew tap moznion/homebrew-linenotcat
$ brew install linenotcat

brewで公開するのははじめてやったのですが,案外手軽にできて良かったです.

こんな感じのリポジトリを作ってFormulaを書くだけでいける.
urlGitHub Releasesに置いてあるビルド済みバイナリのURLを指定するとそのバイナリがダウンロードされてきて,それをmvでいい感じのファイル名にrenameして,bin.installでパスが通ってる所にそのバイナリに対するsymlinkを張る,という感じ.
こうすることで,クライアント側でgo buildとかを走らせて各自コンパイルしてもらう必要なく,ビルド済みバイナリを配布するだけで即利用可能になって便利!!

という感じでした.ご利用下さいませ.

「Open Beer Serverの理論とその実装」というタイトルでbuilderscon tokyo 2016にて発表します

builderscon.io

で表題の通り発表します.

builderscon.io

内容としては物理のビールサーバをイチから組み立てて,更にそのビールサーバにHTTPを喋らせるという何を言ってるんだかよくわからない感じですが当方至って真剣です.
ビールサーバってどうやって動いてるの? ビール樽の構造ってどうなってるの? というところから,ビール樽を継続的に監視する為のシステムの構築までざっくばらんに話せたらな〜と思っています.
皆さんぜひ来て下さい!


ところで以下は現時点でOpen Beer Serverの構築にかかっている費用になりますが,今後更にかかります.

f:id:moznion:20161110144738p:plain

なんてこった,これでは年が越せません.破産してしまいます.Open Beer Serverではカンパを募集しています.

linenotcatというツールを書いた

LINE Notifyが便利でよく使っています.LINE Notifyが何かとか何が便利なのかとかをご存じない方は

コマンドラインから LINE にメッセージを送れる LINE Notify « LINE Engineers' Blog

を読んでいただければと思いますが,あえてものすごくざっくり説明するとim.kayacのLINE版みたいなやつです.

んで,Slackというやつも便利で,こちらはチャットツールなわけですが,そのSlackにはslackcatというこれまた便利なコマンドラインツールがあり,これはコマンドを叩くだけで任意のSlackのchannelに対してメッセージやファイルの中身を送ることが出来ます.その名の通りcatコマンドの結果がSlackに流れるという感じ.

というわけでそのLINE Notify版を作ったという話です.コマンドライン経由でLINE Notifyにメッセージを送ることが出来ます.

github.com

LINE NOTify + catということでlinenotcatという名称です *1

基本的な使い方としてはslackcatとだいたい同じで,

$ echo 'YOUR_ACCESS_TOKEN' > $HOME/.linenotcat

という感じでAccess Tokenを登録するともう使えます.

$ echo 'Hello world!' | linenotcat

という風にすれば標準入力経由で投稿が出来て,

$ linenotcat /your/awesome/file.txt

という風にすればファイルの中身を投稿できます.

$ echo 'Hello world!' | linenotcat --tee
Hello world!

teeもできます.

$ tail -f /your/awesome/error.log | linenotcat --stream

stream modeなんてのもあり,上記の例の場合はtailが何か出力したらその内容を投稿するようになります (現状だと3秒間内容を溜め込んで投稿するようになっています).

$ linenotcat --message 'Hello world!'

なにかと便利だったのでそのままメッセージ送れるモードなんてのもあります.

$ linenotcat --image /path/to/your/awesome/image.png

LINE Notifyは実は画像をアップロードして送れるという機能もあるので画像も送れるようにしました

$ linenotcat --image /path/to/your/awesome/image.png --message "Yo!"

メッセージも添えられます.

$ linenotcat --config_file /path/to/your/config

config fileつまりAccess Tokenも差し替える事ができます.送り先を差し替えられたり出来ます.

$ linenotcat --status
{"status":200,"message":"ok","targetType":"USER","target":"moznion"}

今のTokenの情報を引いてくることも出来ます.


という感じです.まあこんなん無くてもshell scriptで大概解決するんですがバイナリポン置きで動くと楽だなという感じでこさえた次第です.
動くバイナリはGitHub Releasesにあるのでご利用下さい.

github.com

[追記]

homebrewに対応しました.

$ brew tap moznion/homebrew-linenotcat
$ brew install linenotcat

*1:そしてLINEは猫ではない

GuiceとSpringを共存させたい

もともとGuiceを使っているプロジェクトがあってそれをSpringに移植したい,だとか,Guiceをバリバリ使っているコンポーネントをSpringのアプリに組み込むことで資源の再利用をしたい,だとか,そういう事になることがある.あるのです.この前実際になった.

で,"spring guice together" とかそういう適当な検索ワードで調べると大体「そんな事はするな」「そうしたい意味がわからん」「そう考える時点でおかしいのでは」などといった,「とにかくやるな」という結果が引っかかる.確かに.しかしやらなければならない時があるのだ……というわけでそのメモを記す.

TL;DR

やらないで済むならやらないほうが良い.

本編

ご存知の通りGuiceGoogle製のDI Frameworkで,一方のSpring frameworkはWeb Application Frameworkである.この二者間になぜ共存の問題が発生するかというと,Spring Frameworkもその内部にDI Frameworkを持っているから,というかそもそもDI機構がSpringの中核を担っているからである.つまりDI Frameworkが2個ある状態となるなのでそれらを矛盾なく管理する必要が出てくる.どうすれば良いのか.

アプローチ

SpringのDIをメインで利用して,Guiceはサブとして扱うという方法を今回は採用した.簡単に言うと,SpringのDIコンテナに対してGuiceのInjectorをInjectするという手法.
こんな感じ.

@Configuration
public class GuiceModuleConfig {
    @Bean
    Injector injector() {
        return Guice.createInjector(new AppModule());
    }
}

AppModuleGuiceのModuleで,このModuleを元にinjectorを作成し,そのinjectorをSpringのDIにinjectしてSpring DIから取得可能なようにしておく.そんでもって以下のようにAppModuleで提供されているinjecteeをSpringのDIを通じて取得できるようにしてやる.

@Bean
DataSource dataSource(final Injector injector) {
    return injector.getInstance(DataSource.class);
}

@Bean
FluentLogger fluentLogger(final Injector injector) {
    return injector.getInstance(FluentLogger.class);
}

つまりはSpringのDIにinjectしたGuiceのinjectorをSpring DI経由で引っ張ってきて,更にそのinjectorからGuice経由で任意のinstanceを取ってくるという感じ.とりあえずこれで基本的なGuiceSpring FrameworkのDI機構を共存させることが可能となる.なおSpringのDIについてはGuiceがあろうとなかろうといつものように利用できる.

Guiceで言うところのServletScopes.REQUEST使いたいときにどうするのか

@RequestScopeを使う.以下のように.

@Bean
@RequestScope
Connection connection(final Injector injector) {
    return injector.getInstance(Connection.class);
}

しかしGuice経由でinstanceを取ってきている場合はこれだけでは不十分で,GuiceServletContextListenerを継承したClassをServletContextListenerとして登録してやる必要がある.

@WebListener
public class AppGuiceConfig extends GuiceServletContextListener {
    private ServletContext servletContext;

    @Override
    public void contextInitialized(final ServletContextEvent servletContextEvent) {
        servletContext = servletContextEvent.getServletContext();
        super.contextInitialized(servletContextEvent);
    }

    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new AppModule());
    }
}

なおSpring-Boot等でweb.xmlを利用しない場合は上記のように@WebListenerを用いてListenerとして認識させてやる必要がある.

雑感

2つのDI Frameworkを共存させ,管理する事となるので複雑さとコストが増すように感じる.また,適切に双方のinjecteeのライフサイクルのハンドリングも正しく行わなければならないのでその点においても複雑さが増大する.やらなくて済むのであればやらないに越したことは無いと思う.

以上です.我々はやっていっています.

[追記]

https://github.com/spring-projects/spring-guice

これ使えば楽に出来そうな雰囲気があるんだけど,maven centralに上がっていなくて面倒だったので採用を見送ったという経緯があります.未検証.

Springの起動時に好きな画像をAAにして表示する

Spring Boot 1.4.1 1.4.0 (訂正しました.詳細は id:dayflower さんのコメントを参照下さい) の機能として,Springの起動時に任意の画像をAAとして表示できる機能が追加されたようです.
なんかここに書いてた.

www.infoq.com

やり方は非常に簡単で,

  • banner.jpgbanner.pngあるいはbanner.gifという名前の画像ファイルを/src/main/resourcesの直下に置く (あるいはbanner.image.locationで設定した場所に置く)

以上.早速やってみましょう.

f:id:moznion:20161024232806p:plain

普段のSpringの起動後のターミナルといえばこんなのでしたが……

f:id:moznion:20161024232835p:plain

この機能を使うとこの通り! ちなみに元画像は僕のアイコンのこれです.

f:id:moznion:20161024232911p:plain

若干ホラー感がある……と思いきや遠目からAAが中々の再現度であることがわかります.すごい!


当初はこの機能について「なぜウェブアプリケーションフレームワークの機能として入ったんだ……」と疑いの眼差しを向けていたのですが,実際に使ってみると想像以上に気分が上がります.自分のプロジェクトのロゴなんかを入れると良い感じですね!

以上です.


[追記]
画像が大きいとAAも大きくなります.「そんなAA大きくなくて良い!」という時は,application.propertiesのbanner.image.widthもしくはbanner.image.heightを設定することでサイズの調整ができます.便利便利.

ソフトウェアライセンスのURLが軒並みhttpsが使えた

READMEだとかLICENSEファイルだとかに書くソフトウェアライセンスの文言には,そのライセンスのURLが含まれていることが多いと思う.
最近ソフトウェアライセンス文言をめちゃめちゃ書く事があって,その時にふと「ライセンスのURLは軒並みhttpで表記されてるけど実はhttpsでいけるんじゃないのか?」と思ってざっくり調べたら色々なライセンスがhttpsのコンテンツを提供していることがわかった.全部書くと大変なので一部だけれどこんな感じ.


ライセンスの文言って大体コピペとかでパパっと済ませてしまうのでURLが元のままだったりするのだけど,実はhttpsで提供されている事があるので今後はそっちを使っていこうと思った.


[追記]
id:r7kamuraさんに教えてもらったんだけれど,opensource.orgSSLに対応していてHTTPでアクセスするとHTTPSにリダイレクトされる様子.時代はSSL

雑に特定のホストの特定のポートと疎通できてるかどうか確かめる

新しくサーバ立てた時やサーバ追加した時に,そのサーバが他のホストの特定のポートと疎通できるかどうかチェックする必要が出てくる時がある.ACLとかの兼ね合い.
そういうのは本番の環境だと監視のシステム等に組み込まれていたり,あるいはserverspecとかで確認されていることが多いと思うのだけれど,その場で雑に確認したくなることがあると思う.そういう時はtelnetで繋いで,quitして,というのを繰り返していく感じになりがちなのだけれど,対象となるホストの数が多くなってくるとそういうことを手でやるのも大変になってくる……というわけでこれです.

$ (sleep 0.1; echo quit) | telnet $HOST $PORT)

こういう風にしておくとtelnetで繋いだ後にquitを発行するということを自動でやってくれる.
とはいうものの,こうすると正しく繋げているかどうかを目視で確認する必要が出てくる (つまり以下の様な文字列が正しく出力されているかどうかを目視で確かめる必要がある).

Trying ::1...
Connected to localhost.
Escape character is '^]'.

更にこの方法だと Connection closed by foreign host となるために,exit codeが1となってしまう.その為,スクリプト中でexit codeを使って良い感じにするのが難しい.


というような話をしていたら,id:karupaneruraさんから「それncで出来るよ」と教えてもらって以下の様な感じになった.

if [ -z $((sleep 0.1; echo "\nquit") | nc $HOST $PORT) ]; then
    echo "Fail $HOST:$PORT"
fi

見た目としてはtelnetの代わりにncを使って,送り込む文字列を quit から \ncode にしたという様子.
前者はまあその通りという感じ.後者について少し説明すると,ncで正しく繋げている場合に先に改行文字を送り込むと ERROR というレスポンスがncから返ってきた後にquitする.一方で正しく繋げていない場合はncから何もレスポンスが返ってこないという挙動になるので,それを利用して文字列が空か空ではないかで正しく繋げているか否かを判断している (つまり文字列が空でなければ正しく繋げていると判断している).

なお補足すると,ncだとこういう風に動くんだけど,CentOS6のncatコマンドだとquit時に+OKという文字列が出てくるので最初に改行文字を送り込む必要は無かったりする.みたいな感じで微妙にnc (ncat) コマンドの挙動に差があったりするので,そこら辺はまあ臨機応変に対応しましょうという感じ.


これを適当にforの中に組み込んでおくと雑に疎通のチェックが出来て便利,という話でした.ncを使うという発想がなかったので勉強になった.


[追記]

コメントでid:bearminiさんが /dev/tcp を使う方法を教えてくれたんですが,これめちゃめちゃ便利ですね.知らなかった……