| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package dashboard
- import (
- "html/template"
- "math/rand"
- "net/http"
- "time"
- "github.com/gorilla/mux"
- "github.com/gorilla/websocket"
- )
- const (
- dashboard = "index.html"
- login = "login.html"
- dashboardPath = "html/index.html"
- loginPath = "html/login.html"
- sessionTimeout = time.Hour * 24 // TODO replace with config
- )
- var (
- // Cache of HTML templates
- templates = template.Must(template.ParseFiles(dashboardPath, loginPath))
- config *Config
- sessions sessionStore
- store *dataStore
- )
- var upgrader = websocket.Upgrader{
- ReadBufferSize: 1024,
- WriteBufferSize: 1024,
- }
- type Config struct {
- Username string
- Password string
- ListenInterface string
- }
- func Run(c *Config) {
- config = c
- r := mux.NewRouter()
- r.HandleFunc("/", indexHandler)
- r.HandleFunc("/login", loginHandler)
- r.HandleFunc("/ws", webSocketHandler)
- rand.Seed(time.Now().UnixNano())
- sessions = make(sessionStore)
- go sessions.cleaner(sessionTimeout)
- store = newDataStore()
- go ramListener(tickInterval, store)
- http.ListenAndServe(c.ListenInterface, r)
- }
- func indexHandler(w http.ResponseWriter, r *http.Request) {
- if isLoggedIn(r) {
- w.WriteHeader(http.StatusOK)
- templates.ExecuteTemplate(w, dashboard, nil)
- } else {
- http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
- }
- }
- func loginHandler(w http.ResponseWriter, r *http.Request) {
- switch r.Method {
- case "GET":
- if isLoggedIn(r) {
- http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
- } else {
- templates.ExecuteTemplate(w, login, nil)
- }
- case "POST":
- user := r.FormValue("username")
- pass := r.FormValue("password")
- if user == config.Username && pass == config.Password {
- err := startSession(w, r)
- if err != nil {
- w.WriteHeader(http.StatusInternalServerError)
- // TODO Internal error
- return
- }
- http.Redirect(w, r, "/", http.StatusSeeOther)
- } else {
- templates.ExecuteTemplate(w, login, nil) // TODO info about failed login
- }
- default:
- w.WriteHeader(http.StatusMethodNotAllowed)
- }
- }
- func webSocketHandler(w http.ResponseWriter, r *http.Request) {
- if !isLoggedIn(r) {
- w.WriteHeader(http.StatusForbidden)
- return
- }
- sess := getSession(r)
- conn, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- w.WriteHeader(http.StatusInternalServerError)
- // TODO Internal error
- return
- }
- sess.ws = conn
- c := make(chan *point)
- sess.send = c
- store.subscribe(c)
- go sess.receive()
- go sess.transmit()
- }
- func startSession(w http.ResponseWriter, r *http.Request) error {
- sessionID := newSessionID()
- cookie := &http.Cookie{
- Name: "SID",
- Value: sessionID,
- Path: "/",
- // Secure: true,
- }
- sess := &session{
- start: time.Now(),
- expires: time.Now().Add(sessionTimeout), // TODO config for this
- id: sessionID,
- }
- http.SetCookie(w, cookie)
- sessions[sessionID] = sess
- return nil
- }
- func getSession(r *http.Request) *session {
- c, err := r.Cookie("SID")
- if err != nil {
- return nil
- }
- sid := c.Value
- sess, ok := sessions[sid]
- if !ok {
- return nil
- }
- return sess
- }
- func isLoggedIn(r *http.Request) bool {
- sess := getSession(r)
- if sess == nil {
- return false
- }
- if !sess.valid() {
- return false
- }
- return true
- }
|