๐Ÿ’พ Archived View for bbs.geminispace.org โ€บ u โ€บ skyjake โ€บ 12258 captured on 2023-12-28 at 17:50:38. Gemini links have been rewritten to link to archived content

View Raw

More Information

โžก๏ธ Next capture (2024-02-05)

-=-=-=-=-=-=-

Comment by ๐Ÿš€ skyjake

Re: "I saw a comment by @clseibold earlier (hope I spelled that..."

In: u/Addison

When it comes to Lagrange, all requests are handled as streaming. That is, when a request is ongoing, incoming data is handled as it arrives and processed incrementally when possible.

However, currently there is a significant inefficiency with page layout. Whenever new data arrives, even if it's just a single byte, the entire page layout gets redone. This can mean lots of unnecessary work (measuring text runs, wrapping lines, etc.). I've been planning to refactor the document class to allow appending new lines to an existing layout, but it is not a trivial change.

Streaming media has some additional challenges because it depends on the codec and its API whether it's possible to provide the data as a stream. Often the APIs assume that streams are coming over HTTP(S) or some other bespoke streaming protocol, and that's a nice ready-made solution if you doing a web-based program. Decoding a Gemini stream in practice means streaming from a memory buffer managed by the client, which is a little more complicated.

๐Ÿš€ skyjake

Dec 04 ยท 4 weeks ago

19 Later Comments โ†“

๐Ÿ˜ˆ dimkr ยท Dec 04 at 07:46:

@clseibold The main difference is that some file formats require you to have the whole thing before you can show something, while others don't. gplaces streams gemtext to the screen and it can stream any content as long as the handler program accepts "-" as the file path and reads from stdin, but some applications that support this don't show the file immediately, only when they finish reading the whole thing. As far as I know, the "anything can be streamed" assumption is false and you'll have to handle this on a MIME type by MIME type basis.

๐Ÿš€ clseibold ยท Dec 04 at 07:48:

@dimkr That's true. But I would expect clients to detect what mimetypes are streamable, since this should be a mostly fixed list.

๐Ÿš€ clseibold ยท Dec 04 at 07:49:

@dimkr But, what I will say is that it doesn't matter in practice whether a particular filetype/mimetype is streamable or not, because we cannot detect if something is an infinite connection beforehand anyways.

Also, the thing that you are piping the file into should already know to wait until the end or not, so the browser doesn't actually need to know what mimetypes are streamable or not, as long as there's some way for the application to tell what the filetype is (which is usually done by reading magic bytes or whatever).

๐Ÿ˜ˆ dimkr ยท Dec 04 at 10:23:

@clseibold Yes, but not making this distinction means a UX problem: the user needs to know if the client is waiting for the end of the file (through a progress bar?) or filling a buffer before it can show something (a spinner?) or the buffer is empty because download has stalled (a spinner?) or everything is OK but the client is still receiving more data while displaying something. The client can delegate the work of displaying a file to some other component, be it a separate application or not, but it can be confusing for the user if the download part and the display part don't communicate so the client can't explain what's going on.

๐Ÿš€ clseibold ยท Dec 04 at 17:13:

@dimkr That's true. But I think you could get around this by specifying if something is a livestream in links and headings.

๐Ÿ Addison ยท Dec 04 at 18:20:

Rosy Crow runs into a problem similar to what @skyjake described. It's using the native Android WebView to render page contents, so all incoming Gemtext must first be transformed into a valid HTML document and sent to the embedded browser. Since HTML cannot be appended-to in a simple fashion, this means that the whole document has to be re-generated.

One workable solution in this case would be to add some javascript to manipulate the DOM as new content arrives. I will likely end up doing this at soem point, but it sounds like it will be a PITA to test.

Along the lines of what @dimkr was mentioning: while the matter of a malicious/slow server seems like an irrelevant corner-case; it's one of those problems that throws a wrench into the whole concept of just waiting for the server to close the connection. It also adds significant complexity to the UI/UX side of things:

If a host is drip-feeding me bytes:

๐Ÿš€ clseibold ยท Dec 04 at 18:38:

@Addison You make many good point. For the HTML thing - that's also a problem with other browsers that convert gemtext to HTML for their GUI framework. The best solution has always been to avoid doing this from the start, but that's easy to say and harder to do, lol. I don't really have a good answer for this.

For the other questions, I think there are two options available:

1. You could have a "stream" mode that the user has to turn on, and this will just infinitely hold the connection. When a server fails and doesn't close a connection (which I personally thing is highly unlikely), then the user would know this because content would stop forever.

2. Similar to above, but everything is in stream mode. The user would just know that things are broken when content stops forever.

I think this is really the best we can do in Gemini and there aren't any other solutions that are better. The only other option is to just force-close all connections after 24-hours of waiting, assuming most people don't stream for more than 24 hours.

๐Ÿš€ clseibold ยท Dec 04 at 18:53:

What if the user indicated they want to stream, but the server then *actually* fails for some other reason and never kills the connection?

I also think this can just happen in every protocol. A client cannot know that a stream is down unless the server kills the connection, so this is a problem with every livestreaming protocol.

There could be some fancy things that more advanced livestreaming protocols do that I don't know about, I suppose.

All of these problems do make me wonder if we should make a livestreaming protocol companion to gemini... Maybe this would help.

๐Ÿ˜ˆ dimkr ยท Dec 05 at 06:33:

@Addison you can't distinguish between a troll server that sends the document x bytes at a time to annoy you, and a server that "streams" the response in chunks but sometimes network latency is higher or reliability is lower. And this is also true for streaming of audio and video, not just gemtext. The only "solution" is having socket timeouts (for sending and receiving) so the transfer fails if nothing is received (or acknowledged) for some time, but also per-session timeout (so download fails after a while if the server keeps sending more data but the file is really big or endless).

๐Ÿš€ clseibold ยท Dec 05 at 16:08:

@dimkr I thought about this timeout system, but what happens if a streaming server (like my chat) doesn't send text over because nobody sent a message. Is there some other way to keep connections alive *without* sending over text data?

๐Ÿ˜ˆ dimkr ยท Dec 05 at 17:43:

@clseibold Maybe TCP keepalives, but a client may close a session after some deadline regardless of last I/O time, or terminate sessions based on time since last I/O (last packet carrying more data to display) instead of time since the last packet (including keepalive packets). Gemini is not really designed for streaming, it can be done but you need to make assumptions about the client and that means a capsule marked 'works best with x', like old sites built with IE in mind.

๐Ÿš€ clseibold ยท Dec 05 at 18:00:

@dimkr Right. I was trying to get at keep alive packets. I use them, but I don't know much about how they work. A system that assumes a timeout with just the data will not take into account these keepalive packets.

I do disagree that Gemini is not designed for livestreaming (which isn't the same as all streaming - streams that support seeking are very different from livestreams). It works perfectly fine for streaming and the protocol explicitly mentions that it supports streaming. I was there when it was added to the protocol spec.

The difference is support for streaming was *optional* rather than required, which is why we have clients that don't support it. But I do not consider this a real problem, because not all browsers support displaying all filetypes either, that's just how browsers work.

If we think about it, all TCP connections *are* streams. Livestreaming just requires sending bits over a TCP stream over a certain time period. This is why mp3s and oggs have their metadata at the front, so that this is possible. Mp4 file data can also be split up and rearranged so that you can stream them as well.

It is the seeking of a stream that requires specific protocol stuff, but livestreams don't use seeking, that's only streams of on-demand content.

๐Ÿš€ clseibold ยท Dec 05 at 18:05:

@dimkr In fact, the idea of "this site works best with X" was a specific sub-goal that Solderpunk had in mind, to a limited extent. The idea was never to *limit* Gemini to only gemtext! The idea was that all browsers support a baseline but could do other things on top of that. This idea was explicitly outlined in Solderpunk's "A vision for Gemini applications" article:

gemini://gemini.circumlunar.space/users/solderpunk/gemlog/a-vision-for-gemini-applications.gmi

It is also the reason why gemini had the mimetype field - so that browsers could support different filetypes and aren't limited to gemtext only.

With this gemini applications idea, a gemini site could be tailored to a specific application (or rather, a specific application could make use of a gemini site in a specific way). He also outlines gemtext streaming here, and literally thought up Mozz's chat design originally (from chat.mozz.us).

Anyways, it looks like TCP keepalive packets solve a lot of problems.

๐Ÿ˜ˆ dimkr ยท Dec 06 at 07:53:

@clseibold I see things differently, I think that supporting a MIME type is one thing, but assumptions about client behavior is another. For example, some capsules have links that align nicely in Lagrange, and Station expects a client certificate for / although it's /join that returns 60 (Lagrange defaults to certificates for /, so it "just works"). In gplaces, I had to mimic Lagrange in some corner cases - for example, only warn, not show an error, if a capsule doesn't send close_notify like the spec says. I don't like capsules that work better with a specific client, or only with a specific client.

๐Ÿš€ clseibold ยท Dec 06 at 16:57:

@dimkr My point wasn't really whether that was good or not, but that it's how the spec was designed. Stream-like handling is optional in the spec. That's how it was designed.

The spec isn't all-encompasing - a lot of times it allows for *optional things.* A browser can support streaming, it can support different filetypes, it can even display things differently than other clients (headings in lagrange look very different from other browsers, so I make sure to tailor my headings for lagrange first).

How certificates behave is a completely different thing from supporting streaming, imo, so I think it is a false comparison. However, I believe certificates are optional in the spec too.

Peronally, I would require that all clients need to *support* TCP Keep Alive packets when they are used (and I bet many clients already do this), and then the problem we discussed about misbehaving clients would basically be fixed.

Update: Yes, I was correct. Client certificates are completely optional in the spec:

Basic clients may also choose not to support client-certificate authentication, in which case only four distinct status handling routines are required (for statuses beginning with 1, 2, 3 or a combined 4-or-5).

Also from the spec, notice how it's **optional**:

Note that clients are not obligated to wait until the server closes the connection to begin handling the response. This is shown above only for simplicity/clarity, to emphasise that responsibility for closing the connection under typical conditions lies with the server and that the connection should be closed immediately after the completion of the response body.
For example, some capsules have links that align nicely in Lagrange, and Station expects a client certificate for / although it's /join that returns 60 (Lagrange defaults to certificates for /, so it "just works").

The way I see it is this: There's nothing that says that clients cannot use certificates on links that don't request a certificate. Whetehr station expects a client cert for / or /join isn't a client problem, because the client is allowed to use certs on pages that don't request certs, and to lagrange, / encompasses /join.

Which means this is a server problem, not a client problem, because a **server** can only expect a cert to be used on the pages they are requested for.

So it should be reported to the server maintainer/developer, not the client developer, imo.

๐Ÿš€ clseibold ยท Dec 06 at 17:20:

@dimkr Btw, and @skyjake can correct me on this if I'm wrong, but I'm pretty sure lagrange used to only enable certificates on the specific page (like "/join") when that page requested it (and the user enabled the cert from there), rather than always putting it on /. And if I recall correctly, it was the server developers (including me) who didn't realize that we couldn't expect certs on "/" when we only sent the request on "/join" (or "/register").

I ended up fixing this for some of my AuraGem stuff by using "/?register" instead, so that the client cert request always happens on "/", but not all servers fixed this problem, so clients have to adapt to the servers.

So I think the history is actually the opposite - servers started expecting cert requests on subpages to be working for the whole capsule, and clients had to adapt to make this work, instead of the other way around.

I specifically remember running into this problem with one of my AuraGem services, and so I had to fix it on my server, because it was a server bug, not a client bug.

๐Ÿš€ skyjake ยท Dec 06 at 19:38:

Yes you are correct about the history @clseibold.

This reminds me I should use the "/?register" solution myself in Bubble, because having an actual "Create Account" UI action beats the current "just activate a certificate but please only at the root".

๐Ÿ˜ˆ dimkr ยท Dec 07 at 07:23:

@clseibold @skyjake This history shows how much "wiggle room" the spec has, allowing clients to behave very differently from each other, until clients and servers achieve some status quo not mandated by the spec. I know that my client (and probably many others) doesn't support "chat" because it previews the document during download but shows the prompt that allows you to navigate to a link only when transfer is finished.

๐Ÿš€ clseibold ยท Dec 07 at 17:35:

@dimkr I agree that the spec has quite a bit of wiggle room. However, I think the situation with where certs are activated is just an oversight in the spec. One could fix this by just saying under the client certs sections that "A server can only expect a client cert to be activated under the path in which the client cert request status code was sent" or something along those lines.

Lots of clients don't support streaming gemtext in general because it was marked optional. I think the best solution for this is to just go with Solderpunk's idea written in the article I linked ("A vision for Gemini applications") - I can create a chat terminal program specifically for AuraGem Live Chat.

Original Post

๐Ÿ Addison

I saw a comment by @clseibold earlier (hope I spelled that right) talking about streaming audio capabilities in mobile Gemini clients. I can't seem to find the post anymore, but it got me thinking about whether Opal (the client library that Rosy Crow uses to do it's Gemini stuff) can support that. [https link] Currently it does not support that, because the entire response is read all at once into a buffer. Thinking about this a while, I of course arrived at the classic conclusion that...

๐Ÿ’ฌ 24 comments ยท 2 likes ยท Dec 04 ยท 4 weeks ago