mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-05-04 02:23:13 +00:00
109 lines
3.4 KiB
Nim
109 lines
3.4 KiB
Nim
import std/strutils
|
|
import std/sequtils
|
|
|
|
import pkg/stew/byteutils
|
|
import pkg/libp2p/[multicodec, multihash]
|
|
import pkg/questionable
|
|
import pkg/questionable/results
|
|
|
|
import ../errors
|
|
import ../codextypes
|
|
import ./manifest/manifest
|
|
|
|
type
|
|
TorrentVersion* = enum
|
|
v1
|
|
v2
|
|
hybrid
|
|
|
|
MagnetLink* = ref object
|
|
version: TorrentVersion
|
|
infoHashV1: ?MultiHash
|
|
infoHashV2: ?MultiHash
|
|
|
|
proc version*(self: MagnetLink): TorrentVersion =
|
|
## Get the version of the magnet link
|
|
##
|
|
## returns: the version of the magnet link
|
|
result = self.version
|
|
|
|
proc infoHashV1*(self: MagnetLink): ?MultiHash =
|
|
## Get the info hash of the magnet link
|
|
##
|
|
## returns: the info hash of the magnet link
|
|
result = self.infoHashV1
|
|
|
|
proc infoHashV2*(self: MagnetLink): ?MultiHash =
|
|
## Get the info hash of the magnet link
|
|
##
|
|
## returns: the info hash of the magnet link
|
|
result = self.infoHashV2
|
|
|
|
proc parseMagnetLink(link: string): ?!MagnetLink =
|
|
let prefix = "magnet:?"
|
|
if not link.startsWith(prefix):
|
|
return failure("Invalid magnet link format (missing 'magnet:?' prefix)")
|
|
let infoHashParts = link[prefix.len .. ^1].split("&").filterIt(it.startsWith("xt="))
|
|
if infoHashParts.len < 1:
|
|
return
|
|
failure("Invalid magnet link format (at least one info hash part is required)")
|
|
let v1Prefix = "xt=urn:btih:"
|
|
let v2Prefix = "xt=urn:btmh:"
|
|
var infoHashV1 = none(MultiHash)
|
|
var infoHashV2 = none(MultiHash)
|
|
for infoHashPart in infoHashParts:
|
|
# var a = infoHashPart[v1Prefix.len .. ^1]
|
|
if infoHashPart.startsWith(v1Prefix):
|
|
without infoHash =? BitTorrentInfo.buildMultiHash(
|
|
infoHashPart[v1Prefix.len .. ^1]
|
|
), err:
|
|
return failure("Error parsing info hash: " & err.msg)
|
|
infoHashV1 = some(infoHash)
|
|
elif infoHashPart.startsWith(v2Prefix):
|
|
without infoHash =? BitTorrentInfo.buildMultiHash(
|
|
infoHashPart[v2Prefix.len .. ^1]
|
|
), err:
|
|
return failure("Error parsing info hash: " & err.msg)
|
|
infoHashV2 = some(infoHash)
|
|
|
|
if infoHashV1.isNone and infoHashV2.isNone:
|
|
return failure("Invalid magnet link format (missing info hash part)")
|
|
|
|
var version: TorrentVersion
|
|
if infoHashV1.isSome and infoHashV2.isSome:
|
|
version = TorrentVersion.hybrid
|
|
elif infoHashV1.isSome:
|
|
version = TorrentVersion.v1
|
|
else:
|
|
version = TorrentVersion.v2
|
|
|
|
let magnetLink =
|
|
MagnetLink(version: version, infoHashV1: infoHashV1, infoHashV2: infoHashV2)
|
|
return success(magnetLink)
|
|
|
|
proc getHashHex(multiHash: MultiHash): string =
|
|
## Get the info hash of the magnet link as a hex string
|
|
result = byteutils.toHex(multiHash.data.buffer[multiHash.dpos .. ^1]).toUpperAscii()
|
|
|
|
proc `$`*(self: MagnetLink): string =
|
|
## Convert the magnet link to a string
|
|
##
|
|
## returns: the magnet link as a string
|
|
if self.version == TorrentVersion.hybrid:
|
|
result =
|
|
"magnet:?xt=urn:btih:" & (!self.infoHashV1).getHashHex() & "&xt=urn:btmh:" &
|
|
(!self.infoHashV2).hex
|
|
elif self.version == v1:
|
|
result = "magnet:?xt=urn:btih:" & (!self.infoHashV1).getHashHex()
|
|
else:
|
|
result = "magnet:?xt=urn:btmh:" & (!self.infoHashV2).hex
|
|
|
|
proc newMagnetLink*(magnetLinkString: string): ?!MagnetLink =
|
|
## Create a new magnet link
|
|
##
|
|
## version: the version of the magnet link
|
|
## magnetLinkString: text containing the magnet link
|
|
##
|
|
## returns: a Result containing a magnet link object or a failure
|
|
parseMagnetLink(magnetLinkString)
|