andreimarcu
9 years ago
5 changed files with 181 additions and 0 deletions
@ -0,0 +1,98 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"crypto/sha1" |
||||
|
"fmt" |
||||
|
"io" |
||||
|
"net/http" |
||||
|
"os" |
||||
|
"path" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/zeebo/bencode" |
||||
|
"github.com/zenazn/goji/web" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
TORRENT_PIECE_LENGTH = 262144 |
||||
|
) |
||||
|
|
||||
|
type TorrentInfo struct { |
||||
|
PieceLength int `bencode:"piece length"` |
||||
|
Pieces string `bencode:"pieces"` |
||||
|
Name string `bencode:"name"` |
||||
|
Length int `bencode:"length"` |
||||
|
} |
||||
|
|
||||
|
type Torrent struct { |
||||
|
Encoding string `bencode:"encoding"` |
||||
|
Info TorrentInfo `bencode:"info"` |
||||
|
UrlList []string `bencode:"url-list"` |
||||
|
} |
||||
|
|
||||
|
func hashPiece(piece []byte) []byte { |
||||
|
h := sha1.New() |
||||
|
h.Write(piece) |
||||
|
return h.Sum(nil) |
||||
|
} |
||||
|
|
||||
|
func CreateTorrent(fileName string, filePath string) ([]byte, error) { |
||||
|
chunk := make([]byte, TORRENT_PIECE_LENGTH) |
||||
|
|
||||
|
torrent := Torrent{ |
||||
|
Encoding: "UTF-8", |
||||
|
Info: TorrentInfo{ |
||||
|
PieceLength: TORRENT_PIECE_LENGTH, |
||||
|
Name: fileName, |
||||
|
}, |
||||
|
UrlList: []string{fmt.Sprintf("%sselif/%s", Config.siteURL, fileName)}, |
||||
|
} |
||||
|
|
||||
|
f, err := os.Open(filePath) |
||||
|
if err != nil { |
||||
|
return []byte{}, err |
||||
|
} |
||||
|
|
||||
|
for { |
||||
|
n, err := f.Read(chunk) |
||||
|
if err == io.EOF { |
||||
|
break |
||||
|
} else if err != nil { |
||||
|
return []byte{}, err |
||||
|
} |
||||
|
|
||||
|
torrent.Info.Length += n |
||||
|
torrent.Info.Pieces += string(hashPiece(chunk[:n])) |
||||
|
} |
||||
|
|
||||
|
f.Close() |
||||
|
|
||||
|
data, err := bencode.EncodeBytes(&torrent) |
||||
|
if err != nil { |
||||
|
return []byte{}, err |
||||
|
} |
||||
|
|
||||
|
return data, nil |
||||
|
} |
||||
|
|
||||
|
func fileTorrentHandler(c web.C, w http.ResponseWriter, r *http.Request) { |
||||
|
fileName := c.URLParams["name"] |
||||
|
filePath := path.Join(Config.filesDir, fileName) |
||||
|
|
||||
|
if !fileExistsAndNotExpired(fileName) { |
||||
|
notFoundHandler(c, w, r) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
encoded, err := CreateTorrent(fileName, filePath) |
||||
|
if err != nil { |
||||
|
oopsHandler(c, w, r) // 500 - creating torrent failed
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
w.Header().Set(`Content-Disposition`, fmt.Sprintf(`attachment; filename="%s.torrent"`, fileName)) |
||||
|
http.ServeContent(w, r, "", time.Now(), bytes.NewReader(encoded)) |
||||
|
} |
||||
|
|
||||
|
// vim:set ts=8 sw=8 noet:
|
@ -0,0 +1,62 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"testing" |
||||
|
|
||||
|
"github.com/zeebo/bencode" |
||||
|
) |
||||
|
|
||||
|
func TestCreateTorrent(t *testing.T) { |
||||
|
fileName := "server.go" |
||||
|
var decoded Torrent |
||||
|
|
||||
|
encoded, err := CreateTorrent(fileName, fileName) |
||||
|
if err != nil { |
||||
|
t.Fatal(err) |
||||
|
} |
||||
|
|
||||
|
bencode.DecodeBytes(encoded, &decoded) |
||||
|
|
||||
|
if decoded.Encoding != "UTF-8" { |
||||
|
t.Fatalf("Encoding was %s, expected UTF-8", decoded.Encoding) |
||||
|
} |
||||
|
|
||||
|
if decoded.Info.Name != "server.go" { |
||||
|
t.Fatalf("Name was %s, expected server.go", decoded.Info.Name) |
||||
|
} |
||||
|
|
||||
|
if decoded.Info.PieceLength <= 0 { |
||||
|
t.Fatal("Expected a piece length, got none") |
||||
|
} |
||||
|
|
||||
|
if len(decoded.Info.Pieces) <= 0 { |
||||
|
t.Fatal("Expected at least one piece, got none") |
||||
|
} |
||||
|
|
||||
|
if decoded.Info.Length <= 0 { |
||||
|
t.Fatal("Length was less than or equal to 0, expected more") |
||||
|
} |
||||
|
|
||||
|
tracker := fmt.Sprintf("%sselif/%s", Config.siteURL, fileName) |
||||
|
if decoded.UrlList[0] != tracker { |
||||
|
t.Fatalf("First entry in URL list was %s, expected %s", decoded.UrlList[0], tracker) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func TestCreateTorrentWithImage(t *testing.T) { |
||||
|
var decoded Torrent |
||||
|
|
||||
|
encoded, err := CreateTorrent("test.jpg", "static/images/404.jpg") |
||||
|
if err != nil { |
||||
|
t.Fatal(err) |
||||
|
} |
||||
|
|
||||
|
bencode.DecodeBytes(encoded, &decoded) |
||||
|
|
||||
|
if decoded.Info.Pieces != "r\x01\x80j\x99\x84\n\xd3dZ;1NX\xec;\x9d$+f" { |
||||
|
t.Fatal("Torrent pieces did not match expected pieces for image") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// vim:set ts=8 sw=8 noet:
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue