{"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-803673225", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 803673225, "node_id": "MDEyOklzc3VlQ29tbWVudDgwMzY3MzIyNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2021-03-21T22:44:19Z", "updated_at": "2021-03-21T22:44:19Z", "author_association": "OWNER", "body": "Now that I'm looking at refactoring how views work in #878 it's clear that the gnarliest, most convoluted code I need to deal with relates to this old feature.\r\n\r\nI'm going to remove it entirely. Any performance enhancement or provides can be achieved just as well by using regular URLs and a caching proxy.\r\n\r\nI may provide a 404 handling plugin that attempts to rewrite old URLs that used this mechanism, but I won't do any more than that.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1061226942", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1061226942, "node_id": "IC_kwDOBm6k_c4_QQm-", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-07T23:00:06Z", "updated_at": "2022-03-07T23:00:06Z", "author_association": "OWNER", "body": "This needs to take into account the changes made here:\r\n- #1439\r\n\r\nIn the new encoding scheme, `-` has a special meaning in a table name: https://docs.datasette.io/en/latest/internals.html#dash-encoding\r\n\r\nI think `~` is the right character to use to separate a database name from its hash. `~` should be a URL safe character according to Python's implementation of percent-encoding, see comment here: https://github.com/simonw/datasette/blob/c5791156d92615f25696ba93dae5bb2dcc192c98/datasette/utils/__init__.py#L1146-L1152\r\n\r\nSo the plugin could check for `dbname~hash` and react based on that.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1061267615", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1061267615, "node_id": "IC_kwDOBm6k_c4_Qaif", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-08T00:05:43Z", "updated_at": "2022-03-08T00:05:43Z", "author_association": "OWNER", "body": "Built a prototype of that plugin:\r\n```python\r\nfrom datasette import hookimpl\r\nfrom functools import wraps\r\n\r\n\r\n@hookimpl\r\ndef asgi_wrapper(datasette):\r\n def wrap_with_hashed_urls(app):\r\n @wraps(app)\r\n async def hashed_urls(scope, receive, send):\r\n # Only triggers on pages with a path not starting in /-/\r\n # and where the first page component matches a database name\r\n if scope.get(\"type\") != \"http\":\r\n await app(scope, receive, send)\r\n return\r\n path = scope[\"path\"].lstrip(\"/\")\r\n if not path or path.startswith(\"-/\"):\r\n await app(scope, receive, send)\r\n return\r\n potential_database = path.split(\"/\")[0]\r\n # It may or may not be already dbname~hash\r\n if \"~\" in potential_database:\r\n db_name, hash = potential_database.split(\"~\", 1)\r\n else:\r\n db_name = potential_database\r\n hash = \"\"\r\n # Is db_name a database we have a hash for?\r\n try:\r\n db = datasette.get_database(db_name)\r\n except KeyError:\r\n await app(scope, receive, send)\r\n return\r\n\r\n if db.hash is not None:\r\n # TODO: make sure db.hash is documented\r\n if db.hash[:7] != hash:\r\n # Send a redirect\r\n path_bits = path.split(\"/\")\r\n new_path = \"/\" + \"/\".join([\"{}-{}\".format(db_name, db.hash[:7])] + path_bits[1:])\r\n if scope.get(\"query_string\"):\r\n new_path += \"?\" + scope[\"query_string\"].decode(\"latin-1\")\r\n\r\n await send({\r\n \"type\": \"http.response.start\",\r\n \"status\": 302,\r\n \"headers\": [\r\n [b\"location\", new_path.encode(\"latin1\")]\r\n ],\r\n })\r\n await send({\"type\": \"http.response.body\", \"body\": b\"\"})\r\n return\r\n else:\r\n # Add a far-future cache header\r\n async def wrapped_send(event):\r\n if event[\"type\"] == \"http.response.start\":\r\n original_headers = event.get(\"headers\") or []\r\n event = {\r\n \"type\": event[\"type\"],\r\n \"status\": event[\"status\"],\r\n \"headers\": original_headers + [\r\n [b\"Cache-Control\", b\"max-age=31536000\"]\r\n ],\r\n }\r\n await send(event)\r\n\r\n await app(scope, receive, wrapped_send)\r\n return\r\n \r\n await app(scope, receive, send)\r\n return hashed_urls\r\n return wrap_with_hashed_urls\r\n```\r\nOne catch: it doesn't affect the way URLs are generated - so every internal link within Datasette links to the non-hash version and then triggers a 302 redirect to the hashed version.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1061272544", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1061272544, "node_id": "IC_kwDOBm6k_c4_Qbvg", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-08T00:14:42Z", "updated_at": "2022-03-08T00:14:42Z", "author_association": "OWNER", "body": "Maybe the plugin should interfere with `datasette.databases` on startup and change the registered name for each one?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1061276399", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1061276399, "node_id": "IC_kwDOBm6k_c4_Qcrv", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-08T00:21:47Z", "updated_at": "2022-03-08T00:21:47Z", "author_association": "OWNER", "body": "This seems to do the job:\r\n```python\r\n@hookimpl\r\ndef startup(datasette):\r\n for name, database in datasette.databases.items():\r\n if database.hash:\r\n new_name = \"{}_{}\".format(name, database.hash[:7])\r\n del datasette.databases[name]\r\n datasette.databases[new_name] = database\r\n```\r\nWould have to teach the rest of the plugin to split on `_` and to only redirect if the user seems to be hitting the URL for an old hash after which Datasette has been restarted with an updated database.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1061276646", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1061276646, "node_id": "IC_kwDOBm6k_c4_Qcvm", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-08T00:22:11Z", "updated_at": "2022-03-08T00:22:11Z", "author_association": "OWNER", "body": "I'm now convinced this is feasible enough that it's worth doing in time for Datasette 1.0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1061282743", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1061282743, "node_id": "IC_kwDOBm6k_c4_QeO3", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-08T00:32:34Z", "updated_at": "2022-03-08T00:32:47Z", "author_association": "OWNER", "body": "It would be neat if the plugin could spot old-style hyphen hash URLs (maybe on 404) and redirect those too.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1068539404", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1068539404, "node_id": "IC_kwDOBm6k_c4_sJ4M", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-15T22:49:01Z", "updated_at": "2022-03-15T22:49:01Z", "author_association": "OWNER", "body": "I shipped the first version of this: https://github.com/simonw/datasette-hashed-urls\r\n\r\nNext step: test it with a live demo:\r\n- https://github.com/simonw/datasette-hashed-urls/issues/2", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/647#issuecomment-1068552696", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/647", "id": 1068552696, "node_id": "IC_kwDOBm6k_c4_sNH4", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-03-15T23:13:06Z", "updated_at": "2022-03-15T23:13:06Z", "author_association": "OWNER", "body": "The plugin works. I'm going to implement one last feature for it:\r\n\r\n- https://github.com/simonw/datasette-hashed-urls/issues/3\r\n\r\nThen I can remove hashed URL mode in a separate issue.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 531755959, "label": "Move hashed URL mode out to a plugin"}, "performed_via_github_app": null}