技術的な話題 に関する投稿を表示しています

LTSV なデータを SQL で探索する ltsvq を作った

sters/ltsvq: ltsvq is LTSV Queryer that written in Go

Labeled Tab-separated Values (LTSV) なアクセスログのデータをパースし、少しだけ複雑な条件で集計する必要があった。
ELKStackなんかで集計する仕組みを整えて構築するよりも、さくっとできるソリューションでよかった。
ぱっと調べても便利に使えそうなのはなさそうに見えたので、ぱっとひらめいたアイデアで行けるかどうか、おためし的に作った。

実装は GitHub - Songmu/go-ltsvGitHub - mattn/go-sqlite3: sqlite3 driver for go using database/sql がほぼすべて。
パースした結果を SQLite にオンメモリで入れて、リクエストされたクエリを実行し、取れたものを再び LTSV になおして出力する。
SQLite でできることはできるので、絞り込みも並び替えも、集計だってできる。

と、まあ作ること自体はすぐだったのだが GitHub - goreleaser/goreleaser: Deliver Go binaries as fast and easily as possible でリリースを作ろうとしたら数時間積んでいた。
色々調べた結果、必要なライブラリが詰まった Docker イメージを準備し、その上でスタティックリンクになるように ldflags を指定してビルドするのが正解らしい CGO も効いているはず、きいてないと mattn/go-sqlite3 が動かんのでは…?

このあたり cmd/go: build: add -static flag · Issue #26492 · golang/go

ストリーミングなデータの tail -f みたいなずっと流れてくるデータをパイプして使うようなものは、どうしたらいいのかわからなかったので諦めてしまった。また今度挑戦してみよう。

静的コンテンツをシュッと共有する何かの onstatic を作った

ざっくりというと Web サイト(not Web アプリケーション)を作ったときに、公開はまだなんだけど共有したいなっていうのをなんとかする良さげソリューションがないような気がして自作した。

sters/onstatic: onstatic is static page hosting controller.

ビルドされたバイナリを動かしさえすればどこでも出来る。
都合によって CGI 対応をしたので、恐らく FTP 的なことしか出来ないようなレンタルサーバーでも使えるはず。少なくとも Apache で CGI するように設定したら動く。

使う手順はこんな具合。

  1. /registerにリクエストし、Git リポジトリをクローンできる URL をアプリケーションに登録する
  2. アプリケーション内でローカル git リポジトリの準備と SSH キーが生成、保存される。公開鍵がレスポンスになるので、メモしておく
  3. 公開鍵をクローンできるように登録
  4. /pullへリクエストすると 2 で保存した秘密鍵を使って 1 で指定したリポジトリを取りに行く
  5. リポジトリ名をハッシュ化したものがレスポンスされる
  6. アプリケーション URL/ハッシュ値/ファイルパス 的な URL でアクセスできるようになる
  7. リポジトリを更新したら /pullを呼べば git pull をしてくれる

Github であれば DeployKey に登録してしまうのがお手軽。書き込みすることは想定していないし。


実装は go-git を使っていて、中で git クライアントな振る舞いをしている。

src-d/go-git: A highly extensible Git implementation in pure Go.

この中で使っている billy.Filesystem がすごい便利だった。ファイル操作するテストとか書くのちょっとつらそうだなあと思ったけれど、インターフェース化されていて memfs な実装もあった。

src-d/go-billy: The missing interface filesystem abstraction for Go

アプリケーションサーバへのアクセスは、一定のフィルタしたあとに http.FileServer.ServeHTTP をしている。

onstatic/handler.go at master · sters/onstatic

その他、Github Actionsを使ってみたりなどした。リリース作るのがほぼ設定いらずの簡単サクッといけるの便利。


でもって、静的ファイルをシュッと共有できて便利になったのだった
1 バイナリでただのアプリケーションサーバなので nginx でプロキシしたり、認証挟んだり、いろいろ便利、かもしれない。

まあ Netlify 的なものなどでいいといえばいい。
Netlify: All-in-one platform for automating modern web projects.

前後の記事

Next:
Prev:

manabeyond

これはなにか

manabeyond

ここ 2-3 週間の間、夜な夜なちょっとずつ作って、ようやく自分の中でこういうことがしたいなあが形になって一通り使えるようになった。
まだ、どういうふうにやっていこうかとか、どういう要素を見せるようにしたらいいかとか、なんにも決まってないし考えも進んでなく、とりあえず、自分がつかいたい、をファーストにやっている。破壊的変更もバシバシするかも。

自分が学びを得る機会というのはそこら中にあるわけで、例えば Twitter を眺めているときにも、誰かの RT に気になる事柄があれば開いてへ〜〜〜となっている自分がいたり、例えば誰かと話していたり、例えば自分が何かの作業をしていてわからないことにあたったとき、大きくはない、小さな学びというのがたくさんある。じゃあそれをブログや Qiita などの何かでアウトプットしましょうよ、というとちょっと尻込みしてしまうようなところもある。こんなことを書いても、とか、ちゃんとまとめねば、とか、見られるのかな、などなど。そうこうしていると、まとめるのがおっくうで後々になったり、書く気はあれどちょっと後でにしてしまいすぐ忘れてしまったりする。
これはとりあえず、今、こういうことを学んだぞ、をシュッと記録するためだけのもの。整理したり、まとめたり、深追いで調べたり、余計なことは一切いらない。なるほどと思ったそれそのものを記録する。それがもし間違ってたりしたら学び直し正しい知識を得ればいいし、それをぼくらは強く意識をしてはいないかもしれないけれど、やっているし、できているはず。
記録をすることで何が起こるかというと、何か大きな事柄に挑戦しているときに、自分がどういうことを調べてその大きな事柄に挑んでいったのか、どのくらいの時間を書けたのか、様々な発見があるんじゃないかなと。

ここまではひとりで捉えたときの話で、もしかしたら、その学びは誰かとつながることでコラボレーションができるんじゃないかなと思った。実はあんまり知らなかったこととか、そっちの方向はちょっとまだわからないとか、自分のふった内容に相手からツッコミがあって調べたら新しい発見があったとか、別の事柄なのだけど適用できそうなこととか、ひとりで学ぶよりも様々に舞台を広がっていくものだと思う。例えば今日一日だれかと話をしたことを振り返ってみたりしたらなんとなくアテがでてくる。ちょっと何をいっているのかわからないけれど、ここでの、誰か、というのは過去や未来の自分も含まれてくるんじゃないかな。以前やった気がするなあ、なんだったかな〜〜〜とか、よくあると思う、それを振り返って、もしかしたら中途半端だろうのできっとまた調べる。そうするとあたらしい発見もあって、また、なるほど、と。

manabeyond という名前はこのあたりから来ていて manabi + beyond 学びの向こう側に行こう、みたいなイメージ。

ということで、どんなことを学んだのか、を一言で書き、つながっていくようなことに重点した何かが欲しいな、と思った。

調べきれていないだけなのだけれど、こんなことに重点を置くようなものは無い、気がする。
ブログ系サービスや Qiita などは近いかもしれないけれど、一言で出すことはほとんどないんじゃないだろうか。Stackoverflowやteratial とか Q&A 系は完全に違うだろう。 Scrapbox ヘルプ をみると Scrapbox はかなり近いかもしれない。トップページにはチームのためのメモ、というので、コンセプト的な話では若干ずれてる、のかな。はてなブックマーク系な、ブックマークを記録するのもちかいと思う。なるほどこうやるのか、みたいな学びは検索して見つけることがおおい。URLなしでもいける違い。

今後どうしていくか

冒頭にも書いたけれど、まだあんまり決まってない。こんな機能がほしいな、と思っているのでちょっとずつ作っていく。

  • 内容への指摘
    • 指摘、みたいな書き方だとむずかしいので、やわらかい表現いいな
  • 内容の更新
    • そのとき思ったことは変わらないけど、知識は更新される
  • 可視化
    • hourly での投稿数 daily での投稿数
    • タグ別の投稿数
  • タグ同士での関連性
  • タグの名寄せ
  • 振り返り
    • weekly とかの一定周期でどんなタグ、どんな内容があったかサマリを作る
  • 学びのグループ化
    • グラフィカルに、これとこれはこういうカテゴリで取り扱いたい、みたいなのがほしいときがある
    • 例えばまとまった何かに仕上げようとしたときに、自分の中でのまとまりがほしいはず

前後の記事

Next:
Prev:

fail2ban で ban した IP が firewalld に登録されているか確認する

設定の仕方によっても表示される内容は違う、とおもう。
これは sshd を firewallcmd-ipset の action にしたときのもの。

$ sudo firewall-cmd --direct --get-all-rules
ipv4 filter INPUT 0 -p tcp -m multiport --dports ssh -m set --match-set fail2ban-sshd src -j DROP

$ sudo ipset list
Name: fail2ban-sshd
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536 timeout 86400
Size in memory: 312
References: 1
Number of entries: 2
Members:
xxx.xxx.xxx.xxx timeout 86317
xxx.xxx.xxx.xxx timeout 86316

WordPressのメタデータをつか

WordPress にはお手軽便利に関連データを出し入れできる、メタデータとよばれる仕組みがある。
メタデータ API - WordPress Codex 日本語版

これを使うと、例えば、投稿に対するリアクションをつけるようにしたり WordPress の標準にはないデータを乗せることができるようになる。

ちなみに、似たような…というか大体同じ認識のカスタムフィールドなるものもある。これもメタデータ。こっちは登録時?に設定できるようなもの、と思っている。管理画面で入れると、テンプレート側でもその値に合わせて何か表示できる、みたいな。
カスタムフィールドの使い方 - WordPress Codex 日本語版

メタデータにいれるものは serialize に通せるものならなんでもよいようで、配列はもちろん、__sleep()と__wakeup()メソッドを実装していればクラスでも問題なくいけるっぽい。たぶん。
add_metadata() | Function | WordPress Developer Resources
PHP: serialize - Manual

で、この post_meta 系の関数、それそのままだとちょっと大変になる場合があったので簡単にラッパークラスを作った。
wputil/PostMeta.php at master · sters/wputil

こんな感じでつかえる。

$reaction = new PostMeta(get_the_ID(), 'reaction');
echo 'Smile! ' . $reaction->get()['smile'] . ' times';

追記:2020-03-10 PHPのクラスをたどって図で出すツール sters/php-class-graph

あまり知らないクラスのコードを読んでいると、あっちのクラスにいったり、こっちのクラスに行ったり、コレ何だったっけ?、がたくさんでて大変。で、それを説明するのも大変。
というわけで、サクッと簡単にクラスの繋がり方を可視化するような何かを書いた。

GitHub - sters/php-class-graph

書いたはいいんだけど、あんまり考えずにえいやーで作ったのでこれ以上拡張出来ない感じになってしまった…
テストもちょっと書き方な〜〜〜となってしまったのでリファクタ余地は大いにあり…。

PHP のコードをパースするために nikic/PhpParser を使っている。
GitHub - nikic/PHP-Parser: A PHP parser written in PHP

それを使ってクラス呼び出しっぽいのを辿っている。このあたり。

php-class-graph/Visitor.php at master · sters/php-class-graph · GitHub

これで、あるクラスから、どのクラスを呼ぼうとしているかを記録。その記録を整理して図形データとして出力できるようになっている。

クラスっぽいのを辿る際に、クラス名からファイル名を解決するために、プロジェクトルートディレクトリを指定し、その composer autoloader を読み込んでいるのがひとつ工夫したポイント。このあたり。
php-class-graph/SourceList.php at master · sters/php-class-graph · GitHub

おしごとコードや自分のいくつかで試したけど、ちゃんとできてそう…?
たとえば sters/cakephp3-aws-s3-datasource: AWS S3 datasource in CakePHP3 でやるとこういう。いやでもどこからともなく親ノードが発生するのはちょっと違う気がするなあ…、間違ってそう…。

このまま使うと、開始地点から永遠に深ぼってしまうので、どこまで辿るのが指定したほうがいい vendor 下は無視するとか。といったのも example ディレクトリに作ってみたのでお試しどうぞ。

ここから追記: 2020-03-10

実はStaticXxxをどうこうする実装がまるっとなくてバグっていた。というわけで直したらちゃんと出るようになった。

さらに example/whole_project.php というそのままで便利に使えそうなスクリプトを書いた、これでそれぞれのプロジェクトでも実行しやすくなった。と思う。ぜひお試しあれ。

CREATE TABLE 文から Markdown のテーブル表記をつくる

ドキュメントにテーブルの説明を書くのがちょっと苦しかったので CREATE TABLE 文から Markdown のテーブル表記を作れるようにした。

GitHub - sters/createtable2Markdown

CREATE TABLE 文をパースできれば勝てるので別に MySQL 限定とかではない。特殊すぎる記載じゃなければ動くと思う。

GitHub - xwb1989/sqlparser: SQL Parser implemented in Go

これがすごくて、若干の挙動が怪しい不要な要素をスルーするようにしてるけれども、あとはパース結果を組み立てる以外なにもしてない。

標準入力で SQL な文字列を受け取って、標準出力で Markdown が出せるようにしているので、ダンプしたものをそのまま流したり、クリップボードを活用したり、コマンドラインでサクサク使うのにめちゃいい。
Readme にも書いたけどこういうことができる。

mysqldump -u database_user -p -d -n --compact database_name | createtable2Markdown

ごみばこいんのjQuery依存をなくそうとした

ごみばこいんの jQuery 依存をなくそうとした。
背景としては jQuery の読み込みに 30KB くらい使っていて、でも jQuery をそんなに大活用しているわけでもなくて。
じゃあいらんか、と。

zepto にすることも考えた。が、せっかくなのでまるっと消すことにした。
GitHub - madrobby/zepto: Zepto.js is a minimalist JavaScript library for modern browsers with a jQuery-compatible API


自分で書いていたやつから jQuery な記載を消していった。
$は document.querySelector とか document.querySelectorAll とかで。
XHR がちょっと面倒だなあ…とか思ったけど fetch API あるやん!で解決した、便利。

Fetch API - Web API | MDN

あとは Chrome の DevTool でコンソールで試しながら変数あるかなあとか見たりしながら書いてた。


画像の表示に使っていた lity という lightbox なライブラリが jQuery 依存していたので別のものに切り替える必要があった。

GitHub - jsor/lity: Lightweight accessible and responsive lightbox.

cdnjs を lightbox で探していたらよさそうなのがあった。
luminous という lightbox なライブラリで lity と容量もあまりかわらない(3KB くらい)っぽい。

GitHub - imgix/luminous: A simple lightweight no-dependencies JavaScript lightbox.

imgix 画像加工ができる CDN サービスをやっている会社が提供している lightbox なライブラリとのこと。

imgix • Real-time image processing and image CDN

余談にはなるが日本で同様のものだと ImageFlux が有名だろうか。むしろ画像 CDN でパラメータで扱うのはこれしかしらなかった。。
画像変換サービス ImageFlux|さくらインターネット


あと jQuery に依存していたわけではないが Chrome の DevTool から Performance タブで Load イベントまでの様子を測ってみると Highlight.js がそこそこに時間を使っていてなんとかしたいなあと。

GitHub - highlightjs/highlight.js: Javascript syntax highlighter

これまたいくつか調べてみると prism なるものが見つかった。
テーマを切り替えることもできるし、様々な言語のハイライトに対応しているし、プラグインで拡張できるし、でっかいハイライトするなら WebWorker を使っての asyncRender も有効に使えそうな感じがする。

GitHub - PrismJS/prism: Lightweight robust elegant syntax highlighting.

実際にいれてみると、言語検出機能がないので、特に言語を指定せずにざっくり使っていた部分についてハイライトが効かなかった。のでそれっぽいものを自分でざっくり書いた WordPress で使うので、投稿についたタグの情報とか、コードの中身とかからざっくり判断でわりかし十分。多分間違っていても、そんなに気にならない。


そのほか、処理順を入れ替えたり、遅いやつをもっと遅延させて影響なくしたり requestAnimationFrame を使ってみるなどした。
変更する前と比べて、表示されるまでがだいぶ早くなった、と思う。(主観)

Google App Script で Gmail の掃除をする

久しぶりに Google App Script を見たらものすごいアップデートされているような気がする。

こんな管理画面的なものあったっけ…。。
自分のプロジェクト - Apps Script

本題 Github からくる通知メールや、各種メルマガ、その他さまざまな通知系のメールが Gmail の受信箱の大半を圧迫しており、まともに見れなくなってしまった。
フィルタを設定したものの、すでに受信したメールを一括削除することが、どうにも Gmail 上からはうまく動いていないっぽい。

というわけで Google App Script を使って不要なメールをドカッと削除する。

こんな感じのお手軽な関数で十分。

function myFunction() {
  var query = 'label:xxx subject:yyy'; // ここに任意の検索クエリを書く
  while(true) {
    var threads = GmailApp.search(query, 0, 500);
    if (threads.length <= 0) {
      return
    }
    for (var i = 0; i < 5; i++) {
      GmailApp.moveThreadsToTrash(threads.slice(i*100, i*100 + 100));
    }
  }
}

API ドキュメントはここ。
Class GmailApp | Apps Script | Google Developers

初回だけ手動で実行し Gmail に関する権限を取得する必要がある。

あとは自動トリガーに設定 2 時間に 1 回実行くらいで。もっと早い頻度で動かすこともできるのだが、早すぎると Gmail の API で制限に引っかかってしまう。気長にやるのがよさそう。
しばらく放置したのちに見るといらないメールがすべて消え去ってすっきり。

htpasswdをちゃんと使う

なんだか htpasswd で長いパスワードを設定してもちゃんと機能していないっぽい…、いやいや Basic 認証だから短い文字列しか使えない、なんていう制約はない、のでは…?ということで調べた。結果、ドキュメントかコマンドのヘルプ表示に書いてあることがすべてだった。

まずは、おや??と思ったサーバが使っていたのが Apache 2.2 だったので、そちらのドキュメントを見てみる。

htpasswd - Manage user files for basic authentication - Apache HTTP Server Version 2.2

-m
Use MD5 encryption for passwords. This is the default (since version 2.2.18).

-d
Use crypt() encryption for passwords. This is not supported by the httpd server on Windows and Netware and TPF.
This algorithm limits the password length to 8 characters. This algorithm is insecure by today's standards. It used to be the default algorithm until version 2.2.17.

ち、ちしきもソフトウェアも更新されていない。。。
古い httpd を使っていたので、そのまま更新してパスワードファイルを作り直し。

後述するがデフォルトになっている MD5 を利用するのがいいっぽい。

$ sudo yum update httpd

$ htpasswd -inm foo-user

ついでに Apache 2.4 を使っている別サーバの様子も確認。

htpasswd - Manage user files for basic authentication - Apache HTTP Server Version 2.4

こちらは bcrypt が使えたり SHA が insecure だよといった情報も増えている。

-m
Use MD5 encryption for passwords. This is the default (since version 2.2.18).

-B
Use bcrypt encryption for passwords. This is currently considered to be very secure.

-C
This flag is only allowed in combination with -B (bcrypt encryption). It sets the computing time used for the bcrypt algorithm (higher is more secure but slower default: 5 valid: 4 to 17).

-d
Use crypt() encryption for passwords. This is not supported by the httpd server on Windows and Netware. This algorithm limits the password length to 8 characters. This algorithm is insecure by today's standards. It used to be the default algorithm until version 2.2.17.

-s
Use SHA encryption for passwords. Facilitates migration from/to Netscape servers using the LDAP Directory Interchange Format (ldif). This algorithm is insecure by today's standards.

なんで SHA が insecure なのかは下の Security Considerations トピックに書いてある。
SHA を指定するとパスワードに対してソルトが設定されず毎回同じ値になるのがよろしくないとのこと。

というわけでこちらの Apache 2.4 がいるサーバでは bcrypt を使う、ついでにコストパラメータもちょっと上げてみる。

$ htpasswd -nb -C 10 bar-user
...

実際に各種作って比べるとこんな感じ。
いままでのそれよりだいぶ雰囲気がちがう。。。

$ cat htpasswd_test.sh
#!/bin/sh

password=test-foo-bar

echo 'raw'
echo $password | htpasswd -inp test
echo 'crypt()'
echo $password | htpasswd -ind test
echo 'sha'
echo $password | htpasswd -ins test
echo 'md5'
echo $password | htpasswd -inm test
echo 'bcrypt()'
echo $password | htpasswd -inB test
echo 'bcrypt() with cost=10'
echo $password | htpasswd -inB -C 10 test


$ htpasswd_test.sh

raw
Warning: storing passwords as plain text might just not work on this platform.
test:test-foo-bar

crypt()
Warning: Password truncated to 8 characters by CRYPT algorithm.
test:19KcNn65a0Ovo

sha
test:{SHA}FsxBAWUFKrRlyJof3T+q9X6QfNE=

md5
test:$apr1$/nZjVA4i$5.tcV5puEwC6t0xQzuBfK1

bcrypt()
test:$2y$05$W4354fiJgesqn4/EXJhOsemadtHoX.PevbZA76fptomx09NAvbQTa

bcrypt() with cost=10
test:$2y$10$A6DDhPBzUOQA3aRui6acK.IaRpe0bqL9m5dcER4Gp0Bwk/SzEYhNa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15