まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2020/06

Google Fit は Google のヘルスケア関連プラットフォームと、その SDK を提供しています:
https://developers.google.com/fit/

2020062600


Google Fit SDK は Android 標準アプリである Google Fit を操作するものです。簡単に言えば「Android の歩数カウント情報を取得する」ための SDK といえます。

この SDK の1つがブラウザ用の JavaScript で提供されており、ウェブアプリケーションに組み込んで使うことが可能です。データを取得するまでを実際に作ってみたので、その準備手順を含めてまとめてみました。


【Google APIs Console へのプロジェクト登録】
この Google Fit SDK を使う上で最初に必要な作業は Google APIs Console へプロジェクトを登録して Client ID を取得することです(SDK は Client ID を指定して動かすことになります)。
https://console.developers.google.com/flows/enableapi?apiid=fitness&pli=1

Fitness API を使うことになるアプリケーションプロジェクトとして、既存のプロジェクトを流用するか新たにプロジェクトを作成します。そして「使用する API」は「Fitness API」を選択し、「使用する場所」は「ウェブサーバー」を選択、更に「アクセスするデータの種類」は「ユーザーデータ」を選択します。最後に「必要な認証情報」をクリックして、クライアント ID を取得します:
2020062601


次の画面で OAuth 認証用のドメイン登録をします。「承認済みの JavaScript 生成元」と「承認済みのリダイレクト URI」に以下のアプリを動かす URI を指定します。ローカルで動作確認する場合であれば両方に "http://localhost:8080" を追加して保存します※:
2020062602

※以下で紹介するサンプルを https://localhost:8080/ という URL にアクセスして参照する場合の設定です。異なるホスト名やポート番号を使う場合は適宜変更してください。

これで Google APIs Console 側の準備は完了です。



【サンプルアプリケーションで動作確認】
動作確認用の Node.js 向けサンプルアプリケーションを以下に公開しておきました。Node.js がインストール済みの環境であれば実際に動かして動作を確認することが可能です:
https://github.com/dotnsf/google_fit


zip をダウンロードして展開するか、git clone して、自分の PC 内にプロジェクトファイルを展開します。実質的に public/index.html ファイルを 8080 番ポートで公開するだけの Node.js アプリケーションです。

実際に動作させる前に、public/index.html ファイルをテキストエディタで開き、8行目の client_id 変数の文字列値(初期値は 'your_client_id' )を上記で取得したクライアント ID の文字列値に書き換えて保存します:
2020062609


これでサンプルアプリケーションを動作させる準備ができました。以下のコマンドを実行してアプリケーションを稼働状態にします:
$ cd google_fit

$ npm install

$ node app


稼働状態になったアプリケーションは 8080 番ポートでリクエストを待ち受けています。ウェブブラウザで http://localhost:8080/ にアクセスしてみます。正しく動作していると最初に OAuth 認証が実行されるので、Android スマホで利用しているものと同じ Google アカウントでログインします:
2020062604


Google アカウントを選択してログインし、正しく処理が実行されると(このコードでは)2019/03/01 以降の歩数記録を取得します。何種類かの dataSource ごとの記録が表示されるはずです:
2020062608


どれか1つの dataSource をクリックすると、その dataSource に関して更に詳しく日時やその時の歩数が表示されます:
2020062609


↑自分は Android をメインスマホにしていないため、歩数が少ない・・・



実際に使っているコードは OAuth 認証のための authorize 関数と、そのコールバック先で実行している dataSource 一覧のフェッチ、そして各 dataSource ごとの歩数カウントのためのデータセットのフェッチです。JavaScript 自体はかなりシンプルになっていると感じました。



(参考)
https://qiita.com/feb19/items/383848119ba1bdfe5110


人気のテキストエディタである Visual Studio Code(以下 "VSCode")の機能を独自に拡張するプラグインの開発に挑戦してみました。以下で紹介するプラグインの開発は主にこのページにかかれている内容を参照し、参考にさせていただきました。ありがとうございます:
Visual Studio Codeの拡張機能を一通り触って自分用に公開するまで


作った拡張機能は MOTD(Manhole of this day) といいます:
https://marketplace.visualstudio.com/items?itemName=dotnsf.manholeofthisday

2020062305


機能は名前そのままですが、拙作マンホールマップの機能の1つである「今日のマンホール」を VSCode 内に表示する、というマンホーラー向けのものです。

VSCode にこのプラグインをインストールするには左ペインから「拡張機能」を選ぶか、Ctrl + Shift + X を押して拡張機能画面に移動し、検索バーに "manholeofthisday" と入力します("manholeof" あたりまで入力すると、検索候補が一つになります)。そして「インストール」と書かれた箇所をクリックしてインストールします:
2020062301


インストール後、実際に MOTD 機能を利用する場合は Ctrl + Shift + P でコマンドパレットを開き、このパレットに "MOTD" と入力してコマンドを検索し、最後に見つかった MOTD 部分をクリックします:
2020062302


MOTD コマンドを実行した日(月&日)のマンホールがマンホールマップの「本日のマンホール」に記録されて存在していた場合は VSCode 内の新しいタブが一つ追加され、その中で「本日のマンホール」画像と説明が表示されます。なおこの機能の実現には Webview API を使っています:
2020062303


画像部分をクリックすると、ブラウザで該当マンホールのマンホールマップ内ページが開き、より詳しい情報を参照することができる、というものです:
2020062304



この MOTD プラグインのソースコードはこちらで公開しています。開発言語として TypeScript を選ぶこともできましたが、今回は JavaScript で開発しました。この手軽さもハードル低くていいですね:
https://github.com/dotnsf/manholeofthisday

 

最近マイブームになっている「『あつまれ どうぶつの森(以下『あつ森』)』のマイデザイン」ネタです。いままではエンターテイメント色が濃い内容でしたが、ちょっとだけ業務に寄せてみました(ほんのちょっとだけ)。


『あつ森』の「マイデザイン」は 32x32 のピクセルデータになっています:
EYXVHfAUwAAz0tb


このサイズはノーツ/ドミノのデータベースアイコン(以下『DBアイコン』)と同じです:
2020061500


・・・ということは!! というわけで(?)インポートツールを作ってみました。データが流れるロジックとしてはこんな感じ:
  1. ノーツ/ドミノのデータベース(サーバーとファイルパス)を指定
  2. 指定データベースからアイコン情報を取り出す
  3. 取り出したアイコン情報を『あつ森』のマイデザイン情報に変換
  4. 変換したマイデザイン情報を QR コード化して画面に表示
  5. Nintendo Switch Online アプリで QR コードを読み取り
  6. 『あつ森』からマイデザインにダウンロード

このうち4以降の部分は過去のブログで紹介したものと同じですが、1~3部分が今回挑戦した部分です。内容が内容ということもあってググってもサンプルコードや役立ちそうな情報が見つからず、ほぼ独自実装でした。

で、この1~3部分を実現するウェブアプリケーションを作ったわけですが、そのシステム構成はこのようになります:
2020061500


ご覧のように2つのシステム(赤字部分2つでツールとして成立)から成り立っています。理想を言えば①の Domino Servlet(Java Servlet)のみで QR コードを生成できればよかったのですが、現時点では実現できていません(理由は後述)。Java Servlet のみで実現できなかった部分を補足する②のアプリケーション・サービスを別途足すことで実現しています。


作ったシステムはこちらです。ソースコード含めて MIT ライセンスで公開しています:
https://github.com/dotnsf/nsficon2qr


以下、このシステムのセットアップ方法です。ドミノサーバー環境がある方で『あつ森』ユーザーの方(加えて Nintendo Switch Online 加入済みの方)はぜひ試してみてください。ちなみに自分は CentOS 7.8 上の Domino v10.0.1 で動作確認しています。


まず上記リポジトリを git clone するか zip ダウンロード&展開して、nsficon2qr プロジェクトソースコード一式を手元に用意します。このプロジェクトフォルダには java フォルダと node フォルダが含まれており、それぞれ上述の①、②システムを構成するパーツになっています:
2020061501


では順にセットアップしていきます。まずは①ですが、こちらは Domino 環境側にも事前準備が必要です。管理者 ID で Domino サーバーに接続して Domino ディレクトリのサーバー文書を開きます。そして "Internet Protocols" タブの "Domino Web Engine" を選び、その中の "Java Servlets" カテゴリー内を以下のように設定して保存し、サーバーを再起動します:
  • Java Servlet Support : "Domino Servlet Manager" を選択
  • Servlet URL path : "/servlet" と入力※
  • Class path : "domino/servlet" と入力※

2020061502

※これらの設定をすることでデータディレクトリ(CentOS 版だと /local/notesdata)以下の domino/servlet というフォルダの中に存在しているサーブレットのクラスファイル(例えば a.class)を "/servlet/a" という URL パスで指定して実行できることになります。

加えて、Class path に指定したフォルダ(この例だと /local/notesdata/domino/servlet)はデフォルト状態では存在していないため、このフォルダを作成しておきます:
$ sudo mkdir -p /local/notesdata/domino/servlet

$ sudo chown notes.notes /local/notesdata/domino/servlet


これで Domino Servlet Engine が動くようになりました。改めて github からダウンロードした nsficon2qr プロジェクトを開き、java フォルダ内の nsficon2qr.class ファイルをサーブレットフォルダ(上述の例であれば /local/notesdata/domino/servlet/)にコピーします:
$ cp nsficon2qr.class /local/notesdata/domino/servlet

$ chmod 755 /local/notesdata/domino/servlet/nsficon2qr.class

そして、Domino サーバーコンソールから HTTP タスクを再起動します:
> tell http restart


これで①部分のセットアップは完了です。続いて②部分もセットアップします。なお ②は Domino と同じシステム上に作ってもいいですし、①の Domino サーバーに接続可能な別のシステム上に構築しても構いません。動作確認目的であれば、 localhost (つまり自分の PC )上であっても構いません。

②を構築する環境上に Node.js 環境を構築します。リンク先を参照して、各自のシステムに合わせて最新モジュールをインストールしてください(V10 以上であれば動くはず)。

次に node/settings.js ファイルをテキストエディタで編集します。実質1行だけのファイルですが、この中で定義されている exports.servlet_url の値が①で用意したサーブレットにアクセスするための URL となるように編集して(要するに IP アドレス部を変え、必要であればポート番号を追加して)保存します:
exports.servlet_url = 'http://192.168.xx.xx/servlet/nsficon2qr';

その後、ターミナル(コマンドプロンプト)を開いて node/ フォルダに移り、以下のコマンドを実行して②のアプリケーションを起動します:
$ cd node

$ npm install

$ node app

これで②も準備完了です。ウェブブラウザで②が動いているシステム(自システムであれば localhost)の 8080 番ポートにアクセスしてください。以下のような画面になればセットアップは成功です:
2020061503


実際に2つのデータベースを使って動作確認した様子を紹介します。以下ではこの2つのデータベースをマイデザイン化しています:
2020061509


まずは "Node API Demo" というタイトルのデータベースです。こちらはアプリケーションアイコンが設定されているデータベースです:
2020061504


ちなみにもう1つの "デフォルトアイコン" というタイトルのデータベースではアプリケーションアイコンは設定されておらず、クラシカルアイコンが表示されています。こちらも後で試します:
2020061505


まずは前者のデータベースをマイデザイン化してみましょう。②のアプリケーションにアクセスして、Domino サーバーから見たデータベースファイルを指定します。サーブレットが動いている Domino サーバー上のデータベースを対象とする場合であれば "Domino Server" 欄は空のままとなります。また "FilePath" 欄はデータベースファイルのパスを指定します(通常のデータベース指定方法と同じです)。なおこの機能はサーブレットが動いているサーバーの ID を使って動くため、この ID でデータベースの設計要素にアクセスできる権限が必要です。最後に "NSFICON2QR" と書かれた青いボタンをクリックします:
2020061506


データベース容量や複雑さによってパフォーマンスが変わりますが、数秒で解析が終わり、QR コードが画面内に表示されます:
2020061507


この QR コードをスマホにインストールした Nintendo Switch Online アプリケーションのタヌポータル画面から読み取ります。この QR コードを読み取る箇所から先の手順はこちらで紹介した手順と全く同じなので、必要に応じてこちら(の後半部分)も参照ください。

タヌポータルで読み取って保存した後に Nintendo Switch の『あつ森』を起動し、マイデザインからダウンロードを試みると、QR コードで読み取ったデザインが見つかります。「オッケー!」を選択することで『あつ森』ゲーム内で利用することができるようになります:
EaiWUQ6U8AAQsr2


"Node API Demo" という、データベースタイトルと同じ名前のマイデザインが、アプリケーションアイコンをインポートした形でダウンロードできました:
EaiWUROU0AI6-dL


ダウンロードしたマイデザインを地面の模様として貼り付けてみました。これ以外にアバターのトップスとして身につけたりすることもできます:
EaiWURXUEAAq_wq



同様にしてアプリケーションアイコンのない(クラシカルアイコンだけの)データベースも指定して、QR コードを生成してみました。これもスマホの Nintendo Switch Online アプリ内タヌポータルで読み取って、『あつ森』内にダウンロードできます:
2020061508


クラシカルアイコンのマイデザインも取り込むことができました:
EaiWUQ4UYAADIbh


(注 ↑よく見るとクラシカルアイコンを取り込んだ結果の左右が反転していました。現在のソースコードでは修正済みです)


あらためて元のデータベースアイコンと見比べてみます。ちゃんとエクスポートできていますね:
2020061500




以下に現時点での制限事項などをメモしておきます。

まず、上述の「本来はサーブレットのみで実現したがったができなかった」点について。最終的に表示する QR コード(の画像)をサーブレットの実行結果として返すことができるのが自然だし、理想的な挙動だと思っています。一方でこの『あつ森』マイデザイン用の QR コードは(URL などの文字列ではなく)バイナリ配列データを示す QR コードとなっていて、その意味でも少し特殊な仕様となっています。Java で利用できる QR コード生成ライブラリは有名な ZXing をはじめいくつかありますが、このバイナリ配列データを示す QR コードを生成可能な Java ライブラリを見つけることができなかったため、理想的な挙動を断念したという経緯があります(②がデータ入力部分と QR コード生成部分を担当しています)。もしどなたかバイナリ配列の QR コードを生成可能な Java ライブラリをご存知であれば改良に挑戦したいのでぜひ教えてください。

次にマイデザイン化するアイコンについて。上述のように1つのノーツデータベースには最大2つのアイコンが定義されています:
2020061504


これはノーツ v8.5.2 からの新仕様で、それ以前は特定のカラーパレットから選択した16色(+透明な背景色)だけが利用できるもの(以降「クラシカルアイコン」と呼びます)でした:
2020061500


v8.5.2 からは 32x32 のサイズであれば各種画像ファイルを指定して取り込むことができるようになりました(以降、こちらを「アプリケーションアイコン」と呼びます)。実際にワークスペースなどに表示されるアイコンは
 ・アプリケーションアイコンが設定されている場合はアプリケーションアイコン
 ・アプリケーションアイコンが設定されていない場合はクラシカルアイコン
  (クラシカルアイコンにはデフォルト画像が設定されている)
のように判断されて表示されます:
2020061509


このアプリケーションでも同様の判断基準でアイコン情報を取り出してマイデザイン化しています。ただここでマイデザイン特有のカラーパレットの問題が生じます。

簡単に説明すると、『あつ森』マイデザインに利用できる色は自由に選べるわけではなく、特定の 159 色から選択する必要があります。また1つのマイデザインの中で最大15色(+背景色)までしか選ぶことができない、という制約があります。

一方、ノーツアイコンですが、クラシカルアイコンの場合は16色から選択、アプリケーションアイコンの場合はより自由度高く利用できる、という違いがあります。

今回、このツールを作るにあたり、このカラーパレットの違いを吸収する必要がありました。以下のような仕様にしています:
・背景色は強制的に白
・アプリケーションアイコンの場合はカラーパレット内の利用頻度の高い15色に減色
・クラシカルアイコンの場合は2つの灰色を同一視する形で15色に減色
2020061500


これらの仕様の違いによって、ノーツデータベースアイコンが 100% マイデザインで再現できるわけではない、という点をご了承ください。




マンホール蓋の位置情報付きポータルサイトであるマンホールマップは、Twitter の OAuth ログインによってユーザー認証を行い、ログイン後にマンホール画像を投稿できる機能が有効になります。が、ログインしなくても投稿済み情報を参照できるようになっています。


この参照できる情報には投稿されたマンホール画像やその位置情報(地図)だけでなく、投稿者の情報も含まれています。投稿者の名前だけでなく、Twitter アイコン(プロフィール画像)も表示されます:
2020060401



【起こった問題】
正確にはどのタイミングからだったのかわからないのですが、先日からマンホールマップにこの Twitter アイコンが表示されなくなる、という現象が起こっていました。


マンホールマップ側に変更がない状況で表示されていたものが表示されなくなった。ということは Twitter で何かあった?一時的な障害であることを祈っていたのですが1日経過しても状況は変わりませんでした。もしかして Twitter API が変更になったのかなあ、、という可能性も考えたのですが、明確なアナウンス類を見つけることができませんでした。ただ 2019 年に発表されたこの変更予告を見逃していて、もしかしたら今年の5月末くらいに実装からも外れて・・・みたいな感じで関係あったのかなあ(未確認)・・・という感じ:
https://twittercommunity.com/t/upcoming-changes-to-user-object-and-get-users-suggestions-endpoints/124732/2

2020060404



これまでのマンホールマップでの Twitter アイコン取得方法と同じ方法(後述)を解説していたこちらのページの中でも画像が表示されているべき(と思われる)箇所の画像が表示されていません。つまりマンホールマップにだけ発生している現象というわけではなく、このページでも自分と同じ現象が起こっているように感じました:
Twitter APIで取得したプロフィール画像のサイズを変更する


(↓この部分、本来は画像が表示されている??)
2020060403



ともあれ詳しい状況はわからないままですが、表示されなくなった Twitter アイコンを復活させるべく行った緊急対応の顛末を記録しておきます。結論として現時点(2020/06/04)で応急処置的にアイコンが表示されるよう復活しています。



【これまでの Twitter アイコン取得方法】
もう公式ドキュメントには記載されておらず、どこにこの方法について言及したドキュメントがあったのかも覚えてないのですが、これまでは以下のように HTTP API を2回使って Twitter アイコン画像の URL を取得していました:

(1)GET https://twitter.com/screen_name/profile_image にアクセス(screen_name 部はアイコンを表示したい人の Twitter アカウントの表示名※)
(2)(1)の結果得られる JSON オブジェクトから request.path の値を取り出す( "/12345/67890.jpg" みたいな値が取り出される)。
(3)HTML で <img src="https://pbs.twitter.com(request.path の値)"/> などのようにするとアイコン画像が表示できる


※Twitter アカウントの表示名とは、アカウントのページを開いた時のこの部分(赤枠)のことです:
2020060402



これまでのマンホールマップではこの方法で投稿者の Twitter アイコン画像を表示していました。上述の「ここでも自分と同じ現象が起こっている・・・」と書いたリンク先でも同じ手法が紹介されていますが、マンホールマップ同様に表示できなくなっているようでした。

調査した結果を記載しておくと、上述の方法で(1)と(2)は結果を得ることができているのですが、(3)で指定する URL にブラウザでアクセスすると 404 エラー(存在しない URL)となりました:
2020060402


ただ、では(1)と(2)が成功しているのかというと、どうも怪しいと思っています。(1)を実行した結果得られる(2)の値は以前は実行するまで推測できないパス名だったのですが、いま実行すると '/screen_name/profile_image' という結果となりました(つまり(1)を実行した時のパスがそのまま返ってくる)。この時点で以前のアイコンが正しく表示出来ていた頃とは結果が異なっているので、もしかすると(1)が以前のように動かなくなっていることが、アイコンが表示されない直接の原因なのかもしれない、、と推測しています。


いずれにしても、この API はもう使えなくなっちゃったのかな・・・ 結論として後述の応急手当的な対応はできたのですが、正直、今でもこの方法に戻せるなら戻して使いたいと思っています。理由も含めて後述します。


【現時点での正攻法(Twitter API を使う方法)】
上で紹介した方法以外に、(ちゃんと)Twitter API ドキュメントで紹介されている方法を使ってアイコン画像を取得する(正攻法的な)方法もあります。逆にいうと上述の方法は現在の Twitter API ドキュメントを探しても見つからない、ある種の「裏ワザ」的な方法だったりします(苦笑)。

正攻法というのは、具体的には GET /users/show API を使う方法です:
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show

2020060403


この API を実行する際のパラメータでアイコンを取得するユーザーの screen_name を指定します。すると指定したユーザーの情報を得ることができ、その中にはプロフィール画像(アイコン)の URL が含まれているので、その値を使うことでアイコン画像を表示することができる、というものです。


【正攻法(Twitter API を使う方法)では駄目な理由】
しかしこの方法はマンホールマップでの実装には向かない大きな理由があります。それはこの API はアクセストークンを使って実行する必要があるのですが、ユーザーがログインしていないとアクセストークンが取得できないのです。つまりユーザーがログインする前や、そもそもログインしないユーザーからするとアクセストークンを取得するタイミングがないので、この API を使うことが出来ず、アイコンを表示できないのでした。

マンホールマップは上述のようにログインしなくても参照できることを謳ってきていた背景もあり、Twitter 側に仕様変更があったとしても、急にマンホールマップにもログインを必須にすることに抵抗を感じてしまいました。。 そんな背景もあり、この正攻法での方法は採用していません。


【応急処置による現在の Twitter アイコン取得方法】
で、結論としてはこの方法を採用しているのですが、では改めてユーザーのログインなしにどうやって Twitter アイコンを取得しているか、を紹介します。あくまで応急手当的な内容であり、実行効率はよくない(のでできれば早く修正したい)ことを自覚している方法であることをご了承ください。

実現方法を簡単に言うと「Twitter にログイン済みの別プロセスを使って API を実行する」方法です。以下でもう少し詳しく紹介しますが、その前に twurl というコマンドラインツールを紹介します。
https://github.com/twitter/twurl

2020060404



twurl (読み方わからず・・)は Twitter 謹製の Twitter API 専用 curl といった位置づけのオープンソース製品です。各種 Twitter API を必要であればパラメータを付けてコマンドラインから実行し、その結果を標準出力に取り出すことができます。このツールも実行前に OAuth によるログインが必要ですが、ログインを1度実行しておけば、そのあとの API 実行は続けて行うことができます。標準の curl でも Twitter API を実行することは可能ですが、パラメータとして与える署名の計算が毎回面倒だったりするわけです。一方 twurl を使うとそのあたりは裏でバッチリやってくれるらしく、必要最小限のパラメータだけを渡して実行することができる、というものです。

例えば上述した正攻法による API で紹介した GET /users/show API を使ってユーザー情報を取得する場合であれば、セットアップ後にこういったコマンドを実行します(curl と同様ですが、"-X GET" は既定値なので省略可能です):
$ twurl -X GET /1.1/users/show.json?screen_name=dotnsf

これで screen_name が dotnsf(僕のアカウントです)であるユーザーの情報を取得することができます。結果は JSON で得ることができますが、この中の "profile_image_url_https" キーの値がそのユーザーの Twitter アイコン画像を表示するための URL 、ということになります:
$ twurl -X GET /1.1/users/show.json?screen_name=dotnsf
{
  "id": XXXX....,
  "id_str": "XXXX....",
    :
  "profile_image_url_https": "https://pbs.twitter.com/AAAAAAAA/BBBBB.jpg",
    :
}

この値が目的の URL 文字列です。したがって twurl コマンドを使うと目的の文字列を取得することができることがわかりました。


で、今回の API 代替方法というのは、この twurl を外部プロセスで実行して対象 Twitter ユーザーのアイコン画像の URL を取り出し、この URL を使ってアイコンを表示する、という方法です。外部プロセスを使うのがちとダサいのですが、一方でこの方法なら Node.js 実行前に twurl のセットアップを済ませておけば、Twitter API 実行のためのウェブアプリケーション側でのログインは不要となるので、参照目的のユーザーであっても(ログインしなくても)アイコンが表示される、ということが実現できるようになります。

マンホールマップのソースコードは現時点においては非公開ですが、この該当部分だけを別アプリケーションにして github で公開しています:
https://github.com/dotnsf/twurl


このアプリケーションは上述の twurl を別プロセスで動かして目的の URL を取得する、という内容を Node.js で実現するサンプルです。おそらく他のプログラミング言語であっても(外部コマンドを実行して、その結果を取得する機能があれば)実現できると思っています。

サンプルアプリの使い方ですが、まずアプリケーションを実行する前に twurl をセットアップする必要があります。詳しくは twurl の github 内にも記載されていますが、一応こちらでも(日本語で)以下に紹介します。

まず twurl は Ruby Gem を使ってインストールします。そのため Ruby(& Gem) 環境が必要です。Ruby がインストールされていない環境の場合はインストールしておきましょう。 Ubuntu 環境下であればこんな感じで:
$ sudo apt-get install ruby

Ruby Gem が導入されている環境で、以下のコマンドを実行すると twurl が導入されます:
$ sudo gem install twurl

これで(Ubuntu であれば /usr/local/bin/twurl として)twurl がインストールされました。次に twurl のセットアップが必要です。Twitter Developers にアプリを登録し、Consumer Key と Consumer Secret を取得した上で以下のコマンドを実行します:
$ twurl authorize --consumer-key (Consumer Key) --consumer-secret (Consumer Secret)

このコマンドを実行すると「この URL を開け」という指示が表示されます。その URL をブラウザで開くと認証用の文字列が表示され、それと同じ内容を実行中の twurl コマンドの入力待ちプロンプトに打ち込んで Enter キーを押します。正しい文字列が指定されていれば認証が完了し、twurl コマンドが使えるようになります。試しに上述の GET /users/show コマンドを実行するなどしてみてください:
$ twurl /users/show?screen_name=dotnsf
(screen_name が dotnsf であるユーザーのプロフィール情報が表示されます)

これで twurl を実行する準備が整いました。あとは Node.js のアプリケーションからこのコマンドを外部呼び出しで実行し、その結果を取得・解析してプロフィール画像の URL へリダイレクトさせることで目的の機能が実現できそうです。


twurl のセットアップができた所で、改めてこのサンプルアプリケーションを動かしてみます:
https://github.com/dotnsf/twurl


このサンプルアプリケーションの app.js ファイルは以下のようになっています:
//.  app.js
var express = require( 'express' ),
    app = express();
var { execSync } = require( 'child_process' );
var settings = require( './settings' );

app.get( '/', function( req, res ){
  var screen_name = req.query.screen_name;
  if( screen_name ){
    try{
      var stdout = execSync( settings.twurl_command + ' /1.1/users/show.json?screen_name=' + screen_name );
      var obj = JSON.parse( stdout.toString() );
      var profile_image_url_https = obj.profile_image_url_https;
      res.redirect( profile_image_url_https );
    }catch( e ){
      return res.status( 403 ).send( { status: false, error: e } );
    }
  }else{
    return res.status( 403 ).send( { status: false, error: 'No screen_name provided.' } );
  }
});

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );

そして別ファイルである settings.js は以下のような設定にしています:
//. settings.js
exports.twurl_command = '/usr/local/bin/twurl';


簡単に解説しておくと、GET / をハンドルする API だけが定義されています。そしてこの API では screen_name というパラメータを受け取って、
$ /usr/local/bin/twurl /users/show.json?screen_name=(パラメータの値)

を同期的に実行し(twurl のパスは settings.js 内に記載)、実行結果が stdout 変数に格納されます。そして格納された結果を JSON パースした上で "profile_image_url_https" の値を取り出して、その URL にリダイレクトする、という処理を行っています。 これによってパラメータで指定した screen_name を持つ Twitter ユーザーのプロフィールアイコン画像を表示する、という処理を実現しています。

実際にサンプルアプリケーションを動かして、ブラウザで http://localhost:8080/?screen_name=dotnsf を実行した結果がこちらです:
2020060401


http://localhost:8080/?screen_name=dotnsf にアクセスすると、twurl の実行結果に含まれる URL に転送され、screen_name パラメータで指定した Twitter ユーザー(この場合であれば @dotnsf)のプロフィールアイコン画像が表示できました。twurl のセットアップ時に consumer_key と consumer_secret を指定してはいますが、そのあとのアプリケーション実行時には Twitter の OAuth ログインなしに Twitter API を実行して結果を取得することができています。

実用上においては、Twitter アイコンを表示するたびに twurl を使うこの一連の処理を実行するのは重すぎるので、一度取得した結果をキャッシュしておくなどの対処が必要になると思っています。ただこのやりかたで一応、挙動としては最低限の目的を達成することができました。

というわけで、無事にマンホールマップで投稿者の Twitter アイコンは応急処置的に復活できています:
2020060405


このフローは以前に少し違う形で業務やイベントのネタ(の裏側)として使っていたことがあったのですが、埋もれてしまうのはもったいない気がしたので公開しちゃいます。

Node-REDFX (外国為替)情報を取得するフローを作りました。FX というのは例えば USDJPY だと USD と JPY 、つまり米ドルと日本円の関係です。「1ドル=107円23銭」みたいなやつですね。これの EURUSD (ユーロドル)やら EURJPY (ユーロ円)やら AUDJPY (豪ドル円)やら、、主に日本円が絡む通貨ペアを中心に 20 ペアの情報を1分おきにリアルタイムで取得するものです。

フローはこちらで公開しています:
https://flows.nodered.org/flow/9d045f691b6d7c5cb3259c197ad365d0

2020060105



このページ内のフロー定義を "Copy" して、Node-RED 環境に「クリップボードから読み込み」するだけでフローが再現できます。フロー1本だけの、それも標準ノードの組み合わせだけで構成されているシンプルな内容です。動く条件は「Node-RED 環境がインターネットに接続されていること」だけでいけると思います:
2020060101


↓ペースト後、こんなフローのタブが作られていれば成功:
2020060102


あとはこのまま「デプロイ」すれば1分おきに inject ノードが動き出し、取得した FX 情報を debug タブに出力し続けます:
2020060103


1回実行した時の debug タブの様子はこんな感じです。_id に実行時の日付時刻が入り、あとは通貨ペアとその瞬間の価格がまとめて出力されます:
2020060100



公開しているフローではこれだけ(debug タブに出力するだけ)ですが、IBM Cloud 内の Node-RED として動いている環境であれば、バインド済みの Cloudant out ノードをフローの最後に追加して、DB 名を指定するだけで出力される情報を1つのレコードとして DB に格納する所まで簡単に実現できます。他の環境でも各種データベースノードに渡すことで取得データの DB 格納ができます:
2020060104


中身は inject node が一分ごとに発火してオープンな API を使って FX 相場を取得し、(Cloudant DB に格納する前提での)JSON フォーマットに変換して debug ノードに渡す、というものです。FX は24時間相場が動くので、1日に 60 * 24 = 1440 データ集まります。(データ量に気をつけながら)1ヶ月程度動かしっぱなしにしておくとそこそこの為替情報データベースができあがります。シンプルですが API やフォーマットを変えることで応用範囲が広くなりそうだと思っています。

本来は集まったデータをグラフ表示したり、上下動の予測をしたり、、、といった使いみちになると思っています。サンプルではない実データを簡単に集めることができるので、説得力のあるデモアプリに応用しやすいと思っています。興味ある方は使ってみてください。


このページのトップヘ