PlantUMLサーバとリアルタイム編集ツールの作成

環境

※本環境では、Webサーバ及び、PlantUMLサーバを、ubuntu上のDockerコンテナとして起動しています。

完成イメージ

dockerコンテナでplantuml-serverを起動する

% sudo docker run -d --rm \
         -p 8080:8080 \
         --name plantuml-server \
         plantuml/plantuml-server:jetty

dockerコンテナでWebサーバを起動する

dockerコンテナのnginxのDocumentRoot(/usr/share/nginx/html)を、ホストの ${HOME}/web/ で見えるようにする。

% mkdir ${HOME}/web
% sudo docker run -d --rm \
         --name plantuml-web \
         -p 80:80 \
         -v ${HOME}/web:/usr/share/nginx/html \
         nginx

ツールを配置する

このサイトから、Javascript製の圧縮・解凍ツールを ${HOME}/web 以下にダウンロードする

% cd ${HOME}/web

% wget -O inflate.js \
  http://www33146ue.sakura.ne.jp/staff/iz/amuse/javascript/expert/inflate.txt

% wget -O deflate.js \
  http://www33146ue.sakura.ne.jp/staff/iz/amuse/javascript/expert/deflate.txt

${HOME}/web/ に以下を index.html として作成してアクセスする。http://localhost/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
    <script src="./inflate.js" type="text/javascript"></script>
    <script src="./deflate.js" type="text/javascript"></script>
    <title>PlantUML realtime editor</title>
  </head>
  <body>
    <table>
    <tr><td colspan=2><a href="http://pdf.plantuml.net/PlantUML_Language_Reference_Guide_ja.pdf" target=_>Manual</a></td></tr>
    <tr><td colspan=2>
      <textarea id="inputUrl" cols="80%">http://localhost:8080/svg/Iyp9J4xLjKlAJm80</textarea>
      <input type="submit" name="decode" value="decode" onClick="urlToText()">
      <input type="submit" name="copy" value="copy" onClick="copyBuffer()">
    </td></tr>
    <tr>
      <td>
        <textarea id="editorArea" rows="30" cols="80" onchange="textToUrl(this)" onkeyup="textToUrl(this)"></textarea>
      </td>
      <td>
        <img id="outputArea" src="" />
      </td>
    </tr>
    </table>
    <script>
    function copyBuffer(){
      $("#inputUrl").select();
      document.execCommand('copy');
    }

    // text to url
    function textToUrl(){
      var s = $('#editorArea').val();
      s = encodeURIComponent(s);
      s = unescape(s);
      s = zip_deflate(s, 9);
      s = encode64(s);
      $('#inputUrl').val("http://localhost:8080/svg/" + s);
      $('#outputArea').attr("src", "http://localhost:8080/svg/" + s);
    }

    // url to text
    function urlToText(){
      var s = $('#inputUrl').val();
      a = s.split('/');
      url = a[a.length-1];
      s = decode64(url);
      s = zip_inflate(s);
      s = escape(s);
      s = decodeURIComponent(s);
      $('#editorArea').val(s);
      $('#outputArea').attr("src", "http://localhost:8080/svg/" + url);
    }

    // functions
    //  http://plantuml.com/ja/code-javascript-synchronous

    // encode -------------------------------------------------
    function encode64(data) {
      r = "";
      for (i=0; i<data.length; i+=3) {
        if (i+2==data.length) {
          r +=append3bytes(data.charCodeAt(i), data.charCodeAt(i+1), 0);
        }
        else if (i+1==data.length) {
          r += append3bytes(data.charCodeAt(i), 0, 0);
        }
        else {
          r += append3bytes(data.charCodeAt(i), data.charCodeAt(i+1),
               data.charCodeAt(i+2));
        }
     }
     return r;
    }

    function append3bytes(b1, b2, b3) {
      c1 = b1 >> 2;
      c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
      c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
      c4 = b3 & 0x3F;
      r = "";
      r += encode6bit(c1 & 0x3F);
      r += encode6bit(c2 & 0x3F);
      r += encode6bit(c3 & 0x3F);
      r += encode6bit(c4 & 0x3F);
      return r;
    }

    function encode6bit(b) {
      if (b < 10) {
        return String.fromCharCode(48 + b);
      }
      b -= 10;
      if (b < 26) {
        return String.fromCharCode(65 + b);
      }
      b -= 26;
      if (b < 26) {
        return String.fromCharCode(97 + b);
      }
      b -= 26;
      if (b == 0) {
        return '-';
      }
      if (b == 1) {
        return '_';
      }
      return '?';
    }

    // decode -------------------------------------------------
    function decode64(data) {
      var r = ''
      var i = 0
      for (i = 0; i < data.length; i += 4) {
        var t = extract3bytes(data.substring(i, i + 4))
        r = r + String.fromCharCode(t[0])
        r = r + String.fromCharCode(t[1])
        r = r + String.fromCharCode(t[2])
      }
      return r
    }

    function decode6bit (cc) {
      var c = cc.charCodeAt(0)
      if (cc === '_') return 63
      if (cc === '-') return 62
      if (c >= 97) return c - 61 // - 97 + 26 + 10
      if (c >= 65) return c - 55 // - 65 + 10
      if (c >= 48) return c - 48
      return '?'
    }

    function extract3bytes (data) {
      var c1 = decode6bit(data[0])
      var c2 = decode6bit(data[1])
      var c3 = decode6bit(data[2])
      var c4 = decode6bit(data[3])
      var b1 = c1 << 2 | (c2 >> 4) & 0x3F
      var b2 = (c2 << 4) & 0xF0 | (c3 >> 2) & 0xF
      var b3 = (c3 << 6) & 0xC0 | c4 & 0x3F
      return [b1, b2, b3]
    }
    </script>
  </body>
</html>

※本例では、URLをlocalhostとしましたが、別PCからアクセスする場合は、index.html内のlocalhostを、修正する必要があります。完成イメージのアニメーションでは、家のUbuntuがインストールされたノートPCのIPアドレス192.168.1.122 となっています。

Nexus7(2012)のLineageOSにtermuxを導入する

目的

以下、環境にtermuxを導入するにあたり、当該バージョンで躓いた箇所の解決方法をメモしておこうと思います。

環境

  • H/W: Nexus7(2012)
  • S/W: LineageOS 14.1-20170423(Android7.1.2)
  • termux(0.73)をAPKPureでインストールを想定
  • プロンプトと環境
$ adbコマンドを実行するコマンドプロンプト(Linuxでも可)
grouper:/ # Nexus7にadb shellにログインした状態
% LinuxサーバでdockerでWEBサーバを実行する環境

調査

termuxのパッケージをインストール後、termuxの初期環境の入ったbootstrapファイルのダウンロードが正常に行われなかったため、この原因を調査し解決していこうとおもいます。

bootstrapのファイルのURL

初めに、このbootstrapファイルですが、後でわかったのですが、どうも古いパッケージに埋め込まれたURLと、現在提供中のURLが以下のように異なっているようです。

(新)○ http://termux.net/bootstrap/bootstrap-arm.zip
(旧)× https://termux.org/bootstrap-arm.zip

ログを確認する

Nexus7とPCをUSBで繋いでadbで操作をしていきます。

Nexus7でtermuxを実行したのち、adbで繋いでログを確認すると、以下の通り、間違ったURLへ接続を繰り返している事が確認できました。

Javaのsourceはさすがに修正できないので、URL曲げる方向で検討することにします。

$ adb get-state
$ adb shell
grouper:/ # logcat -t 1000|grep boot
04-22 02:24:10.650 7213 9172 E termux : java.io.FileNotFoundException: https://termux.org/bootstrap-arm.zip

どのファイルがURLを突きに行くのか

Nexus7とPCをUSBで繋いでadbでURLが埋め込まれたファイルを捜索していきます。

$ adb get-state
$ adb shell
grouper:/ $ su
grouper:/ # cd /data/app/com.termux-1/oat/arm
grouper:/data/app/com.termux-1/oat/arm # strings base,odex | grep http
./data/misc/profiles/cur/0/com.termux/primary.prof
0https://dl.bintray.com/termux/termux-packages-24
'https://termux.net/bootstrap/bootstrap-
https://termux.org/bootstrap-
https://wiki.termux.com
&https://wiki.termux.com/wiki/Main_Page

修正

上記より、以下のファイルに接続先が埋め込まれているであろうことがわかりましたので、このファイルを書き換えて行こうと思います。

grouper:/data/app/com.termux-1/oat/arm # pwd
/data/app/com.termux-1/oat/arm

バイナリファイルの書き換え

直接/data/app/com.termux-1/oat/armからファイルを転送することが出来ないので、いったん/storage/self/primary にファイルを移してからとってきます。

$ adb get-state
$ adb shell
grouper:/ $ su
grouper:/ # cd /data/app/com.termux-1/oat/arm
grouper:/data/app/com.termux-1/oat/arm # cp base.odex /storage/self/primary
^D
$ adb pull /storage/self/primary/base.odex ./

ファイルを取ってきた後、PCでbzエディタに base.odex を放り込んで、ASCIIモードで
「https://termux.org/bootstrap-」を検索して
「http:///termux.org/bootstrap-」に書き換えて保存する

$ adb push base.odex /storage/self/primary
$ adb shell
grouper:/ $ su
grouper:/ # cp /storage/self/primary/base.odex /data/app/com.termux-1/oat/arm/

linuxのPCでWEBサーバ起動

% cd /home/saka/ngixn/
% sudo vi default.conf
server {
  server_name termux.org;
  listen 80;
  location /bootstrap-arm.zip {
    proxy_pass http://termux.net/bootstrap/bootstrap-arm.zip;
  }
}

% sudo docker run -d --rm \
  -p 80:80 \
  -v /home/saka/nginx:/etc/nginx/conf.d \
  nginx \
  nginx-debug \
  -g 'daemon off;'

nexus7で/system/etc/hosts設定を変える

hostsファイルはread onlyでマウントされているので直接編集できないので、read writeモードで再マントします

$ adb shell
grouper:/ $ su
grouper:/ # mount|grep system

/dev/block/platform/sdhci-tegra.3/by-name/APP on /system type ext4 (ro,seclabel,relatime,user_xattr,acl,barrier=1)

grouper:/ # mount -o rw,remount \
            /dev/block/platform/sdhci-tegra.3/by-name/APP \
            /system
grouper:/ # mount | grep system

/dev/block/mmcblk0p3 on /system type ext4 (rw,seclabel,relatime,user_xattr,acl,barrier=1)

hostsにtermux.orgのIPアドレスを設定します。このIPアドレス(ここでは192.168.1.122としています)は、WEBサーバを起動したLinux PCの物にしてください。

grouper:/system/etc # cd /system/etc
grouper:/system/etc # cp hosts hosts.org
grouper:/system/etc # echo '192.168.1.112 termux.org' >> hosts
grouper:/system/etc # cat hosts
127.0.0.1 localhost
::1 ip6-localhost
192.168.1.112 termux.org
grouper:/system/etc # ping termux.org
PING termux.org (192.168.1.112) 56(84) bytes of data.
64 bytes from termux.org (192.168.1.112): icmp_seq=1 ttl=64 time=61.8 ms

Nexus7でtermuxを起動

既に起動していたらいちどOS事再起動しておいてください。
termuxを起動して、bootstrapファイルのダウンロードが始まれば完了です٩(^▽^*)


他にもいろいろ試したのですが。。。

bzでURLを正しいものに書き換えたら・・・と思ったけど、あくまでもバイナリデータの編集なので、1byteも漏れなく修正する必要があるので、最小限にとどめる必要があった。

httpsのままにしてはどうか?と思ったけど、正しいURLも元の、httpsからhttpへ変更になったようで、httpsで直接接続が出来ない。また、Proxy用のLinuxで立てたWebサーバでSSLサーバ証明書を持たせるにはオレオレしかありませんが、nexus7のjavaが証明書エラーで接続に失敗するので、httpでのproxy接続とする必要があった。

最新のtermuxをインストールすれば?を検討したけど、Nexus7(2012)にインストールできるLineageOSは上記が限界で、最新のtermuxをインストールすることができなかった。

まぁとりあず、本来の目的はtermuxを使う事なので、手段は出来れば何でも良いかな。hostsとか、いじったところは直しておきましょう!