-
Notifications
You must be signed in to change notification settings - Fork 3
/
gogridfs.go
180 lines (146 loc) · 3.96 KB
/
gogridfs.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package main
import (
"labix.org/v2/mgo"
"fmt"
"bytes"
"net/http"
"io"
"io/ioutil"
"encoding/json"
"flag"
"log"
"os"
"strings"
)
// file path and content
type gridfile struct {
Path string
Data bytes.Buffer
}
// make gridfs, logger and config globally accessible
type gogridfs struct {
GFS *mgo.GridFS
Logger *log.Logger
Conf config
}
var ggfs gogridfs
// config options to unmarshaled from json
type config struct {
Servers []string
Logfile string
Database string
GridFSCollection string
Listen string
HandlePath string
Debug bool
Mode string
}
// load config from json file
func loadConfig(file string) (err error) {
b_file, err := ioutil.ReadFile(file)
if err != nil { return }
err = json.Unmarshal(b_file, &ggfs.Conf)
return
}
// fetch file from gridfs
func getFile (path string) (file bytes.Buffer, err error) {
// open gridfile where path is the filename in GridFS
gfsFile, err := ggfs.GFS.Open(path)
if err != nil {
return
}
// read file into buffer
for {
buffer := make([]byte, 4096)
bytes_r, err := gfsFile.Read(buffer)
if bytes_r > 0 {
file.Write(buffer[:bytes_r])
}
if err != nil { break }
}
// non EOF error are to be handled
if err != io.EOF {
return
}
// close gridfile
err = gfsFile.Close()
if err != nil {
return
}
return
}
// handle HTTP requests
func fileHandler(w http.ResponseWriter, r *http.Request) {
// cut handlepath from URL path
// remainder will be the filename to fetch from GridFS
path := r.URL.Path[len(ggfs.Conf.HandlePath):]
// print requested path when debugging
if ggfs.Conf.Debug == true {
ggfs.Logger.Println(path)
}
data, err := getFile(path)
// build the file struct
file := gridfile{Path: path, Data: data}
if err != nil {
ggfs.Logger.Println(err)
}
// print buffer to response writer
fmt.Fprintf(w, "%s", file.Data.String())
}
func main() {
// get config file from command line args
var config_file = flag.String("config", "config.json", "Config file in JSON format")
flag.Parse()
// load config from JSON file
err := loadConfig(*config_file)
// panic on errors before the log file is in place
if err != nil {
panic(err)
}
// initialize log writer
var writer io.Writer
if ggfs.Conf.Logfile == "" {
writer = os.Stdout
} else {
writer, err = os.OpenFile(ggfs.Conf.Logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0750)
// panic on errors before the log file is in place
if err != nil {
panic(err)
}
}
ggfs.Logger = log.New(writer, "", 5)
// concatenate mongodb servers to single string of comma seperated servers
var servers string
for _, server := range ggfs.Conf.Servers {
servers += (server + ",")
}
// determine mode
// Strong (safe) => 2
// Monotonic (fast) => 1
// Eventual (faster) => 0
// default => 2
mode := mgo.Strong
if strings.ToLower(ggfs.Conf.Mode) == "monotonic" {
ggfs.Logger.Println("mgo connection mode: monotonic")
mode = mgo.Monotonic
} else if strings.ToLower(ggfs.Conf.Mode) == "eventual" {
ggfs.Logger.Println("mgo connection mode: eventual")
mode = mgo.Eventual
}
// die if no servers are configured
if servers == "" {
ggfs.Logger.Fatalln("No mongodb servers. Please adjust your config file.")
}
// connect to mongodb
mgo_session, err := mgo.Dial(servers)
mgo_session.SetMode(mode, true)
if err != nil {
ggfs.Logger.Fatalln(err)
}
defer mgo_session.Close()
// get gridfs
ggfs.GFS = mgo_session.DB(ggfs.Conf.Database).GridFS(ggfs.Conf.GridFSCollection)
// run webserver
http.HandleFunc(ggfs.Conf.HandlePath, fileHandler)
http.ListenAndServe(ggfs.Conf.Listen, nil)
}