GoのGenericsの型制約はinterfaceで表現しないといけないけど,自身の型が表現できないの地味に面倒.
単純な例だと,比較できる型を
type Comparable interface {
Equals(Comparable) bool
}
func Compare[T Comparable](a, b T) bool {
return a.Equals(b)
}
と書きたくなるけど,func (v Foo) Equals(other Foo) bool
ではく,func (v Foo)Equals (other Comparable) bool
を実装しないといけなくてGenericsの嬉しさがなくなる.
なので,
type Comparable[T any] interface {
Equals(T) bool
}
func Compare[T Comparable[T]](a, b T) bool {
return a.Equals(b)
}
としないといけない.このanyが分かりにくいので,できれば Comparable[T any]
を Comparable[T Comparable[T]]
と書きたいのだけど,invalid recursive type
になってしまう.
まだ少しだるいけど,体調はもとに戻った気がする.結局一週間ずっとだるくてやる気が出なかった.
一日12時間以上寝てたけど,睡眠時間が長くなると夢の中で夢だと気づく明晰夢を見ることが多いような気がする.明晰夢よりも,寝ぼけていると時間を巻き戻したり物をコピペで増やしたりできなくて現実が不便に感じることが増えるのが困る.
眠い.19時頃寝て夜中に一度起きてまた朝まで寝る生活をしている.
起きたら夜だった.体調はだいぶマシになったような気がするけど,昨日までは大丈夫だった喉と口内炎が痛い..
とても調子悪い.風邪っぽいので病院に行く.
少し熱あるので念のため電話したら37.5℃以下なら普通に行って大丈夫らしい.ただ,午後はCOVID-19の発熱外来だけで予約埋まってるらしいので慌てて家を出る.難易度が高い.一応PCR検査も受けてくる.結果は電話で教えてくれるらしいので帰って寝る.
とりあえずPCR検査は陰性だった.
そういえば,小さい病院は未だに現金のとこ多いのどうにかならないのかな.電子マネーも色々面倒なのだろうけど,現金の不便さのほうが大きい気がする.そして,病院の会計後の財布の残金36円……薬局は電子マネー使えて助かった.
眠い.なんだか先週末から調子が悪い気がする.
昨日の続き.ADBのRSA署名ようにPEM形式の鍵ファイルを読めるようにしたり,よくあるUserScriptみたいに対象URLをスクリプトファイル内にコメントで書けるようにしておく.個人的に使うにはこれで良さそう.
chromedp,テストの自動化とかに使いやすそうだけどユーザが操作しているブラウザに対して何かするには少し使いにくいかも.実行したいコマンド列をRun()に渡して実行するのだけど,途中でユーザがタブを閉じたりするのをハンドリングできなくておかしな状態になる気がする.あとスレッドセーフじゃない操作があるっぽいので複数のgoroutineから使うのが煩雑になりがち.
眠くてやる気が出ない...
* ADBプロトコル
https://github.com/binzume/chrome-watch
一昨日のやつ.コンテナ内で動かすときにAndroidのplatform-toolsに依存したくなかったり,adb forwardして認証無しでブラウザにアタッチできる状態が気持ち悪いので,ADBプロトコルを実装して直接Oculus Quest上のブラウザと通信するようにする.
TCP接続をADBに置き換えるだけなのだけど,chromedpは普通のWebSocketしか対応していないので,接続時に使われるDefaultDialer
を上書きしてADBを使うようにする.色々行儀が悪いことしているので,chromedpの実装が変わったりすると壊れそう.
ADBは単純なプロトコルなので https://android.googlesource.com/platform/packages/modules/adb/ を見ながら実装したらすぐ動いた.ただ,説明と実装が違ってたり読んでも細かいことがよくわからないので,コードを読む方が早かった.パケットのチェックサムを crc32 of data payload
と説明しつつ実際は和を求めているだけだったりするの実装したほとんどの人が目を疑ったんじゃないかと思う.
あまり真面目に調べなかったけど,RSA署名周りの動作が不思議で,署名は送らずに公開鍵をA_AUTH(3,0,pubkey)で送信すると Androidの画面に「USBデバッグを許可しますか?」と鍵のフィンガープリントが表示される.公開鍵だけでこのダイアログ出せる上に,「許可」を押すと問答無用で接続が成功する.公開鍵暗号とはいったい...
AndroidだけmDNS使えなくてWebインターフェイスを持った機器のIPを調べたりするの面倒だと思ってたのだけど,Android 12でmDNSでの名前解決がサポートされてた...
* Oculus QuestのブラウザをGoから操作する
Oculus Browserでbookmarkletやアドレスバーからスクリプト実行できなくなってしまったのでADB経由で操作する.PCのChromeから操作できるけど,開いているタブを監視して,URLがマッチしたら自動的にスクリプトを実行するようにしたい.
Chromeのリモートデバッグで操作可能なのはわかっているので,Chrome DevTools Protocolで通信して操作することにする.Android上ではchrome_devtools_remoteというドメインソケットで待ち受けているらしいので,ADBでforwardする必要がある.
adb forward tcp:9222 localabstract:chrome_devtools_remote
あとは ws://localhost:9222/devtools/browser に繋げば色々出来る.
http://localhost:9222/json
にアクセスすればタブの一覧が見れたりする.
Chromeは直接ADB上で何かしてるように見えるけど,ほとんどのDevTools Protocolを扱うライブラリはTCP(というかWebSocket)で接続するっぽい.
今回はとりあえず, https://github.com/chromedp/chromedp というGoのライブラリを使う.
困ったのは,Contextがcancelされると問答無用でタブを閉じてしまう?仕方ないので, 切断前にchromedp.Context.TargetIDを空にして回避.
あとは,ADBをネットワーク越しに使うために,Questを再起動すると adb tcpip しなおさないといけないのをどうにかしたい...
* JavaScriptのawait
まだPromiseが使えない時代に実装されたPromiseっぽい値も普通にawaitで待てるので,たぶんそうなのだろうと思ってたのだけど,Promise型である必要はなくてthen()が呼び出せれば何でも良いのか.
Meta Quest Browser とうとうアドレスバーやブックマークからJavaScriptを実行する口が本格的に塞がれてしまったように見える.
今まではブックマーク登録時のUIでjavascript:から始まる文字列禁止しているだけだったので抜け道は色々あったのだけど,もうダメっぽい.ChromeのDevToolsで繋いで
contentNavUI.webUIChannelRouter.doAction(3, {url:"javascript:alert('hello!')"});
とかやっても何も起きないので,ブラウザ本体側で無視されてるみたい.
拡張機能の代わりにブックマーク経由でツールを読み込んでいたのが動かなくて不便になってしまった...あとはADB経由で操作するしかなさそう.
他のブラウザに移行することも考えて,Firefox Realityの後継のWolvicも試してみたけど,あまり昔と変わってないな.ChromiumベースでOSSなQuest用のブラウザがあると良いのだけど,ほとんどの人にとってそれはMeta Quest Browserで良さそう.
眠くて昼寝したら夜になっていた…….
npmのdependencyにはfile:...で相対パスを書けるけど,依存関係が壊れるパターンが多い.workspace外で使わない方が良さそう(?)
単純な場合は動きそうに見えたので,https://github.com/binzume/karakurijs で使ってたのだけど,ubuntuで動かないと言われたので挙動を調べる.Linuxだとnode_modules内に作られるシンボリックリンクもdependencyに書いた相対パスになってしまっている.この挙動だと複数のパッケージで構成されるライブラリをシングルリポジトリで開発するのはダメそう.npmcliの実装読む限りただのバグに見えるけどdependency周りの処理は闇が深そうなので触らないことに.
リポジトリ分けるの面倒なので,gitpkg.now.sh経由でgithub上のパッケージを参照するようにした.ただ,参照するためにはgithubにpushしなくてはいけなかったり,同じリポジトリのpackage.jsonのバージョンを1コミット内で変更できない罠がある.結局,workspaceにするか1パッケージ1リポジトリ運用が無難なのかもしれない.
肉を食べた.