summaryrefslogtreecommitdiff
path: root/src/Data/Torrent/Magnet.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Data/Torrent/Magnet.hs')
-rw-r--r--src/Data/Torrent/Magnet.hs119
1 files changed, 114 insertions, 5 deletions
diff --git a/src/Data/Torrent/Magnet.hs b/src/Data/Torrent/Magnet.hs
index 097f4b8e..ae4e134b 100644
--- a/src/Data/Torrent/Magnet.hs
+++ b/src/Data/Torrent/Magnet.hs
@@ -29,14 +29,28 @@ module Data.Torrent.Magnet
29 ( -- * Magnet 29 ( -- * Magnet
30 Magnet(..) 30 Magnet(..)
31 31
32 -- * Construction 32 -- ** Construction
33 , nullMagnet 33 , nullMagnet
34 , simpleMagnet 34 , simpleMagnet
35 , detailedMagnet 35 , detailedMagnet
36 36
37 -- * Conversion 37 -- ** Conversion
38 , parseMagnet 38 , parseMagnet
39 , renderMagnet 39 , renderMagnet
40
41 -- * URN
42 , URN (..)
43
44 -- ** Namespaces
45 , NamespaceId
46 , btih
47
48 -- ** Construction
49 , infohashURN
50
51 -- ** Conversion
52 , parseURN
53 , renderURN
40 ) where 54 ) where
41 55
42import Control.Applicative 56import Control.Applicative
@@ -61,9 +75,104 @@ import Text.PrettyPrint.Class
61import Data.Torrent 75import Data.Torrent
62import Data.Torrent.InfoHash 76import Data.Torrent.InfoHash
63import Data.Torrent.Layout 77import Data.Torrent.Layout
64import Data.Torrent.URN
65 78
66 79
80-- | Namespace identifier determines the syntactic interpretation of
81-- namespace-specific string.
82type NamespaceId = [Text]
83
84-- | BitTorrent Info Hash (hence the name) namespace
85-- identifier. Namespace-specific string /should/ be a base16\/base32
86-- encoded SHA1 hash of the corresponding torrent /info/ dictionary.
87--
88btih :: NamespaceId
89btih = ["btih"]
90
91-- | URN is pesistent location-independent identifier for
92-- resources. In particular, URNs are used represent torrent names
93-- as a part of magnet link, see 'Data.Torrent.Magnet.Magnet' for
94-- more info.
95--
96data URN = URN
97 { urnNamespace :: NamespaceId -- ^ a namespace identifier;
98 , urnString :: Text -- ^ a corresponding
99 -- namespace-specific string.
100 } deriving (Eq, Ord, Typeable)
101
102{-----------------------------------------------------------------------
103-- URN to infohash convertion
104-----------------------------------------------------------------------}
105
106instance Convertible URN InfoHash where
107 safeConvert u @ URN {..}
108 | urnNamespace /= btih = convError "invalid namespace" u
109 | otherwise = safeConvert urnString
110
111-- | Make resource name for torrent with corresponding
112-- infohash. Infohash is base16 (hex) encoded.
113--
114infohashURN :: InfoHash -> URN
115infohashURN = URN btih . longHex
116
117-- | Meaningless placeholder value.
118instance Default URN where
119 def = infohashURN def
120
121{-----------------------------------------------------------------------
122-- URN Rendering
123-----------------------------------------------------------------------}
124
125-- | Render URN to its text representation.
126renderURN :: URN -> Text
127renderURN URN {..}
128 = T.intercalate ":" $ "urn" : urnNamespace ++ [urnString]
129
130instance Pretty URN where
131 pretty = text . T.unpack . renderURN
132
133instance Show URN where
134 showsPrec n = showsPrec n . T.unpack . renderURN
135
136instance QueryValueLike URN where
137 toQueryValue = toQueryValue . renderURN
138 {-# INLINE toQueryValue #-}
139
140{-----------------------------------------------------------------------
141-- URN Parsing
142-----------------------------------------------------------------------}
143
144unsnoc :: [a] -> Maybe ([a], a)
145unsnoc [] = Nothing
146unsnoc xs = Just (L.init xs, L.last xs)
147
148instance Convertible Text URN where
149 safeConvert t = case T.split (== ':') t of
150 uriScheme : body
151 | T.toLower uriScheme == "urn" ->
152 case unsnoc body of
153 Just (namespace, val) -> pure URN
154 { urnNamespace = namespace
155 , urnString = val
156 }
157 Nothing -> convError "missing URN string" body
158 | otherwise -> convError "invalid URN scheme" uriScheme
159 [] -> convError "missing URN scheme" t
160
161instance IsString URN where
162 fromString = either (error . prettyConvertError) id
163 . safeConvert . T.pack
164
165-- | Try to parse an URN from its text representation.
166--
167-- Use 'safeConvert' for detailed error messages.
168--
169parseURN :: Text -> Maybe URN
170parseURN = either (const Nothing) pure . safeConvert
171
172{-----------------------------------------------------------------------
173-- Magnet
174-----------------------------------------------------------------------}
175
67-- TODO multiple exact topics 176-- TODO multiple exact topics
68-- TODO render/parse supplement for URI/query 177-- TODO render/parse supplement for URI/query
69 178
@@ -172,7 +281,7 @@ instance Convertible String Magnet where
172 | otherwise = convError "unable to parse uri" str 281 | otherwise = convError "unable to parse uri" str
173 282
174{----------------------------------------------------------------------- 283{-----------------------------------------------------------------------
175-- Construction 284-- Magnet Construction
176-----------------------------------------------------------------------} 285-----------------------------------------------------------------------}
177 286
178-- | Meaningless placeholder value. 287-- | Meaningless placeholder value.
@@ -221,7 +330,7 @@ detailedMagnet t @ Torrent {tInfoDict = InfoDict {..}, tAnnounce}
221 } 330 }
222 331
223{----------------------------------------------------------------------- 332{-----------------------------------------------------------------------
224-- Conversion 333-- Magnet Conversion
225-----------------------------------------------------------------------} 334-----------------------------------------------------------------------}
226 335
227parseMagnetStr :: String -> Maybe Magnet 336parseMagnetStr :: String -> Maybe Magnet