Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
G
gbs-downloader
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
PrivateStorage
gbs-downloader
Commits
c62510bc
Commit
c62510bc
authored
1 year ago
by
Jean-Paul Calderone
Browse files
Options
Downloads
Plain Diff
Merge remote-tracking branch 'origin/main' into 8.download-sdmf
parents
614af236
a84011fe
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
flake.nix
+6
-1
6 additions, 1 deletion
flake.nix
src/Tahoe/Download.hs
+36
-41
36 additions, 41 deletions
src/Tahoe/Download.hs
with
42 additions
and
42 deletions
flake.nix
+
6
−
1
View file @
c62510bc
...
...
@@ -84,8 +84,13 @@
# headers and stuff.
export PKG_CONFIG_PATH=
${
pkgs
.
lib
.
makeSearchPath
"lib/pkgconfig"
[
pkgs
.
zlib
.
dev
]
}
# Get (or update if we have one) a package database so cabal can
# solve our dependencies.
cabal update hackage.haskell.org
cabal run tests
# Configure with tests enable, build the tests (if necessary),
# and run the default test suite.
cabal run --enable-tests tests
''
;
}
}
/bin/cabal-build-and-test"
;
...
...
This diff is collapsed.
Click to expand it.
src/Tahoe/Download.hs
+
36
−
41
View file @
c62510bc
...
...
@@ -13,13 +13,13 @@ module Tahoe.Download (
import
Control.Exception
(
Exception
(
displayException
),
SomeException
,
throwIO
,
try
)
import
Control.Monad.IO.Class
(
MonadIO
(
liftIO
))
import
Data.Bifunctor
(
Bifunctor
(
first
))
import
Data.Bifunctor
(
Bifunctor
(
first
,
second
))
import
Data.Binary
(
Word16
,
decodeOrFail
)
import
qualified
Data.ByteString
as
B
import
Data.ByteString.Base32
(
encodeBase32Unpadded
)
import
qualified
Data.ByteString.Base64
as
Base64
import
qualified
Data.ByteString.Lazy
as
LB
import
Data.Either
(
isRight
,
partitionEithers
)
import
Data.Either
(
partitionEithers
,
rights
)
import
Data.List
(
foldl'
)
import
qualified
Data.Map.Strict
as
Map
import
qualified
Data.Set
as
Set
...
...
@@ -45,6 +45,12 @@ print' :: MonadIO m => String -> m ()
-- print' = liftIO . print
print'
=
const
$
pure
()
-- | Partially describe one share download.
type
DownloadTask
=
(
ShareNum
,
StorageServer
)
-- | A downloaded share
type
Share
=
(
ShareNum
,
LB
.
ByteString
)
{- | An unrecoverable problem arose while attempting to download and/or read
some application data.
-}
...
...
@@ -120,12 +126,29 @@ download servers cap@Reader{verifier = Verifier{..}} lookupServer = do
Right
discovered
->
do
print'
"Found some shares, fetching them"
-- XXX note shares can contain failures
shares
<-
fetchShares
storageIndex
discovered
shares
<-
executeDownloadTasks
storageIndex
(
makeDownloadTasks
=<<
discovered
)
print'
"Fetched the shares, decoding them"
s
<-
decodeShares
cap
shares
print'
"Decoded them"
pure
s
{- | Execute each download task sequentially and return only the successful
results.
-}
executeDownloadTasks
::
MonadIO
m
=>
-- | The storage index of the shares to download.
StorageIndex
->
-- | The downloads to attempt.
[
DownloadTask
]
->
-- | The results of all successful downloads.
m
[
Share
]
executeDownloadTasks
storageIndex
tasks
=
do
downloadResults
<-
mapM
(
downloadShare
storageIndex
)
tasks
pure
.
rights
$
inject
<$>
downloadResults
where
inject
(
a
,
b
)
=
(
a
,)
<$>
b
-- | Find out which servers claim to have shares related to a given storage index.
locateShares
::
MonadIO
m
=>
...
...
@@ -158,24 +181,6 @@ locateShares servers lookupServer storageIndex required =
then
pure
$
Left
NotEnoughShares
{
notEnoughSharesNeeded
=
fromIntegral
required
,
notEnoughSharesFound
=
countDistinctShares
discovered
}
else
pure
$
Right
discovered
{- | Given a guide to where shares for a given storage index are placed,
download them.
-}
fetchShares
::
MonadIO
m
=>
-- | The storage index of the shares to download.
B
.
ByteString
->
-- | The guide to where shares are placed.
[(
StorageServer
,
Set
.
Set
ShareNum
)]
->
m
[(
ShareNum
,
Either
DownloadError
LB
.
ByteString
)]
fetchShares
storageIndex
discovered
=
do
print'
"Fetching shares"
s
<-
mapM
(
uncurry
$
downloadShare
storageIndex
)
(
Map
.
toList
sharemap
)
print'
"Fetched shares"
pure
s
where
sharemap
=
makeShareMap
discovered
{- | Given the results of downloading shares related to a given capability,
decode them and decrypt the contents of possible.
-}
...
...
@@ -184,12 +189,11 @@ decodeShares ::
-- | The read capability which allows the contents to be decrypted.
Reader
->
-- | The results of downloading the shares.
[
(
Share
Num
,
Either
DownloadError
LB
.
ByteString
)
]
->
[
Share
]
->
m
(
Either
DownloadError
LB
.
ByteString
)
decodeShares
cap
@
Reader
{
readKey
,
verifier
=
Verifier
{
..
}}
shares
=
-- Filter down to shares we actually got.
let
someShares
=
filter
(
isRight
.
snd
)
shares
fewerShares
=
filter
(
isRight
.
snd
)
$
(
\
(
sharenum
,
Right
bs
)
->
(
sharenum
,
decodeOrFail
bs
))
<$>
someShares
let
fewerShares
=
second
decodeOrFail
<$>
shares
onlyDecoded
=
(
\
(
sharenum
,
Right
(
_
,
_
,
share
))
->
(
fromIntegral
sharenum
,
share
))
<$>
fewerShares
in
if
length
onlyDecoded
<
fromIntegral
required
then
pure
$
Left
NotEnoughDecodedShares
{
notEnoughDecodedSharesNeeded
=
fromIntegral
required
,
notEnoughDecodedSharesFound
=
length
onlyDecoded
}
...
...
@@ -230,33 +234,24 @@ discoverShares lookupServer storageIndex (_sid, sann) = do
print'
$
"Got them "
<>
show
massaged
pure
$
(
ss
,)
<$>
massaged
{- | Invert the mapping implied by the list of two tuples so that the servers
that claim to have a certain share can easily be retrieved.
{- | Expand a one-to-many mapping into a list of pairs with each of the "many"
values as the first element and the corresponding "one" value as the second
element.
-}
makeShareMap
::
Ord
k
=>
[(
v
,
Set
.
Set
k
)]
->
Map
.
Map
k
[
v
]
makeShareMap
locations
=
foldl'
(
Map
.
unionWith
(
<>
))
mempty
((
\
(
k
,
v
)
->
Map
.
fromSet
(
const
[
k
])
v
)
<$>
locations
)
makeDownloadTasks
::
Ord
k
=>
(
v
,
Set
.
Set
k
)
->
[(
k
,
v
)]
makeDownloadTasks
(
v
,
ks
)
=
zip
(
Set
.
toList
ks
)
(
repeat
v
)
-- | Download the bytes of a share from one (or more!) of the given servers.
downloadShare
::
MonadIO
m
=>
-- | The storage index of the share to download.
StorageIndex
->
-- | The number of the share to download.
ShareNum
->
-- | The servers which we have a reasonable belief could hold a copy of the
-- share. It is common for there to be only one server holding each share
-- but nothing *prevents* multiple servers from having one. In this case we
-- could download the share from both of them, perhaps.
[
StorageServer
]
->
-- | Addressing information about the share to download.
DownloadTask
->
-- | The bytes of the share or some error that was encountered during
-- download.
m
(
ShareNum
,
Either
DownloadError
LB
.
ByteString
)
downloadShare
_
shareNum
[]
=
pure
(
shareNum
,
Left
NoServers
)
downloadShare
storageIndex
shareNum
(
s
:
_
)
=
do
-- TODO: There might be more servers. We could try them if this fails.
-- On the other hand, we might get bytes but we don't verify them here so
-- we might also need retry logic up a level or two from here.
downloadShare
storageIndex
(
shareNum
,
s
)
=
do
print'
$
"Going to download "
<>
show
storageIndex
<>
" "
<>
show
shareNum
shareBytes
<-
liftIO
$
try
(
storageServerRead
s
storageIndex
shareNum
)
let
massaged
=
first
(
ShareDownloadError
.
(
displayException
::
SomeException
->
String
))
shareBytes
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment