-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
124 lines (104 loc) · 2.96 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"fmt"
"github.com/codegangsta/negroni"
"github.com/gorilla/mux"
"net/http"
"path"
"os"
"os/user"
"io"
"encoding/json"
"path/filepath"
"github.com/unrolled/render"
)
// config configures directory to be looked upon.
type config struct {
LookupDir string `json:"directory"`
}
type HomeDisplay struct {
User, Title, ServingDir string
Files []string
}
func main() {
// get a router, with a default home handler
r := mux.NewRouter()
// read the configuration from the file in the directory
conf := readConfig()
// get the current user. If there is a problem, panic. TODO: refactor.
currentUser, err := user.Current()
if err != nil {
panic(err)
}
// the dir on which we are serving
servingDir := path.Join(currentUser.HomeDir, conf.LookupDir)
// find a file by name, on the /streamr/{id} URL
f := r.PathPrefix("/streamr").Subrouter()
// inject to the stream handler function through a closure the configuration and the current user.
f.HandleFunc("/{id}", streamHandler(conf, currentUser)).Name("file")
// construct the array of files which we can serve from.
files := make([]string, 0)
err = filepath.Walk(servingDir, func(path string, info os.FileInfo, err error) error {
if err == nil {
if servingDir != path {
url, err := r.Get("file").URL("id", filepath.Base(path))
if err != nil {
return err
}
files = append(files, url.String())
}
}
return nil
})
if err != nil {
fmt.Println(err)
}
r.HandleFunc("/", homeHandler(render.New(), HomeDisplay{
Title: "Streamr",
User: currentUser.Name,
ServingDir: servingDir,
Files: files,
}))
// start negroni
n := negroni.Classic()
n.UseHandler(r)
n.Run(":3000")
}
// returns a default configuration if the file is fucked up
func readConfig() config {
var conf config
defaultConfig := config{LookupDir: "streamr"}
j, err := os.Open("streamr.json")
if err != nil {
return defaultConfig
}
dec := json.NewDecoder(j)
if err = dec.Decode(&conf); err != nil {
return defaultConfig
}
return conf
}
// returns a http.HandlerFunc that handles the current user and configuration.
func streamHandler(conf config, current *user.User) http.HandlerFunc {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
// extract the file name and look it up, on HomeDir/LookupDir/FileName.
vars := mux.Vars(r)
filePath := path.Join(current.HomeDir, conf.LookupDir, vars["id"])
file, err := os.Open(filePath)
if err != nil {
// the file most likely doesn't exists.
// TODO: handle better this kind of error.
http.Error(w, http.StatusText(404), 404)
fmt.Fprintf(w, err.Error())
return
}
// copy from file to http.ResponseWriter (efficient)
w.Header().Set("Content-Disposition", "attachment")
io.Copy(w, file)
})
}
func homeHandler(renderer *render.Render, data HomeDisplay) http.HandlerFunc {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
renderer.HTML(w, http.StatusOK, "home-template", data)
})
}