TI9観戦/ナウいScala開発環境/口内炎の予感

日曜なので意識的に在宅していた。

TI9観戦

Dota2のTI9がアツい。FnaticがVPに勝つ番狂わせが起きるかと思いきや起きなかった。Dota2の試合時間はだいたい30分から40分くらいだ。ヒーローは大まかにスキルで戦うヒーローと通常攻撃で戦うヒーローに分類される。前者の方が早熟だが、金を稼いでアイテムが揃うにつれて後者の方が強くなる(基本的に時間が経てば金は貯まる)。金を横軸・強さを縦軸に取ると当然右上がりのグラフになるが、グラフの形はヒーローごとに様々だ。たとえば特定のアイテムを持つことで格段に強くなるということがある。プロレベルの試合では味方のヒーローに重要アイテムが入り、かつ敵のヒーローがまだ重要アイテムを手に入れていない絶妙なタイミングで戦いを仕掛けに行くということもある。そこで勝てば金が手に入り、また有利になる。

しかしこうして有利を拡大していっても決めきれなければ大器晩成型のヒーローによって逆転されることもある。たとえばMedusaは通常攻撃が4体攻撃になるスキルを持つ。単純に考えて通常攻撃を強化するアイテムのもたらす恩恵は4倍だ。だから強力なアイテムを揃える前に勝ちきらなければならない。

ナウいScala開発環境

以前vscodeでScala開発を試みたときはまともに使える拡張機能がなく補完が効かなかったのだが、今はMetalsを入れるだけでいい。補完があるとプログラミングは楽だ。ミスに気づくのは早ければ早いほどいい。

今はActivityPubの実装に挑戦している。仕様が固まっているものなのでTDDしている。ActivityPubではObjectはTypeという属性を持つことを定めているが、これは予約語なので`type`と表現する必要がありややこしい。ScalaTestの機能と思っていたmatcherが実はPlayの機能だったりして難しい。フレームワーク周りの知識がない。

素人丸出しのアレだが、package hogeはそのファイルの内容をhogeに所属させるために使うことを知った。つまり他のファイルからhoge.fugaという呼び出しができるようになる。ファイルでもオブジェクトでもクラスでもなく「パッケージに所属させる」という操作の感覚が新しかった。

今日はもうひとつ、droneのデプロイもした。droneはCIの一種でgitリポジトリにpushしたときに.drone.ymlを読んで自動でテストやビルドを行う。1回毎にdockerコンテナを作って捨てることでクリーンな環境でテストできるのがdroneの特徴だが、1回毎にsbtの初期化を行うせいで(貧弱なサーバーでは)1時間以上かかってしまい、タイムアウトしてしまった。

口内炎の予感

口内の傷が嫌な感じに痛み出していて口内炎になりそうで嫌だ。口内炎は食事が楽しめないのが辛い。ただ、火曜に右上の親知らずを抜くのでどうせ1週間くらいはろくな食事ができない。

houseTemperatureプロジェクトの大詰め

自分の家の天気(気温・湿度・気圧)をRaspberry Piから5分ごとにサーバに送り、それを使っていろいろ遊ぶプロジェクト(github)もそろそろ大詰めだ。使用技術はScala + Play Framework。開発環境にもデプロイにもDockerを利用している。サーバはこのブログと同じさくらのVPSで、nginx-proxyによってサブドメインgyokuroへのアクセスを振り分けている。

ドキュメント

ベースURLはhttps://gyokuro.chao.tokyoで、現状公開しているリソースは以下のとおりだ。

例:
{"status":"200","data":{"time":"00:25:00","temperature":27.7,"humidity":76.7,"pressure":1001.6}}
例:
{"status":"200","data":[{"time":"00:00:00","temperature":27.6,"humidity":76.8,"pressure":1001.7},{"time":"00:05:00","temperature":27.6,"humidity":77,"pressure":1002},{"time":"00:10:00","temperature":27.8,"humidity":76.3,"pressure":1001.9},{"time":"00:20:00","temperature":27.8,"humidity":76.5,"pressure":1001.7},{"time":"00:25:00","temperature":27.7,"humidity":76.7,"pressure":1001.6}]}

iframe化の苦労

WordPressは自由なhtmlをウィジェットに追加できるので、iframeを使って/temperature/nowを常に表示しようと思った。しかしPlay FrameworkはデフォルトでX-Frame-Options: denyが設定されているのでiframeに表示されない。これはクリックジャッキング防止のためだ。クリックジャッキングというのは僕のサイトを透明なiframeにして他のサイトの上に重ねて表示させることで、僕のサイトの任意の箇所を不正にクリックさせる手口だ。

MDNにしたがってX-Frame-Options: allow-from https://example.com/を登録しようと思ったのだが、なんとChromeは対応していない。ブチギレてる。対応してないということで無視されているのでとりあえず動いてはいる。ユーザーがクリックできる箇所はないのでたぶんオッケー(ホンマか?)。

iframeが表示されるようになったはいいが、黒背景に黒文字で表示されていて読めなかった。WordPress側からiframe内のstyleを操作するのは無理っぽかったので上記の通りクエリパラメータで白文字化できるようにして対応した。

頑張って作ったので適当にAPIで遊んでみてください。グラフ化するやつ作ってほしい。

ちなみに現在の状況は27.8 ℃、76.1 %、1001.4 hPa。肌がべたつきやや不快だ。今夜から明朝にかけてすごい降るらしい。通勤はできるかな?

自己管理とサーバ管理

昨日急に健康意識が高まったのでスマホにGoogle Fitを入れた。万歩計のすごいやつで、歩行以外の運動も記録できる。僕は歩くのが早いので通常歩行が強めの運動に分類され、10ポイントが目標のところ43ポイントだった。歩数は6369歩で消費カロリーは1454kcalだった。

早歩きでポイントが貯まると聞くと無意味に早歩きして帰ったし、普段帰りはエレベーターで4階まで上がるが今日は階段で上がった。数値化して可視化することには強い力がある。

気に入らないのはGoogleのアプリだということだ。Googleに情報が集中する現状は気に入らないが、彼らが最も優れたIT企業であることは間違いない。最低限の機能の万歩計くらいなら自分でも作れるだろう。でも運動の激しさを判定したり位置情報と連携したりといった高度な機能を高精度で作れる気はしない。

ブログを書こうと思って管理ページにアクセスしたら異様に重くなっていた。サーバにssh接続してvmstatを実行するとディスクアクセスが多い。さらにtop -b -d 1 -n 1を実行するとCPUを占拠しているのはjavaだった。理由のアタリはついていて、昨日playのアプリケーションをDockerでデプロイするときに起動コマンドをsbt ~runにしてしまっていた。~をつけるとファイルが変更されるたびに自動で再コンパイルを行う。外すと負荷は収まった。

ラーメンを食べられなかった

※この記事は『金麦』を飲んで書かれた。

今日は仕事がしんどかったので帰りに不健康なラーメン(僕の中ではこの言葉は家系ラーメンを指す。なぜなら二郎系は野菜たっぷりで健康的だから)を食べて帰ろうと思った。同僚が「この辺にぃに美味いラーメン屋、あるらしいっすよ」と言っていたのでそこに行った。しかし残念なことに夜はライスが有料だった。

僕は家系ラーメンではライスは2杯〜3杯食べる。にんにく系の味と豆板醤系の味をそれぞれ楽しみたいからだ。

結局ラーメンは食べずに帰宅して焼きそばを食べた。最近は粉ソースではなくさらなる高級感を求めて液体ソースを使っているが、これも特段美味いということはない。そもそも相当な量を入れないと味がしない。そしてコストパフォーマンスが低い。

温度記録サーバはとりあえず公開できた。僕の自宅の気温・湿度・気圧を記録し続けるだけのサービスだ。

https://gyokuro.chao.tokyo/temperature

ちなみに過去ログには以下のような形式でアクセスできる

https://gyokuro.chao.tokyo/temperature/1994/05/17

サーバはScala + Play FrameworkをDockerでデプロイ、センサはRaspberry Pi + BME280でPythonのRequestsライブラリを使ってサーバにログを送信している。計測環境は鉄筋コンクリートでエアコンや換気扇で温度管理していて、Homo sapiensが1匹住んでブログを書いたりしている。

仕事が始まり始めた

※この記事は『金麦』を飲んで書かれた。

配属されたのでぼちぼち仕事っぽい仕事をしている。ただしまだ軽い仕事を回してもらって手順を覚えている段階なので「仕事を始めた」と言えるほどのことでもない。一日中パソコンを触ってお給料を発生させる気分は最高だ。

帰宅してScalaで書いている温度管理サーバの作業を進めた。ScalaはJavaの上に作ることで構造が汚くなっている部分もあるが、Javaの財産を活用できる恩恵は大きい。

本格稼働ではないがサーバに載せた。載せたはいいがディレクトリトラバーサル(←このまえ習った)食らいそうなAPI設計なので安全が確認できるまでURLは秘密です。ひさびさにnginx_proxyの設定を思い出す必要があった。地味にdocker-composeは使ったことがあってもただのdocker runは全然したことがなかった。とは言っても記法が違うだけでやれることは似たようなものだ。環境変数を指定したり、ポートを開けたり、ボリュームをマウントしたり。

こんなコマンドを書いたわけだが-eを連打するくらいなら当然.envファイルを使うべきだ。というか自分でDockerfileを書いてイメージを作るべきかもしれない。

梅雨だ。通勤ルートに徒歩の部分が多いので憂鬱だ。傘を差していても靴は濡れるのでいっそのこと長靴で通勤して会社で履き替えようか。なんて考えているうちに梅雨が明けてしまいそうだ。水筒だって買ったはいいが配属されたら近くに給茶機があるので必要なくなってしまった。トイレに行って帰りにお茶を汲んでくると、自分が単なる濾紙になったような気分になる。人間は情報を取り入れて適切に運動するだけの機械なので似たようなものだが。ステートフルかどうかは議論の余地がある。

Dockerコンテナ内で作ったファイルの所有者はrootになる

※この記事は『プライムリッチ』を飲んで書かれた。

『プライムリッチ』はアルコールが6%で重い。しばらく昏倒していて起きて作業している。

室温記録システムのサーバをScala+Play Frameworkで作っている。サーバ環境のもろもろの事情と技術的興味でDockerで環境構築をしたいが知見が少ない。参考にしているのはこれだ。

一点ハマりポイントを発見したので共有する。『プロジェクトの初期化』の節の内容を実行するとホスト側にプロジェクトが生成されるが、これらのファイルは所有者がrootになっているのでchown -Rしないと編集できない。永続的に解決したいのなら参考はこのあたり

てかこれ当該記事のコメント欄に書くべきだな…Qiitaアカウント作るか。Qiitaアカウントを持っていないのは必要になったことがないからだ。自分で発信プラットフォームを持つことには価値があると思っているけど、Qiitaが潰れる可能性と僕がさくらインターネットに972円を払い忘れる確率だとどっちが高いかな。後者だね普通に。

『らーめん 谷瀬家』でにんにくを補給した/Dockerなんもわからん

『らーめん 谷瀬家』でにんにくを補給した

健康に悪いラーメンが食べたくなったので社内チャットで「健康に悪いラーメンが食べたい」と発言したところ、上司から『らーめん 谷瀬家』を勧められたので同僚と4人で行ってきた(ここで急に日本語入力ができなくなり、しばらく手間取った。たぶん変なショートカットキーを偶然押した)。

家系ラーメンとしてはオーソドックスな構成で、油がいい感じ(?)でスープをつい飲んでしまう。家系と言えば卓上調味料で自分だけのご飯の食べ方を開発するのが楽しみだが、谷瀬屋には一味唐辛子の醤油漬けが置いてあり、パワフルな辛さが楽しめた。これまで行ったことのある家系ラーメンの中で一番好きだった。

以前住んでいた家は近くに家系ラーメンがあってよく行ったが、今の家に来てからは一度しか行っていなかった。俺にはにんにくが足りてなかった。にんにくをドバドバ入れながらご飯を2.5杯食べて大満足だった。

Dockerなんもわからん

Docker-Composeに頼りすぎてDockerfileの書き方を全然知らない。作成中の室温記録アプリのバックエンドをDocker上にPlay Frameworkで作ろうと思っているのだが(Dockerじゃないとサーバですでに動いている他のプログラムとの競合が面倒)、都合のいいDockerイメージが存在せず知見も少ないので手探り状態だ。コンテナ内でサンプルサーバを起動してもすぐに停止してしまう。

Mastodon諦めました/Spotify諦めました

今日はコンピュータに嫌われた一日だった。悲しい。

Mastodon

再びマストドン立てようと思ったんだがメールが送れないのと他インスタンスとの通信ができないトラブルを解決できず諦めた。どちらも初めて出くわした。

前者は名前解決なんちゃらのエラー、後者はどうやらSSLと関係があるようだったが僕の知識では理解できなかった。そもそもMastodonは恐ろしく複雑だ。使いやすくする努力はされているが少しでも不具合が起きるとそれを解決するためにはとんでもない知識と労力が必要になる。

Spotify

Spotifyでローカルの音楽ファイルを再生したかったのだが、mp3にしか対応していなかった。そこで急遽音楽フォルダ内を全部掘ってmp3じゃないファイルをmp3に変えるスクリプトを書いた。

しかしそうして生成したファイルをSpotifyで再生しようとすると、再生ボタンを押した瞬間にSpotifyアプリが終了する。ターミナルからアプリを開いているとログが残るが、終了時に表示されるのはこれだ。

[0228/053947.271857:ERROR:input_method_base.cc(146)] Not implemented reached in virtual ui::InputMethodKeyboardController *ui::InputMethodBase::GetInputMethodKeyboardController()Using InputMethodKeyboardControllerStub
Segmentation fault (コアダンプ)

うーん。軽く調べてみるとChromiumのバグの疑いが強く、2018年11月辺りに報告が頻発している。しかしローカルの曲を再生するときだけこうなるのでSpotify側にも問題がありそうだ。

スプラップアンドビルド

※この記事は『極搾り ピーチ』を飲んで書かれた。

マストドンにelasticsearchをつけようと思ったらなんか壊れてしまったので作り直した。

なんか壊れてしまったというのは、マウント関連だ。リバースプロキシであるnginx-proxyは設定ファイルを外部から読み込むために、ホストの設定ファイル(./my_custom_proxy_settings.conf)をマウントしている。この状態で更にvolumes_fromでmastodon-nginxからnginx-proxyをマウントするとなんだかよくわからないがマウント関連っぽいエラーが出る。read onlyとかなんとか書いてあった。

この2重マウントは僕もわけがわからずやっているが、そんなことだからエラーが出るのは当然だ。面倒なので一回全部消してマストドンを立て直した。前回のデプロイから1週間ちょっとしか経っていないが、github上のデプロイガイドが書き換わっていて驚いた。mastodonの進化はまことに速い。

新しいdocker-compose.ymlはこうだ。今回は自分で改造することも視野に入れ、自前でビルドすることにした。なおmastodonのバージョンはv2.5.0rc1だ。

version: '3'
services:

  mstdn-nginx:
    image: nginx:1.11.10-alpine
    expose:
      - "9090"
    restart: always
    tty: false
    env_file: .env.production
    links:
      - web
      - streaming
    volumes:
      - ./setting/nginx/conf.d:/etc/nginx/conf.d:ro
      - ./setting/nginx/conf:/etc/nginx/conf/:ro
      - /var/www/certs:/etc/nginx/certs:ro
    networks:
      - common_link
      - back-mastodon
  db:
    restart: always
    image: postgres:9.6-alpine
    networks:
      - back-mastodon
### Uncomment to enable DB persistance
    volumes:
      - ./postgres:/var/lib/postgresql/data

  redis:
    restart: always
    image: redis:4.0-alpine
    networks:
      - back-mastodon
### Uncomment to enable REDIS persistance
    volumes:
      - ./redis:/data

  es:
    restart: always
    image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.1.3
    environment:
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    networks:
      - back-mastodon
### Uncomment to enable ES persistance
    volumes:
      - ./elasticsearch:/usr/share/elasticsearch/data

  web:
    build: .
    image: tootsuite/mastodon
    restart: always
    env_file: .env.production
    command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000 -b '0.0.0.0'"
    networks:
      - back-mastodon
    ports:
      - "127.0.0.1:3000:3000"
    depends_on:
      - db
      - redis
#      - es
    volumes:
      - ./public/assets:/mastodon/public/assets
      - ./public/packs:/mastodon/public/packs
      - ./public/system:/mastodon/public/system

  streaming:
    build: .
    image: tootsuite/mastodon
    restart: always
    env_file: .env.production
    command: yarn start
    networks:
      - back-mastodon
    ports:
      - "127.0.0.1:4000:4000"
    depends_on:
      - db
      - redis

  sidekiq:
    build: .
    image: tootsuite/mastodon
    restart: always
    env_file: .env.production
    command: bundle exec sidekiq -q default -q mailers -q pull -q push
    depends_on:
      - db
      - redis
    networks:
      - back-mastodon
    volumes:
      - ./public/packs:/mastodon/public/packs
      - ./public/system:/mastodon/public/system
## Uncomment to enable federation with tor instances along with adding the following ENV variables
## http_proxy=http://privoxy:8118
## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
#  tor:
#    build: https://github.com/usbsnowcrash/docker-tor.git
#    networks:
#      - common_link
#      - back-mastodon
#
#  privoxy:
#    build: https://github.com/usbsnowcrash/docker-privoxy.git
#    command: /opt/sbin/privoxy --no-daemon --user privoxy.privoxy /opt/config
#    volumes:
#      - ./priv-config:/opt/config
#    networks:
#      - common_link
#      - back-mastodon

networks:
  common_link:
    external: true
  back-mastodon:
    external: true

注目してほしいのはmstdn-nginxのvolumesでホストマシンの/var/www/certsをマウントしていることだ。nginx-proxyでもホストマシンの同じディレクトリをマウントしている。2重マウントを解消し同じディレクトリをマウントするようにした。

elasticsearchはデフォルトで日本語対応してません。日本語対応プラグインを入れるのはちょっとしんどそうなのでまた今度やります。

ぶっ壊してまたイチから作ってというのを繰り返せるのは楽しい。無限にやりたい。