Closed binyamin closed 3 years ago
which program hangs? the client?
please post a script that i can use to reproduce the problem.
const request = require('@derhuerst/gemini/client.js');
const defaultOpts = {
followRedirects: true,
verifyAlpnId: () => true,
tlsOpt: {
rejectUnauthorized: false
}
};
function gemfetch(url) {
return new Promise((resolve, reject) => {
request(url, defaultOpts, (err, res) => {
if(err) {
reject(err);
}
res.once("readable", () => {
const doc = String(res.read());
resolve(doc);
})
})
})
}
gemfetch("gemini://binyam.in")
.then(res => {
console.log(res)
}).catch(err => {
throw err;
})
By listening on readable
and using read()
, you're switching res
to non-flowing mode, which in itself is not a problem (for small responses). But read()
does not wait until there's data. When you call it, returns whatever is currently buffered in res
(which is more or less what the client has received since the last read()
call). If there's no response body immediately (either because the server didn't immediately respond with it, or because of network delays), then your first read()
call will return null
.
There are multiple ways to fully read a readable stream, but since you just want to concatenate all data into a string, this is the simplest way:
let doc = ''
res.on('data', chunk => {
doc += chunk
})
res.once('end', () => {
resolve(doc)
})
Also, reject()
does not stop the calling function from continuing to run, it is just a regular function. Therefore, your code will try to read from res
even if err
contains an error. If you return
after calling reject(err)
, you will see the original ETIMEDOUT
error.
If you just want to send Gemini requests in fetch
style (like your code demonstrates above), use gemini-fetch
, it is a thin layer on top of this library.
I've just re-read your original question: Is this Issue about a server that doesn't even accept the request? As in, the TLS connection attempt times out?
As of @derhuerst/gemini@1.2.0
, you can now pass connectTimeout
to request()
:
const request = require('@derhuerst/gemini/client.js');
function gemfetch(url) {
return new Promise((resolve, reject) => {
request(url, {
connectTimeout: 10 * 1000, // 10s
}, (err, res) => {
if(err) {
reject(err);
return;
}
let doc = ''
res.on('data', (chunk) => {
doc += chunk;
})
res.once('end', () => {
resolve(doc);
})
})
})
}
gemfetch("gemini://binyam.in")
.then(res => {
console.log(res)
})
.catch(err => {
console.error(err);
process.exit(1)
})
@derhuerst Thank you. As I mentioned, it's a browser for gemini. How would you recommend I connect to the servers? Does it make sense to use gemini-fetch for each URI?
Is the browser supposed to handle large files? If yes, use a stream-based approach. Otherwise I think something like gemini-fetch
will be a more convenient API.
I hadn't thought about file size. I'll probably use gemini-fetch
. Thank you again.
yeah, a stream based API is only relevant if a) you want to download/display files larger than the memory you want to use up, or b) if you want to start parsing/processing/rendering the file before it has finished downloading.
Context: If I fetch a URL which does not exist, the program seems to hang for around 2 minutes before giving me an error. I want to set it to something shorter.