From 7a00c288b0e66685bea72c4383355639a601ef3d Mon Sep 17 00:00:00 2001 From: nemunaire Date: Sun, 24 Apr 2016 21:54:14 +0200 Subject: [PATCH] Initial go version commit --- api.go | 83 ++++++++++++++++++++++++++++++++++++++++++++ api_version.go | 9 +++++ contents/config.json | 1 + main.go | 49 ++++++++++++++++++++++++++ see.go | 44 +++++++++++++++++++++++ static/css/style.css | 44 +++++++++++++++++++++++ 6 files changed, 230 insertions(+) create mode 100644 api.go create mode 100644 api_version.go create mode 100644 contents/config.json create mode 100644 main.go create mode 100644 see.go create mode 100644 static/css/style.css diff --git a/api.go b/api.go new file mode 100644 index 0000000..dc91038 --- /dev/null +++ b/api.go @@ -0,0 +1,83 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "strings" +) + +type DispatchFunction func([]string, []byte) (interface{}, error) + +var apiRouting = map[string]*(map[string]DispatchFunction){ + "version": &ApiVersionRouting, +} + +func ApiRouting(w http.ResponseWriter, r *http.Request) { + log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) + + // Extract URL arguments + var sURL = strings.Split(r.URL.Path, "/") + if sURL[len(sURL)-1] == "" && len(sURL) > 2 { + // Remove trailing / + sURL = sURL[:len(sURL)-1] + } + + w.Header().Set("Content-Type", "application/json") + + var ret interface{} + var err error = nil + + // Read the body + if r.ContentLength < 0 || r.ContentLength > 10485760 { + http.Error(w, "{errmsg:\"Request too large or request size unknown\"}", http.StatusRequestEntityTooLarge) + return + } + var body []byte + if r.ContentLength > 0 { + tmp := make([]byte, 1024) + for { + n, err := r.Body.Read(tmp) + for j := 0; j < n; j++ { + body = append(body, tmp[j]) + } + if err != nil || n <= 0 { + break + } + } + } + + // Route request + if len(sURL) > 2 { + if h, ok := apiRouting[sURL[2]]; ok { + if f, ok := (*h)[r.Method]; ok { + ret, err = f(sURL[3:], body) + } else { + err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[2])) + } + } + } else { + err = errors.New(fmt.Sprintf("No action provided for %s", sURL[1])) + } + + // Format response + resStatus := http.StatusOK + if err != nil { + ret = map[string]string{"errmsg": err.Error()} + resStatus = http.StatusBadRequest + } + + if ret == nil { + ret = map[string]string{"errmsg": "Page not found"} + resStatus = http.StatusNotFound + } + + if j, err := json.Marshal(ret); err != nil { + http.Error(w, fmt.Sprintf("{errmsg:\"%q\"}", err), http.StatusInternalServerError) + } else { + w.WriteHeader(resStatus) + w.Write(j) + } +} diff --git a/api_version.go b/api_version.go new file mode 100644 index 0000000..c6682ea --- /dev/null +++ b/api_version.go @@ -0,0 +1,9 @@ +package main + +var ApiVersionRouting = map[string]DispatchFunction{ + "GET": showVersion, +} + +func showVersion(args []string, body []byte) (interface{}, error) { + return map[string]interface{}{"version": 0.1}, nil +} diff --git a/contents/config.json b/contents/config.json new file mode 100644 index 0000000..6b32b65 --- /dev/null +++ b/contents/config.json @@ -0,0 +1 @@ +{"name":"YouP0m"} diff --git a/main.go b/main.go new file mode 100644 index 0000000..53ddeaa --- /dev/null +++ b/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "path/filepath" +) + +func readConfig(path string) (map[string]string, error) { + var config map[string]string + + if cnt_raw, err := ioutil.ReadFile(path); err != nil { + return nil, err + } else if err := json.Unmarshal(cnt_raw, &config); err != nil { + return nil, err + } else { + return config, nil + } +} + +func main() { + var port = flag.Int("port", 8080, "Listening port") + var sitedir = flag.String("sitedir", "./contents/", "Directory containing site content and pictures") + flag.Parse() + + log.Println("Reading site configuration...") + if config, err := readConfig(filepath.Join(*sitedir, "config.json")); err != nil { + log.Fatal(err) + os.Exit(1) + } else { + log.Println("Registering handlers...") + mux := http.NewServeMux() + mux.Handle("/favicon.ico", http.FileServer(http.Dir("./static/"))) + mux.Handle("/static/", http.FileServer(http.Dir("./"))) + mux.Handle("/doc/", http.FileServer(http.Dir("./"))) + mux.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir(filepath.Join(*sitedir, "current"))))) + mux.HandleFunc("/api/", ApiRouting) + mux.HandleFunc("/", SeeRouting) + http.HandleFunc("/", mux.ServeHTTP) + + log.Println(fmt.Sprintf("Site ready (n=%s), listening on port %d", config["name"], *port)) + http.ListenAndServe(fmt.Sprintf(":%d", *port), nil) + } +} diff --git a/see.go b/see.go new file mode 100644 index 0000000..bcf1ded --- /dev/null +++ b/see.go @@ -0,0 +1,44 @@ +package main + +import ( + "html" + "log" + "net/http" + "strings" +) + +func SeeRouting(w http.ResponseWriter, r *http.Request) { + log.Printf("Handling request %s: %s\n", r.Method, r.URL.Path) + + // Extract URL arguments + var sURL = strings.Split(r.URL.Path, "/") + if sURL[len(sURL)-1] == "" && len(sURL) > 2 { + // Remove trailing / + sURL = sURL[:len(sURL)-1] + } + + if len(sURL) < 3 { + http.Error(w, "Please provide a valid hash", http.StatusForbidden) + } else { + w.Header().Set("Content-Type", "text/html") + + w.Write([]byte(` + + + OhSnap + + + + + +
+ ` + html.EscapeString(`)) + if "name" != "" { + w.Write([]byte(`
` + html.EscapeString("name") + `
`)) + } + w.Write([]byte(`
+ + +`)) + } +} diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000..aad714c --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,44 @@ +body { + background: #222; + color: #EEE; + margin: 0; + width: 100%; +} + +figure.big { + display: table; + margin: auto; + text-align: center; + padding: 10px 0; + vertical-align: middle; +} + +.big img { + height: calc(100vh - 20px); + max-width: 100vw; +} + +img +{ + border-radius: 20px 0 20px 0; + box-shadow: 0px 0px 10px #9AB; + transition: box-shadow 1s ease-out; + -moz-transition: box-shadow 1.23s ease-out; +} +img:hover +{ + display: table-cell; + box-shadow: 0px 0px 20px #FED; +} + + +.big figcaption +{ + background: #656565; + color: #FFF; + font-weight: bold; + margin: -100px auto; + opacity: 0.65; + padding: 10px; + position: relative; +}