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