Joey Hess [Tue, 23 Jul 2024 18:31:32 +0000 (14:31 -0400)]
Remote.Git checkpresent works with annex+http urls.
Joey Hess [Tue, 23 Jul 2024 18:12:03 +0000 (14:12 -0400)]
factor out http server and client into own modules
To avoid a cycle when Remote.Git uses the client.
Joey Hess [Tue, 23 Jul 2024 17:53:10 +0000 (13:53 -0400)]
started wiring p2phttp into Remote.Git
but we have a cycle, ugh
Joey Hess [Tue, 23 Jul 2024 16:30:27 +0000 (12:30 -0400)]
require a valid uuid at the end of an annex+http url
Joey Hess [Tue, 23 Jul 2024 13:55:14 +0000 (09:55 -0400)]
add remoteAnnexP2PHttpUrl to RemoveGitConfig
This is always parsed, when building without servant, a Baseurl is not
generated, and users of it will need to fail.
Joey Hess [Tue, 23 Jul 2024 13:12:21 +0000 (09:12 -0400)]
starting support for remote.name.annexUrl set to annex+http
In this case, Remote.Git should not use that url for all access to
the repository. It will only be used for annex operations, which isn't
done yet.
Joey Hess [Tue, 23 Jul 2024 12:53:56 +0000 (08:53 -0400)]
update servant build flag
make it work when building w/o assistant
Joey Hess [Tue, 23 Jul 2024 12:53:52 +0000 (08:53 -0400)]
update
Joey Hess [Tue, 23 Jul 2024 12:42:33 +0000 (08:42 -0400)]
annex+http urls
Joey Hess [Tue, 23 Jul 2024 01:19:32 +0000 (21:19 -0400)]
refactor
Joey Hess [Tue, 23 Jul 2024 01:19:20 +0000 (21:19 -0400)]
fix build
Joey Hess [Tue, 23 Jul 2024 00:59:45 +0000 (20:59 -0400)]
update
Joey Hess [Tue, 23 Jul 2024 00:44:48 +0000 (20:44 -0400)]
change default port to 9417
Port 80 would need root, not a good idea, so pick something that might
work by default.
9418 is git protocol's port. 9419 is used by something, but nothing
known uses 9417, so it's as good a default as any.
Joey Hess [Tue, 23 Jul 2024 00:37:37 +0000 (20:37 -0400)]
exit cleanly on eg, failure to bind socket
Joey Hess [Mon, 22 Jul 2024 23:50:08 +0000 (19:50 -0400)]
P2P protocol is finalized
Joey Hess [Mon, 22 Jul 2024 23:48:54 +0000 (19:48 -0400)]
make keeplocked client UUID optional
It's not used, but it makes the protocol simpler if this parameter can
always be sent.
Joey Hess [Mon, 22 Jul 2024 23:44:26 +0000 (19:44 -0400)]
locking over http basically working
Joey Hess [Mon, 22 Jul 2024 23:15:52 +0000 (19:15 -0400)]
make serveKeepLocked check auth just to be safe
Joey Hess [Mon, 22 Jul 2024 22:55:12 +0000 (18:55 -0400)]
implement clientLockContent
Joey Hess [Mon, 22 Jul 2024 21:36:56 +0000 (17:36 -0400)]
implemented serveLockContent (untested)
Joey Hess [Mon, 22 Jul 2024 20:56:44 +0000 (16:56 -0400)]
improve clientKeepLocked
Joey Hess [Mon, 22 Jul 2024 20:50:11 +0000 (16:50 -0400)]
variable name
Joey Hess [Mon, 22 Jul 2024 20:49:05 +0000 (16:49 -0400)]
refactor
Joey Hess [Mon, 22 Jul 2024 20:31:39 +0000 (16:31 -0400)]
finished clientGet validity checking
Joey Hess [Mon, 22 Jul 2024 20:23:08 +0000 (16:23 -0400)]
improve clientGet types
Joey Hess [Mon, 22 Jul 2024 19:48:46 +0000 (15:48 -0400)]
fix TMVar left full crash affecting servePutOffset
Problem is that whatever is reading from the TMVar may not have read
from it yet before the client writes the next thing to it.
Joey Hess [Mon, 22 Jul 2024 19:02:08 +0000 (15:02 -0400)]
implemented servePutOffset and clientPutOffset
But, it's buggy: the server hangs without processing the VALIDITY,
and I can't seem to work out why. As far as I can see, storefile
is getting as far as running the validitycheck, which is supposed to
read that, but never does.
This is especially strange because what seems like the same protocol
doesn't hang when servePut runs it. This made me think that it needed
to use inAnnexWorker to be more like servePut, but that didn't help.
Another small problem with this is that it does create an empty
.git/annex/tmp/ file for the key. Since this will usually be used in
combination with servePut, that doesn't seem worth worrying about much.
Joey Hess [Mon, 22 Jul 2024 17:12:15 +0000 (13:12 -0400)]
fix crash in servePut when client sends from too high offset
Have to consume all the content from the client, but force an Invalid
result, so it will just get discarded.
Joey Hess [Mon, 22 Jul 2024 16:50:21 +0000 (12:50 -0400)]
clientPut seeking to offset
Joey Hess [Mon, 22 Jul 2024 16:30:30 +0000 (12:30 -0400)]
avoid padding in servePut
This means that when the client sends a truncated data to indicate
invalidity, DATA is not passed the full expected data. That leaves the
P2P connection in a state where it cannot be reused. While so far, they
are not reused, they will be later when proxies are supported. So, have
to close the P2P connection in this situation.
Joey Hess [Mon, 22 Jul 2024 15:47:24 +0000 (11:47 -0400)]
avoid padding in clientPut
Instead truncate when necessary to indicate invalid content was sent.
Very similar to how serveGet handles it.
Joey Hess [Mon, 22 Jul 2024 15:26:22 +0000 (11:26 -0400)]
fix releasing of p2p connection
Joey Hess [Mon, 22 Jul 2024 15:19:52 +0000 (11:19 -0400)]
avoid padding content in serveGet
Always truncate instead. The padding risked something not noticing the
content was bad and getting a file that was corrupted in a novel way
with the padding "X" at the end. A truncated file is better.
Joey Hess [Mon, 22 Jul 2024 14:20:18 +0000 (10:20 -0400)]
servePut and clientPut implementation
Made the data-length header required even for v0. This simplifies the
implementation, and doesn't preclude extra verification being done for
v0.
The connectionWaitVar is an ugly hack. In servePut, nothing waits
on the waitvar, and I could not find a good way to make anything wait on
it.
Joey Hess [Thu, 11 Jul 2024 19:47:16 +0000 (15:47 -0400)]
only base64 non-utf8
Joey Hess [Thu, 11 Jul 2024 18:51:45 +0000 (14:51 -0400)]
update deps
Joey Hess [Thu, 11 Jul 2024 18:37:52 +0000 (14:37 -0400)]
use worker pool in withLocalP2PConnections
This allows multiple clients to be handled at the same time.
Joey Hess [Thu, 11 Jul 2024 16:31:41 +0000 (12:31 -0400)]
switch HTTP P2P protocol to base64url
Base64 can include '/', and with UUIDs and keys both used in routes,
the encoding needs to avoid that. Use base64url everywhere in the HTTP
protocol for consistency.
Joey Hess [Thu, 11 Jul 2024 16:20:07 +0000 (12:20 -0400)]
roughed in servePut
Joey Hess [Thu, 11 Jul 2024 16:12:33 +0000 (12:12 -0400)]
oops, 2 datalength headers for put route
Joey Hess [Thu, 11 Jul 2024 15:57:55 +0000 (11:57 -0400)]
use DataLength
Joey Hess [Thu, 11 Jul 2024 15:50:44 +0000 (11:50 -0400)]
simplify
Joey Hess [Thu, 11 Jul 2024 15:42:32 +0000 (11:42 -0400)]
serveGet invalidation
Joey Hess [Thu, 11 Jul 2024 15:26:03 +0000 (11:26 -0400)]
implement generic get server
Joey Hess [Thu, 11 Jul 2024 15:19:20 +0000 (11:19 -0400)]
move serveruuid into routes
In particular the generic get route needs it, so that when a single http
server is serving multiple repositories, it knows what repository to
use.
Joey Hess [Thu, 11 Jul 2024 13:55:17 +0000 (09:55 -0400)]
fix serveGet early handle close
Needed that waitv after all..
Joey Hess [Thu, 11 Jul 2024 13:15:52 +0000 (09:15 -0400)]
fix annexworker shutdown on early client disconnect
Joey Hess [Thu, 11 Jul 2024 11:56:55 +0000 (07:56 -0400)]
cleanup
Joey Hess [Thu, 11 Jul 2024 11:46:52 +0000 (07:46 -0400)]
fix serveGet hang
This came down to SendBytes waiting on the waitv. Nothing ever filled
it.
Only Annex.Proxy needs the waitv, and it handles filling it. So make it
optional.
Joey Hess [Wed, 10 Jul 2024 21:48:48 +0000 (17:48 -0400)]
a little progress on serveGet hang
Now it gets to the validity checker, but it seems it never runs it.
Joey Hess [Wed, 10 Jul 2024 20:10:08 +0000 (16:10 -0400)]
update
Joey Hess [Wed, 10 Jul 2024 20:06:39 +0000 (16:06 -0400)]
implemented serveGet and clientGet
Both are only at bare proof of concept stage. Still need to deal with
signaling validity and invalidity, and checking it.
And there's a bad bug: After -JN*2 requests, another request hangs!
So, I think it's failing to free up the Annex worker and end of request
lifetime.
Perhaps I need to use this:
https://docs.servant.dev/en/stable/cookbook/managed-resource/ManagedResource.html
Joey Hess [Wed, 10 Jul 2024 16:19:47 +0000 (12:19 -0400)]
add Annex worker pool to P2PHttp
This will be needed for get and store, since those need to run Annex
actions.
withLocalP2PConnections will also probably use it.
Joey Hess [Wed, 10 Jul 2024 14:23:10 +0000 (10:23 -0400)]
implement gettimestamp
Joey Hess [Wed, 10 Jul 2024 14:03:26 +0000 (10:03 -0400)]
implement remove-before
The reason to use removeBeforeRemoteEndTime is twofold.
First, removeBefore sends two protocol commands. Currently, the HTTP
protocol runner only supports sending a single command per invocation.
Secondly, the http server gets a monotonic timestamp from the client. So
translating back to a POSIXTime would be annoying.
The timestamp flow with a proxy will be:
- client gets timestamp, which gets the monotonic timestamp from the
proxied remote via the proxy. The timestamp is currently not
proxied when there is a single proxy.
- client calls remove-before
- http server calls removeBeforeRemoteEndTime which sends REMOVE-BEFORE
to the proxied remote.
Joey Hess [Wed, 10 Jul 2024 13:45:23 +0000 (09:45 -0400)]
Revert "proxy local timestamps in single proxy case as well as cluster case"
Turns out not to be necessary. I think.
This reverts commit
81e11efda19ef0b79e52a31aca2ec986108118ee.
Joey Hess [Wed, 10 Jul 2024 13:40:13 +0000 (09:40 -0400)]
proxy local timestamps in single proxy case as well as cluster case
This is less efficient, but it guarantees that the timestamps that the
client is sending are local timestamps, which turns out to be necessary
for the HTTP PTP protocol server.
Joey Hess [Wed, 10 Jul 2024 13:37:43 +0000 (09:37 -0400)]
remove debug print
Joey Hess [Wed, 10 Jul 2024 13:19:58 +0000 (09:19 -0400)]
implement clientRemove
Tested removal.
Joey Hess [Wed, 10 Jul 2024 13:13:01 +0000 (09:13 -0400)]
implement serveRemove and send WWW-Authenticate header on auth failure
Joey Hess [Wed, 10 Jul 2024 03:44:40 +0000 (23:44 -0400)]
git-annex p2phttp options
Joey Hess [Wed, 10 Jul 2024 00:52:56 +0000 (20:52 -0400)]
authentication is implemented
just need to make Command.P2PHttp generate a GetServerMode from options
Joey Hess [Wed, 10 Jul 2024 00:07:20 +0000 (20:07 -0400)]
http basic authorization header parsing
Sadly servant does not expose this though it also implements it.
Joey Hess [Tue, 9 Jul 2024 21:30:55 +0000 (17:30 -0400)]
started on auth
Joey Hess [Tue, 9 Jul 2024 18:30:50 +0000 (14:30 -0400)]
update
Joey Hess [Tue, 9 Jul 2024 18:26:30 +0000 (14:26 -0400)]
fix p2phttp server to not get stuck
Process 1 command, then stop. Hopefully each of the Handlers will only
need 1 command.
Joey Hess [Tue, 9 Jul 2024 17:50:42 +0000 (13:50 -0400)]
set up handles for p2phttp
Now it fully works.. for the first request. But then it gets stuck
waiting for the P2P protocol runner to shut down.
Joey Hess [Tue, 9 Jul 2024 17:37:55 +0000 (13:37 -0400)]
p2phttp is almost working for checkpresent
The server is fully running annex actions, only the P2PConnection is
wrong, currently using stdio.
Joey Hess [Tue, 9 Jul 2024 14:12:36 +0000 (10:12 -0400)]
capture API version in routes
Needed so the client can send it.
Joey Hess [Tue, 9 Jul 2024 13:08:42 +0000 (09:08 -0400)]
implemented serveCheckPresent
Still need a way to run Proto though
Joey Hess [Tue, 9 Jul 2024 01:11:01 +0000 (21:11 -0400)]
split module
Joey Hess [Tue, 9 Jul 2024 01:00:10 +0000 (21:00 -0400)]
implement Locker
Joey Hess [Tue, 9 Jul 2024 00:18:55 +0000 (20:18 -0400)]
add lockids to http p2p protocol
Joey Hess [Mon, 8 Jul 2024 18:20:30 +0000 (14:20 -0400)]
add lock map
Joey Hess [Mon, 8 Jul 2024 18:00:23 +0000 (14:00 -0400)]
thread in a state
Joey Hess [Mon, 8 Jul 2024 17:26:02 +0000 (13:26 -0400)]
finish get API
Joey Hess [Mon, 8 Jul 2024 14:40:38 +0000 (10:40 -0400)]
convert lockcontent api to http long polling
Websockets would work, but the problem with using them for this is that
each lockcontent call is a separate websocket connection. And that's an
actual TCP connection. One TCP connection per file dropped would be too
expensive. With http long polling, regular http pipelining can be used,
so it will reuse a TCP connection.
Unfortunately, at least with servant, bi-directional streams with long
polling don't result in true bidirectional full duplex communication.
Servant processes the whole client body stream before generating the server
body stream. I think it's entirely possible to do full bi-directional
communication over http, but it would need changes to servant.
And, there's no way for the client to tell if the server successfully
locked the content, since the server will keep processing the client
stream no matter what.:
So, added a new api endpoint, keeplocked. lockcontent will lock the key
for 10 minutes with retention lock, and then a call to keeplocked will
keep it locked for as long as needed. This does mean that there will
need to be a Map of locks by key, and I will probably want to add
some kind of lock identifier that lockcontent returns.
Joey Hess [Mon, 8 Jul 2024 11:44:59 +0000 (07:44 -0400)]
implemented servant-client support for websockets
Joey Hess [Mon, 8 Jul 2024 01:51:30 +0000 (21:51 -0400)]
may have found a way to make a request for a websocket?!
dunno, it compiles anyway
Joey Hess [Mon, 8 Jul 2024 01:20:50 +0000 (21:20 -0400)]
dummy HasClient ClientM WebSocket
Enough to let lockcontent routes be included and servant-client be used.
But not enough to use servant-client with those routes. May need to
implement a separate runner for that part of the protocol?
Also some misc other stuff needed to use servant-client.
And fix exposing of UUID in the JSON types. UUID does actually have
aeson instances, but they're used elsewhere (metadata --batch, although
only included to get it to compile, not actually used in there) and not
suitable for use here since this must work with every possible UUID.
Joey Hess [Sun, 7 Jul 2024 20:16:11 +0000 (16:16 -0400)]
status
Joey Hess [Sun, 7 Jul 2024 20:08:05 +0000 (16:08 -0400)]
servant client mostly implemented
lockcontent had to be disabled until I can implement HasClient ClientM WebSocket
and in clientGet, it's not clear how to use the v1 and v0 versions,
which don't have a DataLengthHeader
Joey Hess [Sun, 7 Jul 2024 18:48:20 +0000 (14:48 -0400)]
servant server now compiling
Just need to fill in some undefined
Joey Hess [Sun, 7 Jul 2024 16:59:12 +0000 (12:59 -0400)]
servant API type is complete
Joey Hess [Sun, 7 Jul 2024 16:08:24 +0000 (12:08 -0400)]
Merge branch 'master' into httpproto
Joey Hess [Sun, 7 Jul 2024 16:08:10 +0000 (12:08 -0400)]
started servant implementation of HTTP P2P protocol
Joey Hess [Fri, 5 Jul 2024 19:37:43 +0000 (15:37 -0400)]
Merge branch 'master' of ssh://git-annex.branchable.com
Joey Hess [Fri, 5 Jul 2024 19:34:58 +0000 (15:34 -0400)]
finalizing HTTP P2p protocol some more
Added v2-v0 endpoints. These are tedious, but will be needed in order to
use the HTTP protocol to proxy to repositories with older git-annex,
where git-annex-shell will be speaking an older version of the protocol.
Changed GET to use 422 when the content is not present. 404 is needed to
detect when a protocol version is not supported.
Joey Hess [Fri, 5 Jul 2024 19:34:10 +0000 (15:34 -0400)]
playing around with bytestring lazy streaming in servant
Will be needed for git-annex http p2p protocol.
Joey Hess [Fri, 5 Jul 2024 19:00:05 +0000 (15:00 -0400)]
finalizing HTTP P2P protocol
Managed to avoid netstrings. Actually, using netstrings while streaming
lazy ByteString turns out to be very difficult. So instead, have a
header that specifies the expected amount of data, and then it can just
arrange to send a different amount of data if it needs to indicate
INVALID.
Also improved the interface for GET of a key.
Joey Hess [Fri, 5 Jul 2024 15:53:03 +0000 (11:53 -0400)]
use netstrings for framing binary data with json at the end
This will be easy to implement with servant. It's also very efficient,
and fairly future-proof. Eg, could add another frame with other data.
This does make it a bit harder to use this protocol, but netstrings
probably take about 5 minutes to implement? Let's see...
import Text.Read
import Data.List
toNetString :: String -> String
toNetString s = show (length s) ++ ":" ++ s ++ ","
nextNetString :: String -> Maybe (String, String)
nextNetString s = case break (== ':') s of
([], _) -> Nothing
(sn, rest) -> do
n <- readMaybe sn
let (v, rest') = splitAt n (drop 1 rest)
return (v, drop 1 rest')
Ok, well, that took about 10 minutes ;-)
Joey Hess [Fri, 5 Jul 2024 14:08:43 +0000 (10:08 -0400)]
thoughts on CGI, and use json
Added a comment
Joey Hess [Thu, 4 Jul 2024 19:26:05 +0000 (15:26 -0400)]
update
Joey Hess [Thu, 4 Jul 2024 19:18:17 +0000 (15:18 -0400)]
Merge branch 'master' of ssh://git-annex.branchable.com
Joey Hess [Thu, 4 Jul 2024 19:18:06 +0000 (15:18 -0400)]
update
Joey Hess [Thu, 4 Jul 2024 19:08:33 +0000 (15:08 -0400)]
REMOVE-BEFORE and GETTIMESTAMP proxying
For clusters, the timestamps have to be translated, since each node can
have its own idea about what time it is. To translate a timestamp, the
proxy remembers what time it asked the node for a timestamp in
GETTIMESTAMP, and applies the delta as an offset in REMOVE-BEFORE.
This does mean that a remove from a cluster has to call GETTIMESTAMP on
every node before dropping from nodes. Not very efficient. Although
currently it tries to drop from every single node anyway, which is also
not very efficient.
I thought about caching the GETTIMESTAMP from the nodes on the first
call. That would improve efficiency. But, since monotonic clocks on
!Linux don't advance when the computer is suspended, consider what might
happen if one node was suspended for a while, then came back. Its
monotonic timestamp would end up behind where the proxying expects it to
be. Would that result in removing when it shouldn't, or refusing to
remove when it should? Have not thought it through. Either way, a
cluster behaving strangly for an extended period of time because one
of its nodes was briefly asleep doesn't seem like good behavior.
Joey Hess [Thu, 4 Jul 2024 17:42:09 +0000 (13:42 -0400)]
use REMOVE-BEFORE in P2P protocol
Only clusters still need to be fixed to close this todo.
Joey Hess [Thu, 4 Jul 2024 16:23:46 +0000 (12:23 -0400)]
toward SafeDropProof expiry checking
Added Maybe POSIXTime to SafeDropProof, which gets set when the proof is
based on a LockedCopy. If there are several LockedCopies, it uses the
closest expiry time. That is not optimal, it may be that the proof
expires based on one LockedCopy but another one has not expired. But
that seems unlikely to really happen, and anyway the user can just
re-run a drop if it fails due to expiry.
Pass the SafeDropProof to removeKey, which is responsible for checking
it for expiry in situations where that could be a problem. Which really
only means in Remote.Git.
Made Remote.Git check expiry when dropping from a local remote.
Checking expiry when dropping from a P2P remote is not yet implemented.
P2P.Protocol.remove has SafeDropProof plumbed through to it for that
purpose.
Fixing the remaining 2 build warnings should complete this work.
Note that the use of a POSIXTime here means that if the clock gets set
forward while git-annex is in the middle of a drop, it may say that
dropping took too long. That seems ok. Less ok is that if the clock gets
turned back a sufficient amount (eg 5 minutes), proof expiry won't be
noticed. It might be better to use the Monotonic clock, but that doesn't
advance when a laptop is suspended, and while there is the linux
Boottime clock, that is not available on other systems. Perhaps a
combination of POSIXTime and the Monotonic clock could detect laptop
suspension and also detect clock being turned back?
There is a potential future flag day where
p2pDefaultLockContentRetentionDuration is not assumed, but is probed
using the P2P protocol, and peers that don't support it can no longer
produce a LockedCopy. Until that happens, when git-annex is
communicating with older peers there is a risk of data loss when
a ssh connection closes during LOCKCONTENT.
Joey Hess [Thu, 4 Jul 2024 13:52:02 +0000 (09:52 -0400)]
Merge branch 'master' into p2p_locking