読者です 読者をやめる 読者になる 読者になる

Quiver Export #ruby #markdown

Quiverのノートブックをテキストファイルにエクスポートするツールを作りました。

nori3tsu/unofficial-quiver-export

Quiverの内部で保存しているjsonをパースしてテキストファイルにエクスポートするだけのツールです。Cronで定期的にクラウドストレージにエクスポートすることで、Quiverのノートの中をどの端末でも見ることが出来るようになります。

Text CellはHTMLになっているため、エクスポートしたテキストファイルの中にHTMLが含まれます。

インストール

gem install unofficial-quiver-export

使い方

quiver-export --in $HOME/Dropbox/Apps/Quiver/Quiver.qvlibrary --out $HOME/Dropbox/Apps/Quiver/Quiver.export

定期実行

crontab -eを使います。

LC_CTYPE=en_US.UTF-8
*/5 * * * * $HOME/.rbenv/shims/quiver-export --in $HOME/Dropbox/Apps/Quiver/Quiver.qvlibrary --out $HOME/Dropbox/Apps/Quiver/Quiver.export > $HOME/.quiver-export/quiver-export.log 2>&1

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

SSHログインでタイトルのエラーが発生するようになったときの解決方法。

Terminal

以下の設定のチェックを外す。

Preferences > Profiles > # Advanced # Set locale environment variables on startup

iTerm2

以下の設定のチェックを外す。

Preferences > Profiles > Terminal # Environment # Set locale variables automatically

参考

Quiver: MacのMarkdown Editor #mac

MacのMarkdown EditorをQuiverに乗り換えたので紹介したいと思います。

Markdownいいですよね。簡単なメモから技術的なメモまでシンプルに書けるのでとっても気に入っています。 Macで使えるMarkdown EditorとしてKobitoの操作感が好きでずっと使っていました。Kobito最高なのですが、旧バージョンのKobitoは複数端末の同期が出来ないことと、.mdファイルへの書き出しがそれほど使い勝手が良くないことから、以下の条件で移行先をずっと探していました。

  • 動作が軽い
  • Markdownのプレビュー
  • GitHub Flavord Markdown Style
  • 全文検索
  • .mdファイルへの書き出し
  • 複数端末の同期

様々なアプリを試しては挫折してを繰り返していたのですが、ようやく満足できるアプリを発見しました。 'プログラマーのためのノートブック'として作られている'Quiver'というアプリです。 これは非常に多機能かつ軽く、ほぼ全ての条件を満たしてくれて大変満足しています。

f:id:nori3tsu:20150413114519p:plain

Mac App Store - Quiver: The Programmer's Notebook

不満点は以下の2点ですが、1は現在Issueがあがっていて対応中とのこと。2は現状どうしようも無いですが、Notebook単位で.mdファイルに書き出しできるのでそれで代替できないこともないです。

  1. MarkdownのCodeブロックでシンタックスハイライトが効かない
  2. 保存形式は.mdじゃなくjson

No Syntax highlighting for code block of a Markdown cell type · Issue #70 · HappenApps/Quiver

トライアル版もあるので、同じような悩みを抱えている方は試してみてはいかがでしょうか。

2015-04-29 追記: Quiverの中身をエクスポートするツールを作りました。

Quiver Export #ruby #markdown - nori3tsu's blog

設定

参考までに私の設定の変更点を共有します。

General

  • Apperance: Dark
  • Default Cell Type: Markdown Cell

Cells

Code Cell

  • Key Binding: Vim

Markdown Cell

  • Key Binding: Vim

Styles

Preview/PresentationモードのCSSに参考リンクのgithub-markdown.cssを追加する。QuiverのCSSスタイルに合わせるため、CSS内部の.markdown-body.markdown-cellに置換する。

Sync

Web APIを作る上で考えていること

ここ数年、Web API(以降API)を作る機会が増えています。例えば、スマホやシングルページアプリケーションのバックエンド,システム間のデータ連携などです。 これらのAPI複数の言語やフレームワークで実装してみましたが、個々の機能を実装する前に考えるべき事は共通していました。これから先も多くのAPIを作成する事になると思いますので、APIを作る上での共通実装をまとめてみたいと思います。

目次

  • 文字コード
  • 日付書式
  • リクエストフォーマット
  • レスポンスフォーマット
  • API認証
  • Validation
  • トランザクション
  • ログ出力
  • 横断処理
  • 共通例外処理
  • 設定ファイル
  • 処理時間の計測
  • X-Request-ID
  • ヘルスチェック
  • 単体テスト
  • デプロイ

検討項目

文字コード

UTF-8を選択します。

日付書式

ISO8601形式を選択します。 曖昧さを無くすためタイムゾーン情報を付与したいためです。

例: 2015-04-07T09:00:00+0900

リクエストフォーマット

POST・PUTのリクエストボディはJSONを選択します。

レスポンスフォーマット

JSONを選択します。

API認証

APIの認証方法とリソースの権限制御の仕組みを考えます。 それぞれ一長一短がありますので、要件によって適切な方法を選択します。

...

Validation

入力されたパラメータを簡単に検証するための仕組みを考えます。 RailsだとActiveRecordの標準機能、JavaだとHibernateValidatorなど、メタ情報から検証出来るものを選択します。 また、検証に失敗した項目を構造化したレスポンスで返せる用に拡張します。

トランザクション

業務ロジックの正常終了・異常終了を判断して自動的にコミット・ロールバックする仕組みを考えます。 これを導入しておくと、トランザクションの張り忘れやロールバック忘れなどの些細な不具合が少なくなります。

ログ出力

ログ出力先:

  • ファイル
  • データベース
  • Fluentd

ローテーション周期:

  • 日次
  • 週次
  • サイズ

ローテーション手段:

  • Loggerの機能
  • OSのlogrotate

出力フォーマット:

  • 書式
  • 出力項目
    • ログレベル
    • スレッド名
    • ファイル名
    • クラス名
    • メソッド
    • 行番号
    • X-Request-ID

共通のログ出力:

  • リクエスト・レスポンスのDEBUGログ
  • SQLのDEBUGログ

...

横断処理

業務ロジックの前後に処理を入れる仕組みを考えます。 別項にあるトランザクション・共通例外処理・処理時間計測・X-Request-IDの付与などで使います。

...

共通例外処理

アプリケーションの業務ロジックで発生した例外を適切に処理するポイントを考えます。 APIの場合、例外によってレスポンスを選択することが多いです。

  • 不正なリクエスト・Validationエラー: 400 Bad Request
  • 認証失敗: 401 Not Authorized
  • リソースに対する権限なし: 403 Forbidden
  • リソースが存在しない: 404 Not Found
  • リソースの競合: 409 Conflict
  • サポートされていないメディア・タイプ: 415 Unsupported Media Type
  • その他の例外: 500 Internal Server Error

...

設定ファイル

開発・ステージング・本番環境など、各種環境で設定ファイルを切り替える方法を考えます。

処理時間計測

パフォーマンスを測定するために、リクエスト毎に処理時間を計測します。

X-Request-IDのログ埋め込み

障害発生時や関連システムからの問い合わせなどで対象のリクエストを一意に識別するために、レスポンスにX-Request-IDとしてUUIDを付与します。

ヘルスチェック用URLの用意

ロードバランサーなどから監視するヘルスチェック用のURLを用意します。 DBなど、APIの提供に必要なミドルウェアへの疎通に成功したら正常ステータス(200)を返す処理にします。

余談ですが、外部からの設定でヘルスチェック用URLのレスポンスを200 or 503と切り替える機能を付けると、アプリの設定でロードバランサーから切り離すことが出来るようになるため便利です。

単体テスト

選択するフレームワークや組み合わせるライブラリによって、特定のオブジェクトを生成することが難しいなどの理由で、単体テストの実装が難しくなってしまうことがあります。また、初期の段階で導入しておかないと、テストを意識した設計ができずにテストし辛いクラスが出来あがってしまうことがあります。 私の場合、忙しさに追われて単体テストを書かないという状態に陥ってしまったことがあり、その際にソフトウェアの品質が著しく下がってしまった経験から、単体テストを実行する仕組みを最初に整備しておくことにしています。 また、この段階からJenkinsなどのCIサーバと連携するために、CUIから実行できるようにします。

  • Controllerのテスト
  • Modelのテスト
  • Viewのテスト
  • Mock/Stub

...

デプロイ

稼働するサーバに向けてのデプロイ方法を考えます。 後々JenkinsなどのCIサーバと連携できるようにCUIから実行できるようにします。

おわりに

最近、これらの事をRailsで実装する機会があったのですが、驚くほど簡単に実装できてしまいました。 Java複数のライブラリや設定ファイルを組み合わせて実装していた頃にはもう戻れませんね。

Java+RSA公開鍵暗号化 -> Ruby+RSA秘密鍵復号

JavaからRSA公開鍵で暗号化したデータをRubyからRSA秘密鍵で復号するサンプル。

鍵の保存

require 'openssl'

OpenSSL::Random.seed(File.read("/dev/random", 16))
rsa = OpenSSL::PKey::RSA.generate(2048)

# 秘密鍵を保存
File.open("private_key.pem", "w") do |f|
  f.write(rsa.export)
end

# 公開鍵を保存
public_key = rsa.public_key
File.open("public_key.pem", "w") do |f|
  f.write(public_key.export)
end

Java+RSA公開鍵暗号

package com.example;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

public class RSAPublicKeyExample {
    public static void main(String[] args) throws Exception {
        RSAPublicKeyExample example = new RSAPublicKeyExample();

        String encrypted = example.encrypt("test");
        System.out.println(encrypted);
    }

    public String encrypt(String data) throws IOException,
            GeneralSecurityException {
        // ファイルから公開鍵を読み込む
        PublicKey key = readPublicKeyPem(this.getClass().getResourceAsStream("/public.pem"));

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        // 暗号化+Base64
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.encodeBase64String(encrypted);
    }

    private PublicKey readPublicKeyPem(InputStream stream) throws IOException,
            GeneralSecurityException {
        // PEMのヘッダとフッタを削除
        String pem = IOUtils.toString(stream)
                .replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
        byte[] decoded = Base64.decodeBase64(pem);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);

        return key;
    }
}

Ruby+RSA秘密鍵復号

require 'openssl'
require 'base64'

# ファイルから秘密鍵を読み込む
rsa = OpenSSL::PKey::RSA.new(open('private_key.pem'))

# 復号
puts rsa.private_decrypt(Base64.decode64('{Javaで暗号化+Base64した文字列}'))
# => test

参考

VarnishのコンパイルでError 1

エラーメモ

環境

現象

Varnishをコンパイル中に以下のエラーが発生。

varnishadm.c: In function ‘interactive’:
varnishadm.c:234: error: ‘rl_already_prompted’ undeclared (first use in this function)
varnishadm.c:234: error: (Each undeclared identifier is reported only once
varnishadm.c:234: error: for each function it appears in.)
varnishadm.c:236: error: ‘rl_attempted_completion_function’ undeclared (first use in this function)
varnishadm.c:297: warning: implicit declaration of function ‘rl_forced_update_display’
varnishadm.c:300: warning: implicit declaration of function ‘rl_callback_read_char’
make[3]: *** [varnishadm-varnishadm.o] Error 1
make[3]: Leaving directory `/home/vagrant/download/varnish-3.0.6/bin/varnishadm'
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory `/home/vagrant/download/varnish-3.0.6/bin'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/vagrant/download/varnish-3.0.6'
make: *** [all] Error 2

原因

readline-develがない。

対策

$ yum install readline-devel

参考

Vagrant上のCentOSでhttpd.confをVagrant共有ディレクトリのシンボリックリンクにしているとOSブート時にhttpdが自動起動しない #vagrant #apache

これはApacheに関わらず、Vagrant共有ディレクトリにサービス起動に必要なファイルを配置している場合に発生する現象です。 解決方法を考えてみましたが、起動スクリプトを変更するという微妙な方法になりました。 どなたか良い解決方法をご存知なら教えていただきたいです。

続きを読む