RangerMauve / hypercore-fetch

Implementation of Fetch that uses the Hyper SDK for loading p2p content
MIT License
36 stars 12 forks source link

Support diffs #51

Open josephmturner opened 1 year ago

josephmturner commented 1 year ago

Please add support for interfacing with hyperdrive's drive.diff API.

RangerMauve commented 1 year ago

Is there information that's missing in the current GET/HEAD responses which would make this hard to do in application logic instead?

What would it look like to trigger a diff using an API call?

Also, mind talking a bit more about what the user story for this feature is?

josephmturner commented 1 year ago

Is there information that's missing in the current GET/HEAD responses which would make this hard to do in application logic instead?

We can do diffs in application logic if you'd prefer to leave diffing out of hyper-gateway.

What would it look like to trigger a diff using an API call?

I can imagine diffing the current version with an older version:

drive.diff(42, '/example.txt')

as well as an older version with an even older version:

const snapshot = drive.checkout(42)
snapshot.diff(41, '/example.txt')

We'd need a different way to trigger each kind of request. Here are a couple of ideas, which depend on the approach we use to specify drive versions in urls (see #41).

  1. Specify diff version in url alongside version number with a special character (different from +)

If we specify version numbers after the public key in the url like hyper://public-key+42/example.txt, a GET request to hyper://public-key-42/example.txt could diff the current /example.txt with version 42. To diff the version at 42 with the version at 41, use hyper://public-key+42-41/example.txt.

Regardless of the special character used (-), I don't think it's that clear what's going on in the above urls.

  1. Add a special folder for diffs

If we specify versions under a special folder like hyper://public-key/$/version/12/example.txt, a GET request to hyper://public-key/$/diff/42/example.txt could diff the current /example.txt with version 42. To diff the version at 42 with the version at 41, use hyper://public-key/$/version/42/$/diff/41/example.txt or hyper://public-key/$/diff/42-41/example.txt or ...?

I think the second approach is clearer, since the url explicitly says "version" or "diff".

Also, mind talking a bit more about what the user story for this feature is?

RangerMauve commented 1 year ago

Lets go with the approach in #36 and revisit this if that ends up being unusuable.

josephmturner commented 1 year ago

Sounds good!

alphapapa commented 1 year ago

Another option for the URL format could be to imitate git, like:

hyper://public-key/$/diff/41..42/example.txt
josephmturner commented 1 year ago

We could pass the Etag we want to diff against as the value of the If-None-Match header on a GET request.

For example, the following would return the diff of the current version against version 22

GET hyper://PUBLIC-KEY/example.txt 
If-None-Match: "22"

The following would return the diff of version 50 against version 22

GET hyper://PUBLIC-KEY/$/version/50/example.txt 
If-None-Match: "22"

When the hyper:// URL's version matches the value of If-None-Match, return 304.

josephmturner commented 1 year ago

Another option would be to use a query string, like hyper://PUBLIC-KEY/example.txt?diff-version=50 An advantage here is that it's possible to link to a diff.

alphapapa commented 1 year ago

Something to consider might be how Wikipedia formats URLs for diffing versions of their articles. e.g.

https://en.wikipedia.org/w/index.php?title=Providence_and_Worcester_Railroad&diff=1150515495&oldid=1150489997
RangerMauve commented 1 year ago

Can we revisit the built-in diffs stuff after there's an implementation in emacs to see whether diffing at the app level is unfeasible?

alphapapa commented 1 year ago

Another example to consider is how GitHub formats diff URLs:

https://github.com/RangerMauve/hypercore-fetch/compare/not-writable-status-code...master
RangerMauve commented 1 year ago

My aversion to adding diffs to the gateway itself is at about 8/10 right now.

josephmturner commented 1 year ago

Sure, we can revisit this after we've tried implementing it in Emacs.

josephmturner commented 11 months ago

drive.diff output looks like this:

{
  left: {
    seq: 4,
    key: '/foo/bar',
    value: {
      executable: false,
      linkname: null,
      blob: { byteOffset: 11, blockOffset: 3, blockLength: 1, byteLength: 4 },
      metadata: timestamp-metadata (etc.)
    }
  },
  right: {
    seq: 1,
    key: '/foo/bar',
    value: {
      executable: false,
      linkname: null,
      blob: { byteOffset: 0, blockOffset: 0, blockLength: 1, byteLength: 7 },
      metadata: timestamp-metadata (etc.)
    }
  }
}
{
  left: {
    seq: 3,
    key: '/foo/baz',
    value: {
      executable: false,
      linkname: null,
      blob: { byteOffset: 9, blockOffset: 2, blockLength: 1, byteLength: 2 },
      metadata: timestamp-metadata (etc.)
    }
  },
  right: null
}

I'm not sure how hypercore-fetch would make us of the blob data, but the other metadata would be useful in hyperdrive.el.

Possible flow: User requests the difference in folder foo between version 20 and version 30. hypercore-fetch returns (streams?) the same JSON that drive.diff returns.

With just that information, hyperdrive.el can display this:

  Old New
/foo/bar    
- version 1 4
- timestamp jan 1 jan 15
- size 4 7
/foo/baz    
- version   3
- timestamp   2
- size   jan 10

When user requests individual diffs, we use the current mechanism (where we make two GET requests, one per version).

RangerMauve commented 11 months ago

Another option for the URL format could be to imitate git, like:

hyper://public-key/$/diff/41..42/example.txt

Lets go with this formatting, and return the json as is

josephmturner commented 11 months ago

LGTM. Thank you!