{"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-675610275", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 675610275, "node_id": "MDEyOklzc3VlQ29tbWVudDY3NTYxMDI3NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-08-18T17:24:05Z", "updated_at": "2020-08-18T17:26:10Z", "author_association": "OWNER", "body": "Maybe I can do this with ASGI after all. Here's the output of `/-/asgi-scope` with `datasette-debug-asgi` installed:\r\n```\r\n{'asgi': {'spec_version': '2.1', 'version': '3.0'},\r\n 'client': ('127.0.0.1', 62035),\r\n 'headers': [(b'host', b'127.0.0.1:62029'),\r\n (b'user-agent',\r\n b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko'\r\n b'/20100101 Firefox/79.0'),\r\n (b'accept',\r\n b'text/html,application/xhtml+xml,application/xml;q=0.9,image/'\r\n b'webp,*/*;q=0.8'),\r\n (b'accept-language', b'en-US,en;q=0.5'),\r\n (b'accept-encoding', b'gzip, deflate'),\r\n (b'dnt', b'1'),\r\n (b'connection', b'keep-alive'),\r\n (b'upgrade-insecure-requests', b'1'),\r\n (b'cache-control', b'max-age=0')],\r\n 'http_version': '1.1',\r\n 'method': 'GET',\r\n 'path': '/-/asgi-scope',\r\n 'query_string': b'',\r\n 'raw_path': b'/-/asgi-scope',\r\n 'root_path': '',\r\n 'scheme': 'http',\r\n 'server': ('127.0.0.1', 62029),\r\n 'type': 'http'}\r\n```\r\nThat `'server': ('127.0.0.1', 62029)` bit has the correct port. Question is, can I access that programmatically on server startup?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-675609109", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 675609109, "node_id": "MDEyOklzc3VlQ29tbWVudDY3NTYwOTEwOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-08-18T17:21:51Z", "updated_at": "2020-08-18T17:21:51Z", "author_association": "OWNER", "body": "Asked about this on the encode gitter here: https://gitter.im/encode/community?at=5f3c0dcaa8c17801765940c0", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-651203178", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 651203178, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MTIwMzE3OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T15:44:38Z", "updated_at": "2020-06-29T15:44:54Z", "author_association": "OWNER", "body": "I'm having real trouble figuring out how to gain access to the port that was used to start the server. I'm treating this as a very low priority - it only affects the exact `-p 0 --root` combination which isn't going to affect many people at all.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-651193594", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 651193594, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MTE5MzU5NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T15:27:46Z", "updated_at": "2020-06-29T15:27:46Z", "author_association": "OWNER", "body": "Uninstalling `datasette-debug-asgi` caused the server to startup correctly again.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-651193131", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 651193131, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MTE5MzEzMQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T15:27:00Z", "updated_at": "2020-06-29T15:27:00Z", "author_association": "OWNER", "body": "Aha! Yes it's not being called, and the reason is this: https://github.com/encode/starlette/issues/486\r\n\r\nShort version: by default an exception raised during that phase is silently swallowed! You can avoid the swallowing by adding `lifespan=\"on\"` to the call to `uvicorn.run()`.\r\n\r\nWhen I did that here:\r\n\r\n`uvicorn.run(ds.app(), host=host, port=port, log_level=\"info\", lifespan=\"on\")`\r\n\r\nThe server failed to start with this error:\r\n\r\n```\r\nINFO: Started server process [68849]\r\nINFO: Waiting for application startup.\r\nERROR: Exception in 'lifespan' protocol\r\nTraceback (most recent call last):\r\n File \".../uvicorn/lifespan/on.py\", line 48, in main\r\n await app(scope, self.receive, self.send)\r\n File \".../uvicorn/middleware/proxy_headers.py\", line 45, in __call__\r\n return await self.app(scope, receive, send)\r\n File \".../datasette_debug_asgi.py\", line 9, in wrapped_app\r\n if scope[\"path\"] == \"/-/asgi-scope\":\r\nKeyError: 'path'\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650910137", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650910137, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkxMDEzNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:16:32Z", "updated_at": "2020-06-29T05:16:32Z", "author_association": "OWNER", "body": "I'm not convinced that function is ever actually being called - I added a `print()` statement to it and it's not executing. I don't think the tests cover it.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650909476", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650909476, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwOTQ3Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:14:08Z", "updated_at": "2020-06-29T05:14:08Z", "author_association": "OWNER", "body": "I already have a `AsgiLifespan` class:\r\nhttps://github.com/simonw/datasette/blob/35aee82c60b2c9a0185b934db5528c8bd11830f2/datasette/app.py#L896-L905\r\n\r\nIt runs this function: https://github.com/simonw/datasette/blob/35aee82c60b2c9a0185b934db5528c8bd11830f2/datasette/app.py#L890-L894\r\n\r\nCould that startup function also output the `--root` login URL, if needed?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650909136", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650909136, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwOTEzNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:12:58Z", "updated_at": "2020-06-29T05:12:58Z", "author_association": "OWNER", "body": "On startup Datasette currently outputs:\r\n```\r\nINFO: Waiting for application startup.\r\nINFO: ASGI 'lifespan' protocol appears unsupported.\r\nINFO: Application startup complete.\r\n```\r\nSo the ASGI lifespan protocol is almost certainly the right way to solve this.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650908854", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650908854, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwODg1NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:12:04Z", "updated_at": "2020-06-29T05:12:04Z", "author_association": "OWNER", "body": "Can I detect the port the server is running on from within the regular Datasette ASGI code? If so I could use that ability and maybe output the magic `--root` link a second after the server starts up somehow.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650908534", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650908534, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwODUzNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:11:06Z", "updated_at": "2020-06-29T05:11:06Z", "author_association": "OWNER", "body": "Uvicorn's lifespan stuff isn't easy to figure out, but this test suite holds some clues: https://github.com/encode/uvicorn/blob/master/tests/test_lifespan.py", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650907323", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650907323, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwNzMyMw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:07:16Z", "updated_at": "2020-06-29T05:07:16Z", "author_association": "OWNER", "body": "This line is interesting: is this a hook I can attach to somehow?\r\n```python\r\n await self.lifespan.startup()\r\n```\r\nFrom https://github.com/encode/uvicorn/blob/a75fe1381f6b1f78901691c71894f3cf487b5d30/uvicorn/main.py#L475", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650906533", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650906533, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwNjUzMw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:04:44Z", "updated_at": "2020-06-29T05:04:44Z", "author_association": "OWNER", "body": "The challenge is... can we run our own custom code after that line has executed that has access to `server` and can hence access `server.servers[0].sockets[0].getsockname()[1]` to find the port?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650906318", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650906318, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwNjMxOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:04:04Z", "updated_at": "2020-06-29T05:04:12Z", "author_association": "OWNER", "body": "Within uvicorn it does this:\r\n```python\r\n if port == 0:\r\n port = server.sockets[0].getsockname()[1]\r\n```\r\nThat `server` variable is later stashed here:\r\n```\r\nself.servers = [server]\r\n```\r\nWhere `self` is the instance of `class Server` - which is the class that Uvicorn instantiates and calls `.run()` on when we do `uvicorn.run()` here: https://github.com/simonw/datasette/blob/35aee82c60b2c9a0185b934db5528c8bd11830f2/datasette/cli.py#L409", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/873#issuecomment-650905399", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/873", "id": 650905399, "node_id": "MDEyOklzc3VlQ29tbWVudDY1MDkwNTM5OQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-29T05:01:03Z", "updated_at": "2020-06-29T05:01:03Z", "author_association": "OWNER", "body": "This is a bit tricky to fix. This change to uvicorn is relevant: https://github.com/encode/uvicorn/commit/a75fe1381f6b1f78901691c71894f3cf487b5d30", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 647095487, "label": "\"datasette -p 0 --root\" gives the wrong URL"}, "performed_via_github_app": null}