src/app/proxy.go (view raw)
1package app
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "log"
8 "net/http"
9 "strconv"
10 "time"
11
12 g "github.com/birabittoh/gopipe/src/globals"
13)
14
15func proxyHandler(w http.ResponseWriter, r *http.Request) {
16 if !g.Proxy {
17 http.Error(w, err404, http.StatusNotFound)
18 return
19 }
20
21 videoID := r.PathValue("videoID")
22 formatID := getFormatID(r.PathValue("formatID"))
23
24 video, err := g.KS.Get(videoID)
25 if err != nil || video == nil {
26 http.Error(w, err404, http.StatusNotFound)
27 return
28 }
29
30 if video.ID == emptyVideo.ID {
31 http.Error(w, err500, http.StatusInternalServerError)
32 return
33 }
34
35 format := getFormat(*video, formatID)
36 if format == nil {
37 http.Error(w, err500, http.StatusInternalServerError)
38 return
39 }
40
41 key := fmt.Sprintf("%s:%d", videoID, formatID)
42 content, err := g.PKS.Get(key)
43 if err == nil && content != nil {
44 log.Println("Using cached content for ", key)
45 w.Header().Set("Content-Type", "video/mp4")
46 w.Header().Set("Content-Length", strconv.Itoa(content.Len()))
47 w.Write(content.Bytes())
48 return
49 }
50
51 res, err := g.C.Get(format.URL)
52 if err != nil {
53 http.Error(w, err500, http.StatusInternalServerError)
54 return
55 }
56 defer res.Body.Close()
57
58 w.Header().Set("Content-Type", res.Header.Get("Content-Type"))
59 w.Header().Set("Content-Length", res.Header.Get("Content-Length"))
60
61 pr, pw := io.Pipe()
62
63 // Save the content to the cache asynchronously
64 go func() {
65 var buf bytes.Buffer
66 _, err := io.Copy(&buf, pr)
67 if err != nil {
68 log.Println("Error while copying to buffer for cache:", err)
69 return
70 }
71
72 g.PKS.Set(key, buf, 5*time.Minute)
73 pw.Close()
74 }()
75
76 // Stream the content to the client while it's being downloaded and piped
77 _, err = io.Copy(io.MultiWriter(w, pw), res.Body)
78 if err != nil {
79 http.Error(w, err500, http.StatusInternalServerError)
80 return
81 }
82}