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 format := getFormat(*video, formatID)
31 if format == nil {
32 http.Error(w, err500, http.StatusInternalServerError)
33 return
34 }
35
36 key := fmt.Sprintf("%s:%d", videoID, formatID)
37 content, err := g.PKS.Get(key)
38 if err == nil && content != nil {
39 log.Println("Using cached content for ", key)
40 w.Header().Set("Content-Type", "video/mp4")
41 w.Header().Set("Content-Length", strconv.Itoa(content.Len()))
42 w.Write(content.Bytes())
43 return
44 }
45
46 res, err := g.C.Get(format.URL)
47 if err != nil {
48 http.Error(w, err500, http.StatusInternalServerError)
49 return
50 }
51 defer res.Body.Close()
52
53 w.Header().Set("Content-Type", res.Header.Get("Content-Type"))
54 w.Header().Set("Content-Length", res.Header.Get("Content-Length"))
55
56 pr, pw := io.Pipe()
57
58 // Save the content to the cache asynchronously
59 go func() {
60 var buf bytes.Buffer
61 _, err := io.Copy(&buf, pr)
62 if err != nil {
63 log.Println("Error while copying to buffer for cache:", err)
64 return
65 }
66
67 g.PKS.Set(key, buf, 5*time.Minute)
68 pw.Close()
69 }()
70
71 // Stream the content to the client while it's being downloaded and piped
72 _, err = io.Copy(io.MultiWriter(w, pw), res.Body)
73 if err != nil {
74 http.Error(w, err500, http.StatusInternalServerError)
75 return
76 }
77}