Repos / mcross / 1f361980b5
commit 1f361980b5c3a01162a6f4a996162b27a1608f1f
Author: Bùi Thành Nhân <hi@imnhan.com>
Date:   Sun May 31 17:10:42 2020 +0700

    show request time status, add request timeout

diff --git a/pyproject.toml b/pyproject.toml
index f57b036..77e2e7a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "mcross"
-version = "0.5.10"
+version = "0.5.11"
 description = "Do you remember www?"
 authors = ["nhanb <hi@imnhan.com>"]
 license = "MIT"
diff --git a/src/mcross/gui/controller.py b/src/mcross/gui/controller.py
index 7a6662c..3c90421 100644
--- a/src/mcross/gui/controller.py
+++ b/src/mcross/gui/controller.py
@@ -1,5 +1,6 @@
 import logging
 import threading
+import time
 import traceback
 from ssl import SSLCertVerificationError
 from tkinter import READABLE, Tk, messagebox
@@ -7,6 +8,7 @@
 import curio
 
 from ..transport import (
+    MAX_REQUEST_SECONDS,
     GeminiUrl,
     NonAbsoluteUrlWithoutContextError,
     UnsupportedProtocolError,
@@ -122,6 +124,16 @@ async def visit_link(self, url: GeminiUrl):
             self.model.history.visit(resp.url)
             await self.put_gui_op(self.view.render_page)
 
+        except curio.errors.TaskTimeout:
+            await self.put_gui_op(
+                statusbar_logger.info, f"Request timed out: {MAX_REQUEST_SECONDS}s",
+            )
+            await self.put_gui_op(
+                messagebox.showwarning,
+                "Request timed out",
+                f"Request to {url.without_protocol()} took longer than {MAX_REQUEST_SECONDS}s",
+            )
+
         except (ConnectionError, OSError) as e:
             await self.put_gui_op(statusbar_logger.info, str(e))
             raise
@@ -138,14 +150,13 @@ async def forward_callback(self):
 
     async def load_page(self, url: GeminiUrl):
         await self.put_gui_op(statusbar_logger.info, f"Requesting {url}...")
+        start = time.time()
         resp = await get(url)
-        await self.put_gui_op(statusbar_logger.info, f"{resp.status} {resp.meta}")
-
-        async def clear_status_bar_later():
-            await curio.sleep(2)
-            await self.put_gui_op(statusbar_logger.info, "")
-
-        await curio.spawn(clear_status_bar_later(), daemon=True)
+        request_time = time.time() - start
+        await self.put_gui_op(
+            statusbar_logger.info,
+            f"{resp.status} {resp.meta} (took {request_time:.2f}s)",
+        )
 
         if resp.status.startswith("2"):
             await self.put_gui_op(self.model.update_content, resp.body.decode())
diff --git a/src/mcross/transport.py b/src/mcross/transport.py
index 9031cc9..c925baa 100644
--- a/src/mcross/transport.py
+++ b/src/mcross/transport.py
@@ -7,6 +7,7 @@
 MAX_RESP_HEADER_BYTES = 2 + 1 + 1024 + 2  # <STATUS><whitespace><META><CR><LF>
 MAX_RESP_BODY_BYTES = 1024 * 1024 * 5
 MAX_REDIRECTS = 3
+MAX_REQUEST_SECONDS = 30
 
 
 class Response:
@@ -142,7 +143,7 @@ async def raw_get(url: GeminiUrl):
 
 
 async def get(url: GeminiUrl, redirect_count=0):
-    resp = await raw_get(url)
+    resp = await curio.timeout_after(MAX_REQUEST_SECONDS, raw_get, url)
     if resp.status.startswith("3") and redirect_count < MAX_REDIRECTS:
         redirect_count += 1
         new_url = GeminiUrl.parse_absolute_url(resp.meta)