バグ #1231
完了アカウント切り替えがメニューから実行できない場合がある
説明
アカウント切り替えを画面左上のメニューから実行すると、タイミングによってできない場合があります。
切り替えができないときは、以下のエラーが出力されます(--debugでmikutterを起動)。
error: {MIKUTTER_DIR}/core/plugin/current_world/current_world.rb:21:in `rescue in block (2 levels) in <top (required)>': RuntimeError from {MIKUTTER_DIR}/core/plugin/current_world/current_world.rb:42:in `current_world=' from {MIKUTTER_DIR}/core/plugin/current_world/current_world.rb:17:in `block (2 levels) in <top (required)>' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/listener.rb:25:in `call' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:97:in `block (2 levels) in call_all_listeners' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:96:in `each' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:96:in `block in call_all_listeners' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:95:in `catch' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:95:in `call_all_listeners' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pluggaloid-1.1.1/lib/pluggaloid/event.rb:39:in `block in call' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/delayer-0.0.2/lib/delayer/procedure.rb:24:in `run' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/delayer-0.0.2/lib/delayer/extend.rb:58:in `run_once' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/delayer-0.0.2/lib/delayer/extend.rb:30:in `run' from /Users/akkie/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/delayer-0.0.2/lib/delayer.rb:43:in `method_missing' from {MIKUTTER_DIR}/core/plugin/gtk/delayer.rb:10:in `block in boot' from {MIKUTTER_DIR}/core/plugin/gtk/mainloop.rb:10:in `main' from {MIKUTTER_DIR}/core/plugin/gtk/mainloop.rb:10:in `mainloop' from mikutter.rb:68:in `boot!' from mikutter.rb:104:in `<main>'
実際にどういうタイミングならできるのかは不明(しばらく待てば出来るようになる?とか)です。
感覚的には起動直後のアカウント切り替えはできない印象です。
ただし、ショートカットキーからアカウントを切り替えることは起動直後でもできるようです。
ファイル
再現手順
起動直後にアカウント切り替えを画面左上のメニューからおこなう
toshi_a 初音 さんが6年以上前に更新
- ステータス を 分類待ち から 実装待ち に変更
起動直後に再現することを確認しました。
World系Modelが再生成されているようで、Portalのようなuriをちゃんと生成していないやつは、インスタンスが再生成されるたびに違うURIになるため、切り替え先のWorldと==メソッドで一致するWorldが見つからないという状態になってるようです。
やることとしては
- Worldのインスタンスは起動時一度だけ作ればいいので、何度も作られている原因を探り、一度だけにする
- RuntimeErrorじゃなくて、もうちょっと丁寧なエラーメッセージを出す
くらいかなぁ
toshi_a 初音 さんが6年以上前に更新
原因がわかりました。Twitter, World, Current World, GUIプラグインをそれぞれ修正するコミットをして、それぞれ検証していきます。
対応¶
Twitterプラグイン¶
uriメソッドを実装し、一意な値を返す。
Worldプラグイン¶
デバッグモード時、World slugが同じなのにuriが変わってしまうことを検出し、警告を出す。
今のところはWorldプラグインのドキュメントを書けていないため、このチケットのURLを表示する?
Current Worldプラグイン¶
RuntimeErrorではなく独自の例外を投げる。または、エラーメッセージを設定し、何が起こっているかを書く(切り替えようとしているWorldはリストに存在しない、といった内容)
切り替えはユーザによって行われるはずなので、失敗した場合には例外をstderrに出力するのもいいが、Activityでユーザにその旨を報告したほうが良いと思う。
GUIプラグイン¶
source:core/plugin/gtk/world_shifter.rb@707c4e65#L56 で、Worldリストがリフレッシュされるタイミングをイベントで監視し、それに合わせてGtkウィジェットを作り直している。
しかし、world_modifyで作り直される可能性は考慮されていない。厳密にはWorldリストは再生成しているので、world_modifyが発生したときにもリフレッシュすると今回の問題は緩和できる。
より良い解決策として、 source:core/plugin/world/world.rb@707c4e65#L90 のWorld Modelのリストを作り直したタイミングで、リスト内のWorldのuriが一つでも変わったら発生するイベントを新設して、World Shifterはそちらを利用するようにしたほうが良さそう。
サードパーティプラグイン¶
Twitterプラグインに行った実装を参考に、一意な値を返すようにWorld Modelのuriメソッドを再実装してもらう。
原因¶
world_modifyイベントなどでWorldが更新された時に実行される source:core/plugin/world/world.rb@707c4e65#L79 で、Worldリストが初期化されている。
次回Worldリストが要求された時にWorld Modelが作り直されて変更が反映されるが、作り直されるWorldがuriメソッドを実装していない場合、uriが毎回ランダムに生成される。
current_worldプラグインの source:core/plugin/current_world/current_world.rb@707c4e65#L42 では、 Enumerable#include? による比較を行っているため、uriが異なると対象のWorldが見つけられずRutimeErrorが発生する。こうなるとWorldの切り替えはできないため、World Shifterでアカウントを切り替えても反応がなく、切り替えができないという問題が起こる。
toshi_a 初音 さんが6年以上前に更新
- ファイル DeepinScreenshot_select-area_20180615091645.png DeepinScreenshot_select-area_20180615091645.png を追加
- ステータス を 実装待ち から レビュー待ち に変更
- 担当者 を Akira Ouchi にセット
- ブランチ を topic/1231-fix-rarely-world-shifter-does-not-work にセット
twitter, world, current_worldの変更は実装しました。
今回、この問題は私は再現できてません。 Akira Ouchi 以外でも、この問題が再現できていた人は確認してフィードバックをください。
変更内容と確認方法¶
Worldプラグイン¶
mikutterを起動した時に、標準エラー出力に以下のような出力が出ていれば、WorldのURIが定義されていないことを検出しているということになります。
warning: {MIKUTTER_DIR}/core/plugin/world/world.rb:114:in `block in check_world_uri': The URI of World `a20e42bd-8e5c-4d9b-b3bb-dc274935d840' is not defined. You must define a consistent URI for World Model. see: https://dev.mikutter.hachune.net/issues/1231
しかし、Twitter Worldは今回で対応を入れたので上記のようなエラーメッセージは出ません。Worldonもこのチケットを見て早々に対応されたようです。Portalプラグイン( https://github.com/toshia/portal )によるWorldが含まれていれば再現できます。
current_worldプラグイン¶
World Shifter(アカウント切り替えメニュー)でメニューからアカウントを選んだのにアカウントが切り替わらなかった時、アクティビティタブに「アカウントを切り替えようとしましたが、切り替えようとしたアカウントは存在しませんでした。」というようなメッセージが表示されます。
このシステムメッセージは、以下のコードをmikutterコンソールで実行すると確実に再現できます。
Plugin.call(:world_change_current, Skin['notfound.png'])
twitterプラグイン¶
World Shifterで、PortalなどのWorldに切り替え出来ない状態の時でも、Twitter Worldになら切り替えができるはずです。
GUIプラグインの変更をしなかったことについて¶
GUIプラグインですが、やはり筋が悪いかなと思い直して実装していません。
World Modelは同じ値をコンストラクタに与えられたら同じものが作られるべきです。
したがって内部的にWorld Modelのインスタンスが再生成されることを検出する意味はありません。
また、このような実装をしてしまうと、今後他のサードパーティプラグインもWorld Modelを特別扱いする必要が出てきて、余計なルールが増えます。worldやcurrent_worldに今回実装したように、World Modelにuriを定義することを促すような形のほうがスッキリすると思います。
Akira Ouchi さんが6年以上前に更新
- ステータス を レビュー待ち から まだダメ に変更
checkoutして確認しようとしたところ、以下のエラーでクラッシュしました。
/Users/akkie/mikutter/core/plugin/current_world/current_world.rb:17:in `block (2 levels) in <top (required)>': undefined method `uri' for nil:NilClass (NoMethodError)
コードを確認したところ、on_world_change_currentのrescueでnew.urlがなくてコケているように見えます。
(なんかこれが出るかどうかで再現してるしてないかが分かれていそうな気もしますね。)
newを使わないようにしてやると、こけなくなりました。
rescue Plugin::CurrentWorld::WorldNotfoundError activity :system, _('アカウントを存在しないアカウント(%{uri})に切り替えようとしました') % {uri: "あ"}, description: _('アカウントを切り替えようとしましたが、切り替えようとしたアカウントは存在しませんでした。') + "\n\n" + _("切り替え先のアカウント:\n%{uri}") % {uri: "あ"} + "\n\n" + _('現在存在するアカウント:') + "\n" + Enumerator.new{|y| Plugin.filtering(:worlds, y) }.map{|w| "#{w.slug} (#{w.uri})" }.to_a.join("\n") + "\n\n" + _('%{world_class}#uri を定義することでこのエラーを回避できます。詳しくは %{see} を参照してください') % {world_class: "い", see: 'https://dev.mikutter.hachune.net/issues/1231'}
情報量ゼロになるのでやくに立たないですが、一応こういう出力が起動直後に1つ出るようになります。
アカウントを切り替えようとしましたが、切り替えようとしたアカウントは存在しませんでした。 切り替え先のアカウント: あ 現在存在するアカウント: worldon:akkiesoft@social.mikutter.hachune.net (plugin://world.worldon/social.mikutter.hachune.net/akkiesoft/******) worldon:poop_parrot@social.mikutter.hachune.net (plugin://world.worldon/social.mikutter.hachune.net/poop_parrot/******) twitter34582322 (plugin://world.twitter/twitter******) 7958e4e8-4315-4b9e-9754-5e5fb7d06b2e (plugin://world.portal/******) haiku--3826178559572183616 (plugin://world.haiku/******) worldon:Akkiesoft@pawoo.net (plugin://world.worldon/pawoo.net/Akkiesoft/******) worldon:Akkeisoft@mstdn.maud.io (plugin://world.worldon/mstdn.maud.io/Akkeisoft/******) い#uri を定義することでこのエラーを回避できます。詳しくは https://dev.mikutter.hachune.net/issues/1231 を参照してください
printデバッグでnewを確認しても、まじで何も入ってないっぽかったです。
toshi_a 初音 さんが6年以上前に更新
- ステータス を まだダメ から レビュー待ち に変更
- 担当者 を toshi_a 初音 から Akira Ouchi に変更
nilガードは付けられるので付けてみました。
しかし、world_change_currentイベントの引数にnilが与えられる状況がわからないです。サードパーティプラグインなんかで、このイベントを発生させているものをインストールしてませんか。
Izumi Tsutsui さんが6年以上前に更新
とりあえずで
topic/1231-fix-rarely-world-shifter-does-not-work ba07605 をチェックアウト
worldon を fbdcab44 に更新 https://github.com/cobodo/mikutter-worldon/commit/fbdcab44f9b081a278948fc0f74d8d37958d6981
という状態、かつ、
1つ目のアカウントがマストドン
2つ目のアカウントが Twitter
という mikutter 設定でテストしてみました。
3回ほど起動してみた範囲では起動直後にそれぞれ world 変更できるようです。
元の 3.7.2 の環境では起動後しばらく(条件不明)はマストドンアカウントから Twitter に変更できませんでした。
topic/1231-fix-rarely-world-shifter-does-not-work と worldon の変更前 (6/9 くらい) の組み合わせでは
Twitter → マストドンへの変更ができない場合がありました。
ということで、こちらでは意図通り修正されているように見えます。
Akira Ouchi さんが6年以上前に更新
- ステータス を レビュー待ち から マージ待ち に変更
toshi_a 初音 さんは書きました:
nilガードは付けられるので付けてみました。
しかし、world_change_currentイベントの引数にnilが与えられる状況がわからないです。サードパーティプラグインなんかで、このイベントを発生させているものをインストールしてませんか。
https://github.com/namotch/world_primary のせいっぽそうです。
world_primaryを無効にしたらnilガード無しでも起動することを確認できました。
また、nilガードを適用した状態でworld_primaryを有効にしても起動できました。
cob odo さんが6年以上前に更新
mikutterを起動した時に、標準エラー出力に以下のような出力が出ていれば、WorldのURIが定義されていないことを検出しているということになります。
warning: {MIKUTTER_DIR}/core/plugin/world/world.rb:114:in `block in check_world_uri': The URI of World `a20e42bd-8e5c-4d9b-b3bb-dc274935d840' is not defined. You must define a consistent URI for World Model. see: https://dev.mikutter.hachune.net/issues/1231
しかし、Twitter Worldは今回で対応を入れたので上記のようなエラーメッセージは出ません。Worldonもこのチケットを見て早々に対応されたようです。Portalプラグイン( https://github.com/toshia/portal )によるWorldが含まれていれば再現できます。
こちらの環境でもこの方法で動作確認できました。world_primaryをインストールした状態でもクラッシュしていません。
また、最近のmikutterでは、起動後しばらくtwitterのリストによるストリーム受信ができていなかったように見受けられていたのですが、このパッチによって解消しているのも確認しました。