Contains the Concourse pipeline definition for building a line-server container
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.0 KiB

  1. package main
  2. import (
  3. "bytes"
  4. "crypto/sha1"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "time"
  9. "github.com/zeebo/bencode"
  10. "github.com/zenazn/goji/web"
  11. )
  12. const (
  13. TORRENT_PIECE_LENGTH = 262144
  14. )
  15. type TorrentInfo struct {
  16. PieceLength int `bencode:"piece length"`
  17. Pieces string `bencode:"pieces"`
  18. Name string `bencode:"name"`
  19. Length int `bencode:"length"`
  20. }
  21. type Torrent struct {
  22. Encoding string `bencode:"encoding"`
  23. Info TorrentInfo `bencode:"info"`
  24. UrlList []string `bencode:"url-list"`
  25. }
  26. func hashPiece(piece []byte) []byte {
  27. h := sha1.New()
  28. h.Write(piece)
  29. return h.Sum(nil)
  30. }
  31. func createTorrent(fileName string, f io.ReadCloser, r *http.Request) ([]byte, error) {
  32. chunk := make([]byte, TORRENT_PIECE_LENGTH)
  33. torrent := Torrent{
  34. Encoding: "UTF-8",
  35. Info: TorrentInfo{
  36. PieceLength: TORRENT_PIECE_LENGTH,
  37. Name: fileName,
  38. },
  39. UrlList: []string{fmt.Sprintf("%sselif/%s", getSiteURL(r), fileName)},
  40. }
  41. for {
  42. n, err := f.Read(chunk)
  43. if err == io.EOF {
  44. break
  45. } else if err != nil {
  46. return []byte{}, err
  47. }
  48. torrent.Info.Length += n
  49. torrent.Info.Pieces += string(hashPiece(chunk[:n]))
  50. }
  51. data, err := bencode.EncodeBytes(&torrent)
  52. if err != nil {
  53. return []byte{}, err
  54. }
  55. return data, nil
  56. }
  57. func fileTorrentHandler(c web.C, w http.ResponseWriter, r *http.Request) {
  58. fileName := c.URLParams["name"]
  59. err := checkFile(fileName)
  60. if err == NotFoundErr {
  61. notFoundHandler(c, w, r)
  62. return
  63. } else if err == BadMetadata {
  64. oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
  65. return
  66. }
  67. f, err := fileBackend.Open(fileName)
  68. if err != nil {
  69. oopsHandler(c, w, r, RespHTML, "Could not create torrent.")
  70. return
  71. }
  72. defer f.Close()
  73. encoded, err := createTorrent(fileName, f, r)
  74. if err != nil {
  75. oopsHandler(c, w, r, RespHTML, "Could not create torrent.")
  76. return
  77. }
  78. w.Header().Set(`Content-Disposition`, fmt.Sprintf(`attachment; filename="%s.torrent"`, fileName))
  79. http.ServeContent(w, r, "", time.Now(), bytes.NewReader(encoded))
  80. }