8000 Need supported way to "steal" socket from requests library for mp3 streaming · Issue #198 · adafruit/Adafruit_CircuitPython_Requests · GitHub
[go: up one dir, main page]

Skip to content

Need supported way to "steal" socket from requests library for mp3 streaming #198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jepler opened this issue Jul 1, 2024 · 8 comments · Fixed by #199
Closed

Need supported way to "steal" socket from requests library for mp3 streaming #198

jepler opened this issue Jul 1, 2024 · 8 comments · Fixed by #199

Comments

@jepler
Copy link
Contributor
jepler commented Jul 1, 2024

Right now I do this:

def get_mp3_stream():
    if STREAMING_URL.startswith("http:") or STREAMING_URL.startswith("https:"):
        return requests.get(STREAMING_URL, headers={"connection": "close"}).socket
    return open(STREAMING_URL, "rb")

but

  • the socket property is not documented and not in standard requests
  • this has no way of properly releasing the socket at the ConnectionManager level

The real requests library has a public raw property that calling code may use when the request includes stream=True. So simply renaming the socket property to raw would be one step in the right direction. (the stream argument is already supported in adafruit_requests)

        #: File-like object representation of response (for advanced usage).
        #: Use of ``raw`` requires that ``stream=True`` be set on the request.
        #: This requirement does not apply for use internally to Requests.
        self.raw = None

As for properly releasing the socket, I guess I need to restructure my code so it can hold onto the requests object as long as needed.

@justmobilize
Copy link
Collaborator

Isn't the raw object a urllib3.response.HTTPResponse? So not really the socket.

In json() we set:

self._raw = _RawResponse(self)

And _RawResponse has read. Could we do something similar if it's a stream?

@jepler
Copy link
Contributor Author
jepler commented Jul 1, 2024

It is a HTTPResponse object in standard Python, but it supports the read method (and not recv):

>>> response = requests.get("http://example.com", headers={'connection': 'close', 'accept-encoding': ''}, stream=True)
>>> response.raw
<urllib3.response.HTTPResponse object at 0x7f23ee80be50>
>>> response.raw.read(32)
b'<!doctype html>\n<html>\n<head>\n  '
>>> response.raw.recv
AttributeError: 'HTTPResponse' object has no attribute 'recv'

In CicuitPython a socket object supports recv and not read at the Python level, so the API still doesn't match. Small consolation then that for "my code" (MP3Decoder which uses C calls that work for a built in file or for a built in socket) doesn't care.

and I don't want to add a type to Requests that wraps a socket to provide read in terms of recv. For my purposes, an intermediate object, especially one coded in Python code, is undesirable, because dropping back into arbitrary Python code from a background task causes problems and we avoid it whenever possible.

@jepler
Copy link
Contributor Author
jepler commented Jul 1, 2024

if we just decide to document the socket property as a CircuitPython extension that's fine by me.

@justmobilize
Copy link
Collaborator

I understand not wanting to pass the wrapper to have read.

Although for CircuitPython, returning the socket as raw would break anything written in python...

@justmobilize
Copy link
Collaborator

Also, any desire to do this the standard way:

socket.fromfd(response.raw.fileno(), socket.AF_INET, socket.SOCK_STREAM)

I know fileno isn't currently supported...

@dhalbert
Copy link
Contributor
dhalbert commented Jul 1, 2024

This FAQ, https://requests.readthedocs.io/en/latest/community/faq/#encoded-data, says

You can get direct access to the raw response (and even the socket), if needed as well.

Is socket.fromfd() what they mean?

@justmobilize
Copy link
Collaborator

socket.fromfd() is what I've used in CPython.

@jepler
Copy link
Contributor Author
jepler commented Jul 1, 2024

file numbers really aren't a thing in circuitpython, though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants
0