diff options
| -rw-r--r-- | src/dict2rest/dict.go | 93 | ||||
| -rw-r--r-- | src/dict2rest/handlers.go | 103 | ||||
| -rw-r--r-- | src/dict2rest/logger.go | 4 | ||||
| -rw-r--r-- | src/dict2rest/main.go | 50 |
4 files changed, 154 insertions, 96 deletions
diff --git a/src/dict2rest/dict.go b/src/dict2rest/dict.go index d3ae1e5..fa9690e 100644 --- a/src/dict2rest/dict.go +++ b/src/dict2rest/dict.go @@ -1,13 +1,8 @@ package main import ( - "encoding/json" - "github.com/julienschmidt/httprouter" "golang.org/x/net/dict" "log" - "net/http" - "strconv" - "strings" ) type definition struct { @@ -20,85 +15,33 @@ type dictionary struct { Desc string `json:"description"` } -type jsonError struct { - Code int `json:"code"` - Message string `json:"message"` -} - -func Render(w http.ResponseWriter, status int, body interface{}) { - w.WriteHeader(status) - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - json.NewEncoder(w).Encode(body) -} - -func FormatError(e error) jsonError { - parts := strings.SplitN(e.Error(), "[", 2) - log.Printf("Error %s", parts[0]) - parts = strings.SplitN(parts[0], " ", 2) - code, err := strconv.Atoi(parts[0]) +func getDictClient() (*dict.Client, error) { + client, err := dict.Dial("tcp", dictServer) if err != nil { - return jsonError{ - Code: 500, - Message: "Error parsing error o_0", - } - } - return jsonError{ - Code: code, - Message: strings.TrimSpace(parts[1]), + log.Printf("Unable to connect to dict server at %s", dictServer) + return nil, err } + log.Println("Connected to", dictServer) + return client, nil } -func FormatDefinitions(defs []*dict.Defn) ([]definition, error) { - definitions := make([]definition, len(defs)) - for i, def := range defs { - definitions[i] = definition{ - Dictionary: def.Dict.Desc, - Word: def.Word, - Definition: string(def.Text[:]), - } - } - return definitions, nil -} - -func Databases(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - var dicts []dictionary - for _, d := range dictMap { - dicts = append(dicts, dictionary{d.Name, d.Desc}) - } - if len(dicts) == 0 { - Render(w, 200, jsonError{554, "No databases present"}) - return +func getDictionaries(*dict.Client) ([]dictionary, error) { + client, err := getDictClient() + if err != nil { + log.Printf("Unable to connect to dict server at %s", dictServer) + return nil, err } - Render(w, 200, dicts) -} - -func Define(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - word := ps.ByName("word") - queryValues := r.URL.Query() - d := queryValues.Get("dict") - var dict string + defer client.Close() - _, ok := dictMap[d] - if d != "" && !ok { - Render(w, 400, jsonError{500, "Invalid database"}) - return - } else if d != "" && ok { - dict = d - } else { - dict = "*" - } - defs, err := client.Define(dict, word) + dictArr, err := client.Dicts() if err != nil { - Render(w, 400, FormatError(err)) - return + return nil, err } - //log.Printf("DEFINE '%s' from '%s' found %d definitions", word, dict, len(defs)) - definitions, err := FormatDefinitions(defs) - if err != nil { - Render(w, 500, err) - return + var dicts []dictionary + for _, d := range dictArr { + dicts = append(dicts, dictionary{d.Name, d.Desc}) } - Render(w, 200, definitions) + return dicts, nil } diff --git a/src/dict2rest/handlers.go b/src/dict2rest/handlers.go new file mode 100644 index 0000000..024a8d6 --- /dev/null +++ b/src/dict2rest/handlers.go @@ -0,0 +1,103 @@ +package main + +import ( + "encoding/json" + "github.com/julienschmidt/httprouter" + "golang.org/x/net/dict" + "log" + "net/http" + "strconv" + "strings" +) + +type jsonError struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func render(w http.ResponseWriter, status int, body interface{}) { + w.WriteHeader(status) + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + json.NewEncoder(w).Encode(body) +} + +func formatError(e error) jsonError { + parts := strings.SplitN(e.Error(), "[", 2) + log.Printf("Error %s", parts[0]) + parts = strings.SplitN(parts[0], " ", 2) + code, err := strconv.Atoi(parts[0]) + if err != nil { + return jsonError{ + Code: 500, + Message: "Error parsing error o_0", + } + } + return jsonError{ + Code: code, + Message: strings.TrimSpace(parts[1]), + } +} + +func formatDefinitions(defs []*dict.Defn) ([]definition, error) { + definitions := make([]definition, len(defs)) + for i, def := range defs { + definitions[i] = definition{ + Dictionary: def.Dict.Desc, + Word: def.Word, + Definition: string(def.Text[:]), + } + } + return definitions, nil +} + +func dictDatabases(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + client, err := getDictClient() + if err != nil { + log.Printf("Unable to connect to dict server at %s", dictServer) + render(w, 500, jsonError{420, "Server temporarily unavailable"}) + return + } + + defer client.Close() + + dicts, err := getDictionaries(client) + if err != nil { + render(w, 400, formatError(err)) + return + } + render(w, 200, dicts) +} + +func dictDefine(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + client, err := getDictClient() + if err != nil { + render(w, 500, jsonError{420, "Server temporarily unavailable"}) + return + } + defer client.Close() + + word := ps.ByName("word") + queryValues := r.URL.Query() + d := queryValues.Get("dict") + + var dict string + + if d != "" { + dict = d + } else { + dict = "*" + } + + defs, err := client.Define(dict, word) + if err != nil { + render(w, 400, formatError(err)) + return + } + + definitions, err := formatDefinitions(defs) + if err != nil { + render(w, 500, err) + return + } + render(w, 200, definitions) +} diff --git a/src/dict2rest/logger.go b/src/dict2rest/logger.go index b4b1187..709666b 100644 --- a/src/dict2rest/logger.go +++ b/src/dict2rest/logger.go @@ -20,8 +20,8 @@ func Logger(next http.Handler) http.Handler { size, _ := bw.Apply(w) // Usually milliseconds - latency := time.Since(startTime).Seconds() + latency := time.Since(startTime).Seconds() * 1000 - log.Printf("%s %s %d %d (%v)\n", r.Method, r.URL.Path, bw.Status, size, latency) + log.Printf("%s %s %d %d (%.1fms)\n", r.Method, r.URL.Path, bw.Status, size, latency) }) } diff --git a/src/dict2rest/main.go b/src/dict2rest/main.go index bbdd5d6..608ab8c 100644 --- a/src/dict2rest/main.go +++ b/src/dict2rest/main.go @@ -4,16 +4,16 @@ import ( "flag" "github.com/julienschmidt/httprouter" "github.com/justinas/alice" + "github.com/rs/cors" "github.com/stretchr/graceful" - "golang.org/x/net/dict" "log" "net/http" "os" "time" ) -var client *dict.Client -var dictMap map[string]dict.Dict +// Globals +var dictServer string func main() { var err error @@ -25,35 +25,47 @@ func main() { flag.Parse() - server := *dictHost + ":" + *dictPort - client, err = dict.Dial("tcp", server) + dictServer = *dictHost + ":" + *dictPort + + client, err := getDictClient() if err != nil { - log.Printf("Unable to connect to dict server %s", server) os.Exit(1) } - log.Println("Connected to", server) - var dictArr []dict.Dict - dictArr, err = client.Dicts() + // Get the global list of databases + dicts, err := getDictionaries(client) if err != nil { - log.Fatal("Unable to get dictionaries") + log.Println("Unable to get database list") + os.Exit(1) } - dictMap = make(map[string]dict.Dict) - for _, d := range dictArr { - log.Println("Using dictionary", d.Name, d.Desc) - dictMap[d.Name] = d + for _, d := range dicts { + log.Printf("Available dictionary %s: %s", d.Name, d.Desc) } + // No need for it until a request comes in + client.Close() + // Define our routes router := httprouter.New() + router.GET("/define/:word", dictDefine) + router.GET("/databases", dictDatabases) + router.GET("/db", dictDatabases) + + // Define our middlewares - router.GET("/define/:word", Define) - router.GET("/databases", Databases) - router.GET("/db", Databases) + // Going to need some CORS headers + cors := cors.New(cors.Options{ + AllowedHeaders: []string{ + "Accept", "Content-Type", "Origin", + }, + AllowedMethods: []string{ + "GET", "OPTIONS", + }, + }) - chain := alice.New(Logger).Then(router) + chain := alice.New(cors.Handler, Logger).Then(router) if *gzip { - chain = alice.New(Logger, Gzip).Then(router) + chain = alice.New(cors.Handler, Logger, Gzip).Then(router) log.Println("Using Gzip compression") } |
