fix: improved server check

Included timeout, check url even if http is included, doc strings
This commit is contained in:
Fredrik Burmester
2024-09-16 21:15:57 +02:00
parent 5e141f27c4
commit 3577aae7cc

View File

@@ -80,40 +80,92 @@ const Login: React.FC = () => {
setLoading(false); setLoading(false);
} }
}; };
async function checkUrl(url: string) {
// remove trailing / so we don't double add double / in my checker
if (url.endsWith("/")) {
url = url.slice(0, -1);
}
if( await fetch("https://" + url + "/System/Info/Public", {mode: 'cors'}).then((response) => { const [loadingServerCheck, setLoadingServerCheck] = useState<boolean>(false);
return response.status;
}).catch((error) => { /**
console.log(error) * Checks the availability and validity of a Jellyfin server URL.
}) === 200) { *
return "https://"+url * This function attempts to connect to a Jellyfin server using the provided URL.
} else if (await fetch("http://" + url + "/System/Info/Public", {mode: 'cors'}).then((response) => { * It tries both HTTPS and HTTP protocols, with a timeout to handle long 404 responses.
return response.status; *
}).catch((error) => { * @param {string} url - The base URL of the Jellyfin server to check.
console.log(error) * @returns {Promise<string | undefined>} A Promise that resolves to:
}) === 200) { * - The full URL (including protocol) if a valid Jellyfin server is found.
return "http://"+url * - undefined if no valid server is found at the given URL.
*
* Side effects:
* - Sets loadingServerCheck state to true at the beginning and false at the end.
* - Logs errors and timeout information to the console.
*/
async function checkUrl(url: string) {
url = url.endsWith("/") ? url.slice(0, -1) : url;
setLoadingServerCheck(true);
const protocols = ["https://", "http://"];
const timeout = 2000; // 2 seconds timeout for long 404 responses
try {
for (const protocol of protocols) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(`${protocol}${url}/System/Info/Public`, {
mode: "cors",
signal: controller.signal,
});
clearTimeout(timeoutId);
if (response.ok) {
return `${protocol}${url}`;
}
} catch (e) {
const error = e as Error;
if (error.name === "AbortError") {
console.log(`Request to ${protocol}${url} timed out`);
} else {
console.error(`Error checking ${protocol}${url}:`, error);
}
}
}
return undefined;
} finally {
setLoadingServerCheck(false);
} }
return undefined;
} }
/**
* Handles the connection attempt to a Jellyfin server.
*
* This function trims the input URL, checks its validity using the `checkUrl` function,
* and sets the server address if a valid connection is established.
*
* @param {string} url - The URL of the Jellyfin server to connect to.
*
* @returns {Promise<void>}
*
* Side effects:
* - Calls `checkUrl` to validate the server URL.
* - Shows an alert if the connection fails.
* - Sets the server address using `setServer` if the connection is successful.
*
*/
const handleConnect = async (url: string) => { const handleConnect = async (url: string) => {
url = url.trim(); url = url.trim();
if (!url.startsWith("http")) {
const result = await checkUrl(url); const result = await checkUrl(
if (result === undefined){ url.startsWith("http") ? new URL(url).host : url
Alert.alert("Invalid URL", "Please enter a valid URL"); );
return;
} if (result === undefined) {
url = result; Alert.alert(
"Connection failed",
"Could not connect to the server. Please check the URL and your network connection."
);
return;
} }
console.log(url);
setServer({ address: url }); setServer({ address: result });
}; };
const handleQuickConnect = async () => { const handleQuickConnect = async () => {
@@ -150,7 +202,6 @@ const Login: React.FC = () => {
color="black" color="black"
onPress={() => { onPress={() => {
removeServer(); removeServer();
setServerURL("");
}} }}
justify="between" justify="between"
iconLeft={ iconLeft={
@@ -248,7 +299,12 @@ const Login: React.FC = () => {
maxLength={500} maxLength={500}
/> />
</View> </View>
<Button onPress={ async () => await handleConnect(serverURL)} className="mb-2"> <Button
loading={loadingServerCheck}
disabled={loadingServerCheck}
onPress={async () => await handleConnect(serverURL)}
className="mb-2"
>
Connect Connect
</Button> </Button>
</View> </View>
@@ -258,4 +314,3 @@ const Login: React.FC = () => {
}; };
export default Login; export default Login;