プログラミング勉強日記

勉強したことを書きます。Haskellとか。

HaskellでBitTorrentクライアントを作りたい

blog.chaps.io

Haskellで何か作りたい。でも何か作れるほどHaskellわからない。
と思ってたらBitTorrentクライアントのチュートリアルっぽいものを見つけたので、せっかくだし作ってみようという話です。

以前の記事で作っていたBencodeのパース部分をとりあえず書いてみました。

{-# LANGUAGE OverloadedStrings #-}

module Bencode where

import Control.Monad
import Control.Applicative
import Data.Attoparsec.ByteString (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as B
import Data.ByteString

data BValue = String ByteString
            | Number Integer
            | List [BValue]
            | Dictionary [(ByteString, BValue)]
            deriving (Show)

string :: Parser BValue
string = do
    n <- B.decimal
    void $ B.char ':'
    String <$> B.take n

number :: Parser BValue
number = Number <$> (B.char 'i' *> B.signed B.decimal <* B.char 'e')

list :: Parser BValue
list = List <$> (B.char 'l' *> B.many' value  <* B.char 'e')

dictionary :: Parser BValue
dictionary = do
    void $ B.char 'd'
    pairs <- B.many' ((,) <$> string <*> value)
    void $ B.char 'e'
    return $ Dictionary $ fixPair <$> pairs
    where fixPair (String s, v) = (s, v)

value :: Parser BValue
value = string <|> number <|> list <|> dictionary

実行してみます。

ghci> :set -XOverloadedStrings
ghci> B.parseOnly value "d8:announce42:http://tracker.archlinux.org:6969/announce13:creation datei1438414567e4:infod6:lengthi688914432e4:name29:archlinux-2015.08.01-dual.iso12:piece lengthi524288eee"
Right (Dictionary [("announce",String "http://tracker.archlinux.org:6969/announce"),("creation date",Number 1438414567),("info",Dictionary [("length",Number 688914432),("name",String "archlinux-2015.08.01-dual.iso"),("piece length",Number 524288)])])

Attoparsecにも少しずつ慣れてきた気もします。
とりあえずここまで。