Add basic html/js to search for and display some books.
[quanweb.git] / main / handler.go
1 package main
2
3 import (
4   "encoding/json"
5   "fmt"
6   "io"
7   "net/http"
8   "os"
9   "strconv"
10   "strings"
11 )
12
13 const PARAM_IDS = "ids"
14 const MAX_TERMS = 10
15
16 // ============================================================================
17 func efsPathForId(efsId int) string {
18   config := getConfig()
19
20   idStr := fmt.Sprintf("%010d", efsId)
21   path := fmt.Sprintf("%s/%s/%s/%s/%s/%s.dat", config.efsBasePath, idStr[0:2], idStr[2:4], idStr[4:6], idStr[6:8], idStr)
22
23   return path
24 }
25
26 func handler(w http.ResponseWriter, r *http.Request) {
27   err := r.ParseForm()
28   if nil != err {
29     fmt.Fprintln(w, "ERROR!", err)
30     return
31   }
32
33   action := strings.Split(r.URL.Path[1:], "/")[0]
34
35   switch(action) {
36   case "download":
37     handleDownload(w, r)
38   case "info":
39     handleInfo(w, r)
40   case "search":
41     handleSearch(w, r)
42   default:
43     fmt.Fprintf(w, "Unrecognized request:  %s\n", r.URL.Path[1:])
44     fmt.Fprintf(w, "id: %s\n", r.FormValue("id"))
45   
46     fmt.Fprintln(w, "URL: ", r.URL)
47     fmt.Fprintln(w, "Query: ", r.URL.Query())
48   }
49 }
50
51 /*
52 func handleApp(w http.ResponseWriter, r *http.Request) {
53   fmt.Println("handleApp():", r.URL.Path)
54
55   // Security check:  prevent walking up the directory
56   pos := strings.Index(r.Url.Path, "../")
57   if (-1) == pos {
58     fmt.Fprintln(w, "Paths containing \"../\" are not permitted:", r.URL.Path)
59     return
60   }
61
62   fileName := "../app" + r.URL.Path
63   _, err := os.Stat(fileName)
64   if nil != err { 
65     fmt.Fprintln(w, "Failed to find file:", fileName, err)
66     return
67   }
68
69   http.ServeFile(w, r, "../app/" + r.URL.Path[1:])
70 }
71 */
72
73 func handleDownload(w http.ResponseWriter, r *http.Request) {
74   path := r.URL.Path[1:]
75   tok := strings.Split(path, "/")
76   if 2 != len(tok)  {
77     fmt.Fprintln(w, "Unexpected path for download:", path)
78     return
79   }
80   efsId, err := strconv.Atoi(tok[1])
81   if (nil != err) || (0 == efsId) {
82     fmt.Fprintln(w, "Invalid id for download:", path, err)
83     return
84   }
85   
86   mimeType := queryMimeTypeByEfsId(efsId)
87   if 0 == len(mimeType) {
88     fmt.Fprintln(w, "No MIME type found for id:", efsId)
89     return
90   }
91
92   efsPath := efsPathForId(efsId)
93
94   var fd *os.File
95   fd, err = os.Open(efsPath)
96   if nil != err {
97     fmt.Fprintln(w, "Failed to read file for id:", efsId, err)
98     return
99   }
100   defer fd.Close()
101
102   io.Copy(w, fd)
103 }
104
105 func handleInfo(w http.ResponseWriter, r *http.Request) {
106   idParams := r.Form[PARAM_IDS]
107   if 1 != len(idParams) {
108     fmt.Fprintln(w, "ERROR!  Detected either zero or multiple ids= parameters.  Exactly one expected.")
109     return 
110   } 
111
112   idParam := idParams[0]
113   idStrings := strings.Split(idParam, ",")
114   ids := make([]int, len(idStrings))
115   var err error
116   for i, v := range(idStrings) {
117     ids[i], err = strconv.Atoi(v)
118     if nil != err {
119       ids[i] = 0
120     }
121   }
122
123   books := queryBooksByIds(ids)
124
125   var jsonValue []byte
126   jsonValue, err = json.Marshal(books)
127   if nil != err {
128     fmt.Fprintln(w, "ERROR!", err)
129   } else {
130     w.Write(jsonValue)
131   }
132 }
133
134 func handleSearch(w http.ResponseWriter, r *http.Request) {
135   var err error
136   fmt.Println("DEBUG:  handleSearch():  " + r.URL.Path)
137
138   fields := []Field{Author, Title, Series}
139
140   terms := make([]SearchTerm, len(fields))
141   
142   count := 0
143   for _, fv := range(fields) {
144     paramName := fv.String()
145     paramValues := r.Form[paramName]
146     for _, pv := range(paramValues) {
147       fmt.Println("DEBUG:  handleSearch():  ", paramName, "=", pv)
148       if count >= len(terms) {
149         fmt.Printf("WARNING:  limit of %d search terms exceeded.  One or more terms ignored.", len(terms))
150         break
151       }
152       terms[count] = SearchTerm{Attribute:fv, Text:pv}
153       count++
154     }
155   }
156
157   terms = terms[:count]
158
159   ids := queryIds(terms)
160
161   jsonValue, err := json.Marshal(ids)
162   if nil != err {
163     fmt.Fprintln(w, "ERROR!", err)
164   } else {
165     w.Write(jsonValue)
166   }
167 }
168