kannibalox / pyrosimple

An overhauled fork of the pyrocore tools for rTorrent
https://kannibalox.github.io/pyrosimple/
GNU General Public License v3.0
52 stars 5 forks source link

RPC errors with rtcontrol #72

Closed fffe closed 6 days ago

fffe commented 2 months ago

I'm unable to fetch or filter on the trackers field with rtcontrol, using the current version of pyrosimple against the current master branches of (vanilla) rtorrent/libtorrent.

(test_venv) username@host:~$ rtcontrol --from-view=0123456789012345678901234567890123456789 tracker='*tracker1.net*,*tracker2.net*,*tracker3.net*'
Traceback (most recent call last):
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/torrent/rtorrent.py", line 833, in items
    raise rpc.RpcError(f"Errors in system.multicall: {uniq_errors}")
pyrosimple.util.rpc.RpcError: <RpcError -500: 'Errors in system.multicall: {\'{\\\'faultCode\\\': -506, \\\'faultString\\\': "Method \\\'t.multicall=,t.url=,t.is_enabled\\\' not defined"}\'}'>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/base.py", line 184, in run
    self.mainloop()
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/rtcontrol.py", line 845, in mainloop
    matches = futures[url].get()
              ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 774, in get
    raise self._value
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 125, in worker
    result = (True, func(*args, **kwds))
                    ^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/rtcontrol.py", line 836, in fetch
    matches = list(e.items(view=view, prefetch=prefetch))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/torrent/rtorrent.py", line 896, in items
    raise error.EngineError(
pyrosimple.error.EngineError: While getting download items from RtorrentEngine connected to host:12345 [rTorrent 0.13.8/0.9.8] via 'scgi+unix:///home/username/rtorrent/.scgi_local': <RpcError -500: 'Errors in system.multicall: {\'{\\\'faultCode\\\': -506, \\\'faultString\\\': "Method \\\'t.multicall=,t.url=,t.is_enabled\\\' not defined"}\'}'>

Without the filter, this displays the torrent as expected. I'm not sure why this is failing, as those methods appear to exist:

(test_venv) username@host:~$ rtxmlrpc system.listMethods | egrep -i '^t\.(multicall|url|is_enabled)'
t.is_enabled
t.is_enabled.set
t.multicall
t.url

I'm getting a similar error trying to format output as JSON:

(test_venv) username@host:~$ rtcontrol --json --from-view=complete //
Traceback (most recent call last):
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/util/rpc.py", line 133, in __request_xml
    response = self.__transport.request(
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/io/scgi.py", line 165, in request
    return self.parse_response(io.BytesIO(response))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/io/scgi.py", line 59, in parse_response
    return super().parse_response(response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/xmlrpc/client.py", line 1351, in parse_response
    return u.close()
           ^^^^^^^^^
  File "/usr/lib/python3.12/xmlrpc/client.py", line 668, in close
    raise Fault(**self._stack[0])
xmlrpc.client.Fault: <Fault -506: "Method 'd.session_file' not defined">

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/username/test_venv/bin/rtcontrol", line 8, in <module>
    sys.exit(run())
             ^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/rtcontrol.py", line 1055, in run
    RtorrentControl().run()
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/base.py", line 184, in run
    self.mainloop()
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/rtcontrol.py", line 980, in mainloop
    {name: getattr(i, name) for name in list(engine.FIELD_REGISTRY)}
           ^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/torrent/engine.py", line 258, in __get__
    self._accessor(obj)
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/torrent/engine.py", line 562, in <lambda>
    accessor=lambda o: os.path.expanduser(str(o.rpc_call("d.session_file"))),
                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/torrent/rtorrent.py", line 209, in rpc_call
    val = getter(self._fields["hash"], *args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/xmlrpc/client.py", line 1122, in __call__
    return self.__send(self.__name, args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/util/rpc.py", line 242, in __request
    return self.__request_switch(methodname, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/util/rpc.py", line 268, in __request_switch
    raise exc
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/util/rpc.py", line 260, in __request_switch
    return self.__request_xml(methodname, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/util/rpc.py", line 137, in __request_xml
    raise RpcError(exc.faultString, exc.faultCode) from exc
pyrosimple.util.rpc.RpcError: <RpcError -506: "Method 'd.session_file' not defined">

This time the method doesn't exist:

(test_venv) username@host:~$ rtxmlrpc system.listMethods | egrep -i '^d.session_file'
(test_venv) username@host:~$

Is this a bug or have I skipped a step somewhere?

fffe commented 2 months ago

... the filtering appears to work inconsistently.

rtcontrol is_complete=yes is_open=yes is_ignored=no tracker=\*trackerthatexists.net\* -q displays a list of all torrents from that tracker, as expected.

rtcontrol is_complete=yes is_open=yes is_ignored=no tracker=\*nothingusesme.net\*,\*trackerthatexists.net\* -q shows nothing, which is unexpected.

In my postprocessing scripts (previously working on rt-ps) this used to be treated as an OR; I used it for filtering torrents that matched any of a handful of trackers.

It looks like either it's being treated as an AND here, or it's just silently failing. I'm not sure which.

fffe commented 2 months ago

Okay, I had been missing the rtorrent config, but filtering on trackers is still breaking as described above.

kannibalox commented 2 months ago

Is this a bug or have I skipped a step somewhere?

By default --json tries to output all fields, which includes a field that expects the custom command d.session_file. It's a simple method, and definition is available here, but I'll probably rewrite it to not depend on that. In general a full --json is going to be pretty heavy, I'd recommend combining it with -o to limit the fields being fetched.

rtcontrol is_complete=yes is_open=yes is_ignored=no tracker=\*nothingusesme.net\*,\*trackerthatexists.net\* -q shows nothing, which is unexpected.

Here the , is being treated as part of the search string, it doesn't have any special OR significance. Try: rtcontrol is_complete=yes is_open=yes is_ignored=no [ tracker=\*nothingusesme.net\* OR tracker=\*trackerthatexists.net\* ]

Alternatively, you can accomplish the same goal with regexes: rtcontrol is_complete=yes is_open=yes is_ignored=no tracker=/nothingusesme.net\|trackerthatexists.net/

fffe commented 2 months ago

Yeah, I screwed up. I didn't realize there were additional steps beyond just installing the python bits.

Try: rtcontrol is_complete=yes is_open=yes is_ignored=no [ tracker=*nothingusesme.net* OR tracker=*trackerthatexists.net* ]

This throws an error. I tried a couple of different things in case I was missing some escaping, but I always get the same error:

username@host:~/bin$ rtcontrol is_complete=yes is_open=yes is_ignored=no [ tracker=\*nothingusesme.net\* OR tracker=\*trackerthatexists.net\* ] fno=1
username@host:~/bin$ rtcontrol is_complete=yes is_open=yes is_ignored=no [ tracker=\*nothingusesme.net\* OR tracker=\*trackerthatexists.net\* ] fno=1
Traceback (most recent call last):
  File "/home/username/test_venv/bin/rtcontrol", line 8, in <module>
    sys.exit(run())
             ^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/rtcontrol.py", line 1055, in run
    RtorrentControl().run()
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/base.py", line 184, in run
    self.mainloop()
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/scripts/rtcontrol.py", line 787, in mainloop
    self.log.debug("Matcher is: %s", matcher.to_match_string())
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/test_venv/lib/python3.12/site-packages/pyrosimple/util/matching.py", line 193, in to_match_string
    child_strings = [c.to_match_string() for c in self.children]
                     ^^^^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'to_match_string'

Alternatively, you can accomplish the same goal with regexes: rtcontrol is_complete=yes is_open=yes is_ignored=no tracker=/nothingusesme.net|trackerthatexists.net/

This worked, thanks.

Is this a functional change from pyrocore? That comma syntax works/worked on my old rt-ps setup.

kannibalox commented 2 months ago

This throws an error. I tried a couple of different things in case I was missing some escaping, but I always get the same error:

This is happening because of the fno=1 at the end. I'll have to dig into exactly why that is, it's definitely a bug, but moving that to the front of the filters seems to make it work.

Is this a functional change from pyrocore? That comma syntax works/worked on my old rt-ps setup.

Indeed it is, I've never really used the feature so I missed documenting it's removal, that's been add to the migration page now: https://github.com/kannibalox/pyrosimple/commit/7468517c0c7b396a41d8c0a4d74518845b874190

kannibalox commented 6 days ago

I've documented the change in behavior and fixed the associated bug, closing this out.