もぐてっく

人は1つ歳を取る度、1ビットづつ大きくなれると信じてた。

Multiverse-coreで新しいワールドを作ってる途中にSpigotが落ちる

こんな感じでワールド生成を開始したところ、約1分でSpigotが落ちました。

>mv create 1-9 NORMAL
[05:17:20 INFO]: CONSOLE: Starting creation of world '1-9'...
・・・
[05:17:20 INFO]: Preparing start region for level 4 (Seed: 7967941679464971899)
[05:17:22 INFO]: Preparing spawn area for 1-9, 0%
・・・
[05:18:21 INFO]: Preparing spawn area for 1-9, 53%
[05:18:22 ERROR]: The server has stopped responding!
[05:18:22 ERROR]: Please report this to http://www.spigotmc.org/
[05:18:22 ERROR]: Be sure to include ALL relevant console errors and Minecraft crash reports

どうもワールド生成中はスレッドが固まったと判断されて、60秒後にタイムアウトしてたみたいです。
タイムアウト時限は設定ファイルにあるので、変更してしまいます。

config-version: 8
settings:
 ・・・
  timeout-time: 60 ← 300秒にしました。

これで無事にワールドが生成されました。

Chromeで見てるページのURLをmikutterから投稿できるようにしたよ

なにこれ?

古来、ブログとは、

狭義にはWorld Wide Web上のウェブページのURLとともに覚え書きや論評などを加えログ(記録)しているウェブサイトの一種である。「WebをLogする」という意味でWeblogウェブログ)と名付けられ、それが略されてBlog(ブログ)と呼ばれるようになった。(Wikipediaより)

であるからして、「マイクロブログ」と称されるTwitterのクライアントについてもWebブラウザとの密接な連携が不可欠なのである。

と、言うわけでChromeで見てるページのURLをmikutterから投稿できるようにしてみました。

インストール

GitHubからzipファイルをダウンロードして適当なディレクトリに展開して下さい。

GitHub - moguno/mikutter-webapi-hardpoint: Chromeとかと会話する用のWebAPIを提供する前提プラグイン。Chromeで今見てるページをmikutterのPostboxに入力するサンプル付き

※mikutterプラグインマネージャ"Packaged"で"moguno"を検索してインストールするのもおすすめですけどこれまだ動くんかな? ← ダメだったので直しました。

Chrome拡張のコンパイル

今回はChromeにボタンを追加するので、Chrome拡張のインストールを伴います。
大して手間じゃ無いのでソースだけ添付してユーザーさんにコンパイルしてもらうことにしました。
(バイナリの管理嫌い)

突然ですがここでニュースです(2016/3/5)

先日のChromeのアップデートから、野良拡張がインストール不能になりました。
セキュリティ上の都合だそうです。にゃあ。

仕方が無いので$5.00払って正式公開しました。

chrome.google.com

以下、せっかく頑張って書いたので残しておきます。
公開前のデバッグなどに有効な手順だと思います。

Chrome拡張ソースコードをどっかにコピーする。

アーカイブの中にあるchromeディレクトリをどこかにコピーしてください。
~/.mikutter以下だとChromeから見えなかったりするので。

chrome://extensionsを開いて、拡張機能タブを開く。

アドレスバーにchrome://extensionsと入力します。

f:id:moguno:20160221102100p:plain

こんな画面が出てくると思います。

f:id:moguno:20160221102353p:plain

デベロッパーモードを有効にする。

画面上部の「デベロッパーモード」を有効にしてください。

f:id:moguno:20160221102420p:plain

いくつかボタンが増えました。

f:id:moguno:20160221102500p:plain

拡張機能をパッケージ化する

増えたボタンから「拡張機能をパッケージ化...」ボタンを押下します。

f:id:moguno:20160221131729p:plain

ダイアログが出てくるので、先ほどのchromeディレクトリを指定して「拡張機能のパッケージ化」ボタンを押してください。

f:id:moguno:20160221102544p:plain

こんなメッセージが出ればOKです。

f:id:moguno:20160221102555p:plain

chromeディレクトリと同じ階層にchrome.crx、chrome.pem(今回使いません)ができています。

f:id:moguno:20160221132700p:plain

拡張のインストール

先ほどのchrome.pemをChrome拡張機能タブにドラッグアンドドロップします。
「ここにドロップすると、インストールされます」が表示されるエリアにポイっ!すると良いです。

f:id:moguno:20160221133029p:plain

やましいことは無いので、どうぞ「拡張機能を追加」ボタンを押してください。

f:id:moguno:20160221133139p:plain

無事インストールされて、みくったーちゃんボタンがツールバーに登録されたはずです。

f:id:moguno:20160221133242p:plain

使い方

これは!と思うページを見つけたら、みくったーちゃんボタンを押すだけです。

f:id:moguno:20160221133402p:plain

こんな感じでmikutterのポストボックスにタイトルとURLがコピーされます。
後は思う存分ふぁぼを稼いでください。

f:id:moguno:20160221133501p:plain

実は・・・、

Chromeとmikutterとの会話を実現するために、mikutterをWebサービス化すると言う技を今回考案しました。

mikutter-webapi-hardpointをインストールすると、mikutterにhttp://127.0.0.1:39080/testと言うエンドポイントが生えます。

Chromeのボタンを押すとhttp://127.0.0.1:39080/test?title=タイトル&url=URLをGETし、mikutterが受け取った情報をPostboxに挿入すると言う仕組みです。

このmikutterをWebサービス化する仕組みは他にも応用が効きそうなので、DSLを用意しました。

webapi DSL

Webサービスのエンドポイントを追加します。
req, resはそれぞれWEBrick::HTTPRequest、WEBrick::HTTPResponse オブジェクトとなっています。
ぶっちゃけWebrick::mount_proc()のラッパーなのでそっちを色々見てもらえれば。

今回のtestエンドポイントはこんな感じです。

webapi("test") { |req, res|
  message = ">#{req.query["title"].force_encoding("UTF-8")}\n#{req.query["url"].force_encoding("UTF-8")}\n"

  Plugin[:gtk].widgetof(Plugin::GUI::Postbox::cuscaded.values.first).post.buffer.text = message
}

Ubuntu15.10でterminologyを使う

ふと、mikutterをBot的に使うために必要最低限のパッケージで構成したコンテナを作りたいなと思いました。

ベースは Ubuntu Server15.10(大好き)。

vnc経由で軽量なウインドウマネージャと適当なターミナルを使えるようにして、後はmikutterのインストールかなと。

ウインドウマネージャはFluxbox。ターミナルはUbuntu15.04からパッケージ化された未来的オシャレ端末terminologyにしました。

そこでちょびっとハマった時のメモです。

terminologyがFluxboxのメニューに出てこない!

次のコマンドでFluxboxとterminologyをインストールしました。

apt-get install fluxbox terminology

しかし、Fluxboxのメニューにterminologyが追加されませんでした。

試しに別のターミナルxterm、gnome-terminalを入れるとメニュー登録される。
逆にデスクトップ環境XFCE4を導入するとterminologyがメニューにちゃんといる。

謎。

UbuntuにおけるGUIメニューシステム

調べてみると、Ubuntuにはアプリケーションをデスクトップ環境のメニューに追加する仕組みが大きく2系統あることがわかりました。

freedesktop.org

デスクトップ環境を設計する上で、守ったほうがいいお約束をfreedesktop.orgと言う団体がまとめています。
このお約束に沿っていれば、例えばGTK製アプリとQtアプリで連携が取れるようになったり、各種設定ファイルがGnomeKDEで共有出来たりします。

ランチャーのメニュー項目についてもfreedesktop.orgに規定があり、アプリケーションはメニュー項目を定義した*.desktopファイルを用意することで、freedesktop準拠のデスクトップ環境のメニューにアプリケーションを登録できます。

先ほどのXFCE4も freedesktop.org準拠のデスクトップ環境です。

Debian Menu System

とは言え、昔ながらのデスクトップ環境(とかランチャー付きのウインドウマネージャ)はfreedesktop.orgに準拠していないものも多いです。

これらのデスクトップ環境では、ユーザ自身がメニュー定義を編集してアプリケーションを登録する必要があります。

それはさすがに面倒だよねということで、Debian系のディストリビューションにはDebian Menu Systemと言う仕組みがあります。

これはfreedesktop.orgのdesktopファイルと同等に、アプリケーション提供側がメニューファイルを用意します。
そしてupdate-menuコマンドでメニューファイルを元に各種デスクトップ環境用のメニュー定義が生成できるというものです。

古き良きBlackbokの流れを組むFluxboxはこっちのグループです。

つまり

今回のterminologyのパッケージにはfreedesktop.orgのterminology.desktopは収録されていたけれど、Debian Menu Systemのメニューファイルが入っていなかったのが原因です。

対策

Debian Menu Systemのメニューファイルを書きました。

/usr/share/menu/terminology

?package(terminology): \
        needs="X11" \
        section="Applications/Terminal Emulators" \
        title="Terminology" \
        command="/usr/bin/terminology" \

めっちゃかっこいい

無事、Fluxboxでterminologyが起動できました。
カーソルが怪しい青白の光を放っていたり、ベルの代わりに赤色灯が回ったりします。
Fluxboxのテーマともあつらえたように合ってますね。かっこいい。

f:id:moguno:20160214222225p:plain

Yet Another 実行中のmikutterにコードを流し込むやつを作ったよ

何これ?

明けましておめでとうございます。

これは「あー正月ってテレビもつまんないしマジすることないよねー」カレンダー (なにそれ?)1日目の記事です。(1年ぶり2記事目)


今回は「起動中のmikutterに外部から任意のコードを流し込むプラグイン&コマンド」を作ったのでその紹介をば。

これ、コンセプトは@toshi_aさんのmikutter-modeと同じで、プラグインを改造するたびにmikutterをいちいち再起動したくないよねと言うところです。

じゃあなんで再発明してんだよ溜まってるIssue処理しろよ最近お前の腹の出方ヤバイだろ痩せろよ?のかと言うと、

もぐのがMacDBusを動かせなかった

mikutter-modeがプロセス間通信に使っているLinux御用達フレームワークDBusが、もぐののMacではなんかエラーになるんですよね。
なので、今回は古のRuby標準ライブラリであるdrubyでプロセス間通信を実現しました。

もぐのがvim

mikutter-modeはEmacsLISPで実装されてる所がいっぱいあって、vimで使うにあたってよくわかんなかったので。
せっかくなので、エディタに依存しない仕組みにすることにしました。

(ちなみにmikutter-modeのvim移植は2GMonさんによる実装があったりします。)
github.com

インストール

GitHubからzipファイルをダウンロードして、プラグインディレクトリにmikutter-code-injectorと言うディレクトリ名で展開して下さい。

moguno/mikutter-code-injector · GitHub

※mikutterプラグインマネージャ"Packaged"で"moguno"を検索してインストールするのもおすすめです。

使い方

普通にmikutterを起動する。

ごく普通にmikutterを起動してください。

見た目には変化はありませんが、netstat -aするとこんな行が増えてたりします。

tcp6       0      0  localhost.39311        *.*                    LISTEN

コードを送り込む

~/.mikutter/plugin/mikutter-code-injector/にmktrと言うコマンドがあります。
そのmktrの標準入力にRubyコードを流し込んでみてください。
起動中のmikutterでコードが実行されます。

実行できるコードに制限はなく、mikutterのフル機能を操作できます。

仕組み的にはmikutterのトップレベルbindingをdrubyで公開しておいて、mktr側でそれを取得。
んで、取得したbindingのevalを呼ぶとmikutter側でコードが実行されると言う寸法です。

それでは試しに、コマンドラインからつぶやいてみましょう。

echo 'Service.primary.post(:message => "みくっ")' | ./mktr

f:id:moguno:20151121103409p:plain

ちゃんとつぶやけましたね。
速攻で複数人からふぁぼられてるのは弊TLの仕様です。

vimから使ってみる。

もぐのはvimスクリプトが書けない人なので、mikutter-modeの様なvimとの統合機能は作り込んでません。
て言うか、vimではこんな風に現在のバッファをmktrの標準入力に流し込むことが出来るので、これでいっかーな感じになってます。

:w !./mktr

これで本格的なプラグイン開発にも対応できますね。

f:id:moguno:20151121111310p:plain

現状の制限として、mikutter起動時のイベントon_bootはコード流し込み時には実行されません。
この辺はなにか工夫できたらいいなと思ってます。

IPアドレス固定なしで家庭内サーバを公開できるデーモンを作ったよ

何これ

自宅サーバを公開したい!
→ルータのポートマッピングを設定しないといけない!
→サーバのIPアドレスを固定しないといけない!
→IPアドレスの管理めんどい!DHCPのまま公開したい!

と言う、おおよそサーバ管理者に向かないものぐさ思考をUPnPを使って解決することにしました。

UPnPとは、ネットワーク内でのサービス提供者の発見、サービス内容の公開、リモートプロシージャコールを行う仕組みです。10年以上前からあるふっるい技術ですね。

当時はWebサービスマッシュアップ技術の本命だったのですが、結局、サービス探索なんてあんま使わないじゃん。RPCはシンプルなRESTでいいじゃん。となって流行る前に忘れられた感があります。

そんなわけで、UPnPを使ってて広く実用化されているのはルータのポート開放とDLNA位と言うのが現状です。

UPnPでのポート開放は通常はメッセンジャーなどのアプリケーションが自分用のポートを開けるために使用しますが、今回、これを使って任意のポートを制御するデーモンを作ってみました。

こだわったところ

mDNSとの親和性

mDNS(avahi、bonjour)を使えば、ローカルなDNSサーバがなくとも「ホスト名.local」と言う名前で端末にアクセスできるようになります。これを使えばDHCPでころころIPアドレスが変わる端末にも、ホスト名でアクセスできるということです。素晴らしい。

今回作ったデーモンはこの素晴らしいmDNSとの連携を意識した設計になっています。

デーモンは定期的にホスト名を正引きして、IPアドレスが変わっていた場合はルータにポートマッピングの再登録を行います。
この動きにより、ポート転送先サーバとして「ホスト名.local」を指定していれば、たとえサーバのリブートでDHCPから払い出されるIPアドレスが変わったとしても、ポート転送を追従させることができます。

これによって当初の「DHCP環境でもサーバ公開したい!」が達成できるというわけです。

集中管理にも分散管理にも使えます

このデーモンはデーモンが動作しているサーバへのポート転送の他に、別のサーバへのポート転送も設定することができます。

なので、管理サーバ立ててネットワーク内のすべてサーバのポートマッピングを集中管理することもできますし、それぞれのサーバでデーモンを動かして各サーバに自分が使うポートの管理を任せることもできます。

ダウンロード

github.com

インストール

Ruby開発キットをインストールする

apt-get install ruby ruby-dev build-essential

mupnp gemをインストールする

gem install mupnp

設定ファイルを編集して/etc/にコピーする

cp -p pnp_portmapd.conf.sample /etc/pnp_portmapd.conf

デーモンを起動する。

./pnp_portmapd

設定ファイル

YAML記法になってます。
JSONと違ってコメントが書き放題なのが良いですね。

# 設定
Settings:
  # ポートマッピング更新周期(秒)
  Period: 5

# ポートマッピング定義
PortMapping:
  # 転送先ホスト名
  akari.local:
   - ExtPort: 82   # 外部ポート
     IntPort: 81   # 転送先ポート
     Protocol: TCP # プロトコル(TCP/UDP)
   - ExtPort: 100
     IntPort: 101
     Protocol: UDP

  alicia.local:
   - ExtPort: 101
     IntPort: 102
     Protocol: UDP

この設定を適用すると、うちのルータではこんな感じになります。
akari.localが192.168.11.17、alicia.localが192.168.11.11です。
両者ともIPアドレスDHCPから払い出されたものであり、IPアドレス固定なしでサーバが公開できています。

f:id:moguno:20151126120957p:plain

ログファイル

/var/log/pnp_portmapd.logです。
ルータに設定を行うたびにINFOメッセージを出しているので、眺めてると楽しいです。

ライセンス

License: 3 clauses BSDとやらにします。

Mac OS Xでmikutterの通知とサウンドが使えるようになるプラグイン

何これ?

OS Xでmikutterの通知ポップアップとサウンドを使えるようにします。
RubyからMacの通知を出すgem(terminal-notifier)を見つけた記念です。

インストール

GitHubからzipファイルをダウンロードして適当なディレクトリに展開して下さい。

moguno/mikutter-notifier-osx · GitHub

※mikutterプラグインマネージャ"Packaged"で"moguno"を検索してインストールするのもおすすめです。

もしかするとmikutterディレクトリでbundle installしないといけないかもしれません。

使い方

他のOS同様に、設定画面の「通知」メニューから有効にしたい通知とサウンドファイルを設定してください。

f:id:moguno:20151018221201p:plain

加えて、「サウンド」メニューから「Mac OS X」を選択してください。

f:id:moguno:20151018221213p:plain

こんな感じで通知が出て来ればOKです。

f:id:moguno:20151018221535p:plain

タイトルのターミナルっぽいアイコンはOS Xの仕様でterminal-notifierのアイコンから変更できないそうです。残念。

Proxmox VEのLXCコンテナにavahi-daemonを入れようとしてハマった話

Proxmox VEが4.0にバージョンアップしてLXCベースのコンテナが使えるようになったので、コンテナをぽこぽこ作っててハマったメモです。

コンテナのテンプレートはみんな大好きUbuntu Serverの15.04(ubuntu-15.04-standard_15.04-1.amd64.tar.gz)です。

2コンテナ目からavahi-daemonのインストールがコケる

IPアドレスお手軽解決のavahi-daemonを各コンテナにインストールしていたところ、2つ目のコンテナでapt-getが失敗する怪現象が発生しました。

root@FileServer:~# apt-get install avahi-daemon
・・・
Setting up avahi-daemon (0.6.31-4ubuntu4) ...
update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults
Job for avahi-daemon.service failed. See "systemctl status avahi-daemon.service" and "journalctl -xe" for details.
invoke-rc.d: initscript avahi-daemon, action "start" failed.
dpkg: error processing package avahi-daemon (--configure):
 subprocess installed post-installation script returned error exit status 1
dpkg: dependency problems prevent configuration of libnss-mdns:amd64:
 libnss-mdns:amd64 depends on avahi-daemon (>= 0.6.16-1); however:
  Package avahi-daemon is not configured yet.

dpkg: error processing package libnss-mdns:amd64 (--configure):
 dependency problems - leaving unconfigured
Processing triggers for dbus (1.8.12-1ubuntu5) ...
Processing triggers for ureadahead (0.100.0-19) ...
Processing triggers for systemd (219-7ubuntu6) ...
Errors were encountered while processing:
 avahi-daemon
 libnss-mdns:amd64
E: Sub-process /usr/bin/dpkg returned an error code (1)

インストール後の自動起動がコケた結果、パッケージのインストールに失敗しているようです。
ファイルのインストール自体は済んでるみたいなので、試しに手動で起動してみます。

root@FileServer:~# avahi-daemon

Found user 'avahi' (UID 109) and group 'avahi' (GID 119).
Successfully dropped root privileges.
chroot.c: fork() failed: Resource temporarily unavailable
failed to start chroot() helper daemon.

なんでかふわっとした理由でfork()が失敗してますね。

ここまでの情報を使ってググると、ズバリの英語ページが見つかりました。

Avahi, setrlimit NPROC and lxc | Playing on the frontier

どうやら、avahi-daemonの中で作れるプロセス数の条件が制限されている模様です。

その制限がなぜかコンテナ間で共有されていて、複数コンテナの合計でこの制限に引っかかるっぽいですね。実際、1つめのコンテナを落とすと起動に成功しました。

# Linuxのネームスペースのサポートが未だ完璧でないんでしょうか。
# 応用したら別のコンテナをDoS出来そうでヤバいすね。

対策

avahi-daemonのインストール失敗後、/etc/avahi/avahi-daemon.confのプロセス数制限を無効にします。

     61 [rlimits]
     62 #rlimit-as=
     63 rlimit-core=0
     64 rlimit-data=4194304
     65 rlimit-fsize=0
     66 rlimit-nofile=768
     67 rlimit-stack=4194304
     68 #rlimit-nproc=3   ←コメントアウト。

avahi-daemon.conf編集後、再度apt-get install avahi-daemonしてインストールを成功させればOKです。
既にインストール済みのコンテナのavahi-daemon.confも同様に修正しておきましょう。