Browse Source

Session, error page, fixes, rework

Vova Tkach 6 years ago
parent
commit
a43fff7076

+ 9 - 0
Gopkg.lock

@@ -17,12 +17,21 @@
   revision = "4fce983c6e02d13313582a3c9f089c06c7979e8f"
   revision = "4fce983c6e02d13313582a3c9f089c06c7979e8f"
   version = "v1.0.0"
   version = "v1.0.0"
 
 
+[[projects]]
+  digest = "1:287426c516549a444caa7e6bab8a44f4e23af54eb3a87fd49f13d7c5a7b06038"
+  name = "github.com/vladimirok5959/golang-server-sessions"
+  packages = ["session"]
+  pruneopts = "UT"
+  revision = "c6d341a14a93caab1ba52fb552527ad88a5fa53b"
+  version = "v1.0.0"
+
 [solve-meta]
 [solve-meta]
   analyzer-name = "dep"
   analyzer-name = "dep"
   analyzer-version = 1
   analyzer-version = 1
   input-imports = [
   input-imports = [
     "github.com/vladimirok5959/golang-server-bootstrap/bootstrap",
     "github.com/vladimirok5959/golang-server-bootstrap/bootstrap",
     "github.com/vladimirok5959/golang-server-resources/resource",
     "github.com/vladimirok5959/golang-server-resources/resource",
+    "github.com/vladimirok5959/golang-server-sessions/session",
   ]
   ]
   solver-name = "gps-cdcl"
   solver-name = "gps-cdcl"
   solver-version = 1
   solver-version = 1

+ 39 - 0
consts/consts.go

@@ -3,3 +3,42 @@ package consts
 const Debug = !false
 const Debug = !false
 const ServerVersion = "1.0.1"
 const ServerVersion = "1.0.1"
 const AssetsVersion = "1"
 const AssetsVersion = "1"
+const AssetsPath = "assets"
+const DirIndexFile = "index.html"
+
+// Bootstrap resources
+const AssetsBootstrapCss = AssetsPath + "/bootstrap.css"
+const AssetsBootstrapJs = AssetsPath + "/bootstrap.js"
+const AssetsJqueryJs = AssetsPath + "/jquery.js"
+const AssetsPopperJs = AssetsPath + "/popper.js"
+
+// System resources
+const AssetsCpScriptsJs = AssetsPath + "/cp/scripts.js"
+const AssetsCpStylesCss = AssetsPath + "/cp/styles.css"
+const AssetsSysBgPng = AssetsPath + "/sys/bg.png"
+const AssetsSysFaveIco = AssetsPath + "/sys/fave.ico"
+const AssetsSysLogoPng = AssetsPath + "/sys/logo.png"
+const AssetsSysLogoSvg = AssetsPath + "/sys/logo.svg"
+const AssetsSysStylesCss = AssetsPath + "/sys/styles.css"
+
+// Template data
+type TmplSystem struct {
+	PathIcoFav       string
+	PathSvgLogo      string
+	PathCssStyles    string
+	PathCssCpStyles  string
+	PathCssBootstrap string
+	PathJsJquery     string
+	PathJsPopper     string
+	PathJsBootstrap  string
+	PathJsCpScripts  string
+}
+
+type TmplError struct {
+	ErrorMessage string
+}
+
+type TmplData struct {
+	System TmplSystem
+	Data   interface{}
+}

+ 85 - 135
main.go

@@ -1,40 +1,26 @@
 package main
 package main
 
 
 import (
 import (
+	"errors"
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
+	"os"
 
 
 	"golang-fave/assets"
 	"golang-fave/assets"
 	"golang-fave/consts"
 	"golang-fave/consts"
+	"golang-fave/static"
 	"golang-fave/utils"
 	"golang-fave/utils"
 
 
 	"github.com/vladimirok5959/golang-server-bootstrap/bootstrap"
 	"github.com/vladimirok5959/golang-server-bootstrap/bootstrap"
 	"github.com/vladimirok5959/golang-server-resources/resource"
 	"github.com/vladimirok5959/golang-server-resources/resource"
-	/*
-		"context"
-		"errors"
-		"flag"
-		"fmt"
-		"log"
-		"net/http"
-		"os"
-		"os/signal"
-		"strconv"
-		"strings"
-		"time"
-
-		"golang-fave/constants"
-		"golang-fave/engine/actions"
-		"golang-fave/engine/wrapper"
-	*/)
+	"github.com/vladimirok5959/golang-server-sessions/session"
+)
 
 
 var ParamHost string
 var ParamHost string
 var ParamPort int
 var ParamPort int
 var ParamWwwDir string
 var ParamWwwDir string
 
 
-//var VhostHomeDir string
-
 func init() {
 func init() {
 	flag.StringVar(&ParamHost, "host", "0.0.0.0", "server host")
 	flag.StringVar(&ParamHost, "host", "0.0.0.0", "server host")
 	flag.IntVar(&ParamPort, "port", 8080, "server port")
 	flag.IntVar(&ParamPort, "port", 8080, "server port")
@@ -44,25 +30,29 @@ func init() {
 
 
 func main() {
 func main() {
 	ParamWwwDir = utils.FixPath(ParamWwwDir)
 	ParamWwwDir = utils.FixPath(ParamWwwDir)
-	if !(utils.IsFileExists(ParamWwwDir) && utils.IsDir(ParamWwwDir)) {
+	if !utils.IsHostDirExists(ParamWwwDir) {
 		fmt.Println("Virtual hosts directory is not exists")
 		fmt.Println("Virtual hosts directory is not exists")
 		fmt.Println("Example: ./fave -host 127.0.0.1 -port 80 -dir ./hosts")
 		fmt.Println("Example: ./fave -host 127.0.0.1 -port 80 -dir ./hosts")
 		return
 		return
 	}
 	}
 
 
 	res := resource.New()
 	res := resource.New()
-	res.Add("assets/cp/scripts.js", "application/javascript; charset=utf-8", assets.CpScriptsJs)
-	res.Add("assets/cp/styles.css", "text/css", assets.CpStylesCss)
-	res.Add("assets/sys/bg.png", "image/png", assets.SysBgPng)
-	res.Add("assets/sys/fave.ico", "image/x-icon", assets.SysFaveIco)
-	res.Add("assets/sys/logo.png", "image/png", assets.SysLogoPng)
-	res.Add("assets/sys/logo.svg", "image/svg+xml", assets.SysLogoSvg)
-	res.Add("assets/sys/styles.css", "text/css", assets.SysStylesCss)
-
-	bootstrap.Start(fmt.Sprintf("%s:%d", ParamHost, ParamPort), 30, "assets", func(w http.ResponseWriter, r *http.Request) {
+	res.Add(consts.AssetsCpScriptsJs, "application/javascript; charset=utf-8", assets.CpScriptsJs)
+	res.Add(consts.AssetsCpStylesCss, "text/css", assets.CpStylesCss)
+	res.Add(consts.AssetsSysBgPng, "image/png", assets.SysBgPng)
+	res.Add(consts.AssetsSysFaveIco, "image/x-icon", assets.SysFaveIco)
+	res.Add(consts.AssetsSysLogoPng, "image/png", assets.SysLogoPng)
+	res.Add(consts.AssetsSysLogoSvg, "image/svg+xml", assets.SysLogoSvg)
+	res.Add(consts.AssetsSysStylesCss, "text/css", assets.SysStylesCss)
+
+	// TODO: Move this to `"github.com/vladimirok5959/golang-server-static/static"`
+	stat := static.New(consts.DirIndexFile)
+
+	// TODO: Logic as object here
+
+	bootstrap.Start(fmt.Sprintf("%s:%d", ParamHost, ParamPort), 30, consts.AssetsPath, func(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Server", "fave.pro/"+consts.ServerVersion)
 		w.Header().Set("Server", "fave.pro/"+consts.ServerVersion)
 	}, func(w http.ResponseWriter, r *http.Request) {
 	}, func(w http.ResponseWriter, r *http.Request) {
-
 		// Mounted assets
 		// Mounted assets
 		if res.Response(w, r, func(w http.ResponseWriter, r *http.Request, i *resource.Resource) {
 		if res.Response(w, r, func(w http.ResponseWriter, r *http.Request, i *resource.Resource) {
 			w.Header().Set("Cache-Control", "public, max-age=31536000")
 			w.Header().Set("Cache-Control", "public, max-age=31536000")
@@ -70,127 +60,87 @@ func main() {
 			return
 			return
 		}
 		}
 
 
-		/*
-			// After callback
-			w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
-			w.Header().Set("Content-Type", "text/html")
-			w.Write([]byte(`
-				<div>Hello World!</div>
-				<div><a href="/assets/bootstrap.css">/assets/bootstrap.css</a></div>
-				<div><a href="/assets/bootstrap.js">/assets/bootstrap.js</a></div>
-				<div><a href="/assets/jquery.js">/assets/jquery.js</a></div>
-				<div><a href="/assets/popper.js">/assets/popper.js</a></div>
-			`))
-		*/
+		// Host and port
+		host, port := utils.ExtractHostPort(r.Host, false)
+		vhost_dir := ParamWwwDir + string(os.PathSeparator) + host
+		if !utils.IsHostDirExists(vhost_dir) {
+			vhost_dir = ParamWwwDir + string(os.PathSeparator) + "localhost"
+		}
 
 
-	})
+		// Check for minimal dir structure
+		vhost_dir_config := vhost_dir + string(os.PathSeparator) + "config"
+		vhost_dir_htdocs := vhost_dir + string(os.PathSeparator) + "htdocs"
+		vhost_dir_logs := vhost_dir + string(os.PathSeparator) + "logs"
+		vhost_dir_template := vhost_dir + string(os.PathSeparator) + "template"
+		vhost_dir_tmp := vhost_dir + string(os.PathSeparator) + "tmp"
 
 
-	/*
-		if _, err := os.Stat(ParamWwwDir); os.IsNotExist(err) {
-			fmt.Println("Virtual hosts directory is not exists")
-			fmt.Println("Example: ./fave -host 127.0.0.1 -port 80 -dir ./hosts")
+		if !utils.IsHostDirExists(vhost_dir_config) {
+			utils.SystemErrorPage(w, errors.New("Folder "+vhost_dir_config+" is not found"))
 			return
 			return
 		}
 		}
-		if ParamWwwDir[len(ParamWwwDir)-1] != '/' {
-			ParamWwwDir = ParamWwwDir + "/"
+		if !utils.IsHostDirExists(vhost_dir_htdocs) {
+			utils.SystemErrorPage(w, errors.New("Folder "+vhost_dir_htdocs+" is not found"))
+			return
 		}
 		}
-
-		// Handle
-		mux := http.NewServeMux()
-		mux.HandleFunc("/", handler)
-
-		srv := &http.Server{
-			Addr:    fmt.Sprintf("%s:%d", ParamHost, ParamPort),
-			Handler: mux,
+		if !utils.IsHostDirExists(vhost_dir_logs) {
+			utils.SystemErrorPage(w, errors.New("Folder "+vhost_dir_logs+" is not found"))
+			return
 		}
 		}
-
-		stop := make(chan os.Signal)
-		signal.Notify(stop, os.Interrupt)
-
-		go func() {
-			log.Printf("Starting server at %s:%d", ParamHost, ParamPort)
-			if err := srv.ListenAndServe(); err != nil {
-				if err != http.ErrServerClosed {
-					log.Fatal(err)
-				}
-			}
-		}()
-
-		// Wait for signal
-		<-stop
-
-		log.Printf("Shutting down server...\n")
-		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
-		defer cancel()
-
-		if err := srv.Shutdown(ctx); err != nil {
-			log.Fatal(err)
-		} else {
-			log.Printf("Server is off!")
+		if !utils.IsHostDirExists(vhost_dir_template) {
+			utils.SystemErrorPage(w, errors.New("Folder "+vhost_dir_template+" is not found"))
+			return
+		}
+		if !utils.IsHostDirExists(vhost_dir_tmp) {
+			utils.SystemErrorPage(w, errors.New("Folder "+vhost_dir_tmp+" is not found"))
+			return
 		}
 		}
-	*/
-}
 
 
-/*
-func vhExists(vhosthome string) bool {
-	if st, err := os.Stat(vhosthome); !os.IsNotExist(err) {
-		if err == nil {
-			fmode := st.Mode()
-			if fmode.IsDir() {
-				return true
-			}
+		// Static files
+		if stat.Response(vhost_dir_htdocs, w, r, nil, nil) {
+			return
 		}
 		}
-	}
-	return false
-}
 
 
-func handler(w http.ResponseWriter, r *http.Request) {
-	// Build vhost home dir
-	host := r.Host
-	port := strconv.Itoa(ParamPort)
-	index := strings.Index(host, ":")
-	if index > -1 {
-		port = host[index+1:]
-		host = host[0:index]
-	}
+		// Session
+		//sess := session.New(w, r, vhost_dir_tmp)
+		//defer sess.Close()
 
 
-	// Cut "www" if exists
-	if strings.HasPrefix(host, "www.") {
-		host = host[4:]
-	}
-	VhostHomeDir = ParamWwwDir + host
+		// Session struct need to make public!
+		sess := session.New(w, r, vhost_dir_tmp)
+		defer sess.Close()
 
 
-	// Check if virtual host exists
-	if !vhExists(VhostHomeDir) {
-		host = "localhost"
-		VhostHomeDir = ParamWwwDir + host
-	}
+		// Logic
+		// TODO: call from `logic.Response()`
+		// TODO: create logic object here???
+		if logic(host, port, vhost_dir_config, vhost_dir_htdocs, vhost_dir_logs, vhost_dir_template, vhost_dir_tmp, w, r) {
+			return
+		}
 
 
-	// Set protocol
-	r.URL.Scheme = "http"
+		// Error 404
+		// TODO: display default template
+		w.WriteHeader(http.StatusNotFound)
+		w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+		w.Header().Set("Content-Type", "text/html")
+		w.Write([]byte(`404`))
+	})
 
 
-	// Set server name
-	w.Header().Set("Server", "fave.pro/"+constants.ServerVersion)
+	// Delete expired session files
+	// session.Clean("./tmp")
+}
 
 
-	wrap := wrapper.New(&w, r, host, port, ParamWwwDir, VhostHomeDir)
+func logic(host, port, dir_config, dir_htdocs, dir_logs, dir_template, dir_tmp string, w http.ResponseWriter, r *http.Request) bool {
+	if r.URL.Path == "/" {
+		w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+		w.Header().Set("Content-Type", "text/html")
 
 
-	// Check if localhost exists
-	if !vhExists(VhostHomeDir) && !strings.HasPrefix(r.URL.Path, "/assets/") {
-		wrap.PrintEnginePageError(errors.New("Folder " + VhostHomeDir + " is not found"))
-		return
-	}
+		//counter := sess.GetInt("counter", 0)
+		//w.Write([]byte(`Logic -> (` + fmt.Sprintf("%d", counter) + `)`))
 
 
-	// Create and start engine
-	wrap.Run(func(wrapper *wrapper.Wrapper) bool {
-		// Actions
-		action := actions.New(wrapper)
-		if action.Run() {
-			wrapper.Session.Save()
-			return true
-		}
+		w.Write([]byte(`Logic`))
 
 
-		// Pages
-		return handlerPage(wrapper)
-	})
+		//counter++
+		//sess.SetInt("counter", counter)
+
+		return true
+	}
+	return false
 }
 }
-*/

+ 81 - 0
static/static.go

@@ -0,0 +1,81 @@
+package static
+
+import (
+	"net/http"
+	"os"
+)
+
+type static struct {
+	dirIndexFile string
+}
+
+func New(file string) *static {
+	r := static{dirIndexFile: file}
+	return &r
+}
+
+func (this *static) Response(dir string, w http.ResponseWriter, r *http.Request, before func(w http.ResponseWriter, r *http.Request), after func(w http.ResponseWriter, r *http.Request)) bool {
+	if r.URL.Path == "/" {
+		f, err := os.Open(dir + string(os.PathSeparator) + this.dirIndexFile)
+		if err == nil {
+			defer f.Close()
+			st, err := os.Stat(dir + string(os.PathSeparator) + this.dirIndexFile)
+			if err != nil {
+				return false
+			}
+			if st.Mode().IsDir() {
+				return false
+			}
+			if before != nil {
+				before(w, r)
+			}
+			http.ServeFile(w, r, dir+string(os.PathSeparator)+this.dirIndexFile)
+			if after != nil {
+				after(w, r)
+			}
+			return true
+		}
+	} else {
+		f, err := os.Open(dir + r.URL.Path)
+		if err == nil {
+			defer f.Close()
+			st, err := os.Stat(dir + r.URL.Path)
+			if err != nil {
+				return false
+			}
+			if st.Mode().IsDir() {
+				if r.URL.Path[len(r.URL.Path)-1] == '/' {
+					fi, err := os.Open(dir + r.URL.Path + string(os.PathSeparator) + this.dirIndexFile)
+					if err == nil {
+						defer fi.Close()
+						sti, err := os.Stat(dir + r.URL.Path + string(os.PathSeparator) + this.dirIndexFile)
+						if err != nil {
+							return false
+						}
+						if sti.Mode().IsDir() {
+							return false
+						}
+						if before != nil {
+							before(w, r)
+						}
+						http.ServeFile(w, r, dir+r.URL.Path+string(os.PathSeparator)+this.dirIndexFile)
+						if after != nil {
+							after(w, r)
+						}
+						return true
+					}
+				}
+				return false
+			}
+			if before != nil {
+				before(w, r)
+			}
+			http.ServeFile(w, r, dir+r.URL.Path)
+			if after != nil {
+				after(w, r)
+			}
+			return true
+		}
+	}
+	return false
+}

+ 68 - 0
utils/utils.go

@@ -1,8 +1,13 @@
 package utils
 package utils
 
 
 import (
 import (
+	"html/template"
+	"net/http"
 	"os"
 	"os"
 	"strings"
 	"strings"
+
+	"golang-fave/assets"
+	"golang-fave/consts"
 )
 )
 
 
 func IsFileExists(filename string) bool {
 func IsFileExists(filename string) bool {
@@ -25,6 +30,13 @@ func IsDir(filename string) bool {
 	return false
 	return false
 }
 }
 
 
+func IsHostDirExists(path string) bool {
+	if IsFileExists(path) && IsDir(path) {
+		return true
+	}
+	return false
+}
+
 func FixPath(path string) string {
 func FixPath(path string) string {
 	newPath := strings.TrimSpace(path)
 	newPath := strings.TrimSpace(path)
 	if len(newPath) <= 0 {
 	if len(newPath) <= 0 {
@@ -35,3 +47,59 @@ func FixPath(path string) string {
 	}
 	}
 	return newPath
 	return newPath
 }
 }
+
+func ExtractHostPort(host string, https bool) (string, string) {
+	h := host
+	p := "80"
+	if https {
+		p = "443"
+	}
+	i := strings.Index(h, ":")
+	if i > -1 {
+		p = h[i+1:]
+		h = h[0:i]
+	}
+	return h, p
+}
+
+func GetAssetsUrl(filename string) string {
+	return "/" + filename + "?v=" + consts.AssetsVersion
+}
+
+func GetTmplSystemData() consts.TmplSystem {
+	return consts.TmplSystem{
+		PathIcoFav:       GetAssetsUrl(consts.AssetsSysFaveIco),
+		PathSvgLogo:      GetAssetsUrl(consts.AssetsSysLogoSvg),
+		PathCssStyles:    GetAssetsUrl(consts.AssetsSysStylesCss),
+		PathCssCpStyles:  GetAssetsUrl(consts.AssetsCpStylesCss),
+		PathCssBootstrap: GetAssetsUrl(consts.AssetsBootstrapCss),
+		PathJsJquery:     GetAssetsUrl(consts.AssetsJqueryJs),
+		PathJsPopper:     GetAssetsUrl(consts.AssetsPopperJs),
+		PathJsBootstrap:  GetAssetsUrl(consts.AssetsBootstrapJs),
+		PathJsCpScripts:  GetAssetsUrl(consts.AssetsCpScriptsJs),
+	}
+}
+
+func GetTmplError(err error) consts.TmplError {
+	return consts.TmplError{
+		ErrorMessage: err.Error(),
+	}
+}
+
+func SystemErrorPage(w http.ResponseWriter, err error) {
+	if tmpl, errr := template.New("template").Parse(string(assets.TmplPageErrorEngine)); errr == nil {
+		w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Header().Set("Content-Type", "text/html")
+		tmpl.Execute(w, consts.TmplData{
+			System: GetTmplSystemData(),
+			Data:   GetTmplError(err),
+		})
+		return
+	}
+	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+	w.WriteHeader(http.StatusInternalServerError)
+	w.Header().Set("Content-Type", "text/html")
+	w.Write([]byte("<h1>Critical engine error</h1>"))
+	w.Write([]byte("<h2>" + err.Error() + "</h2>"))
+}

+ 21 - 0
vendor/github.com/vladimirok5959/golang-server-sessions/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Vova Tkach
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 22 - 0
vendor/github.com/vladimirok5959/golang-server-sessions/session/bool.go

@@ -0,0 +1,22 @@
+package session
+
+func (this *session) IsSetBool(name string) bool {
+	if _, ok := this.v.Bool[name]; ok {
+		return true
+	} else {
+		return false
+	}
+}
+
+func (this *session) GetBool(name string, def bool) bool {
+	if v, ok := this.v.Bool[name]; ok {
+		return v
+	} else {
+		return def
+	}
+}
+
+func (this *session) SetBool(name string, value bool) {
+	this.v.Bool[name] = value
+	this.c = true
+}

+ 27 - 0
vendor/github.com/vladimirok5959/golang-server-sessions/session/clean.go

@@ -0,0 +1,27 @@
+package session
+
+import (
+	"io/ioutil"
+	"os"
+	"time"
+)
+
+func Clean(tmpdir string) error {
+	files, err := ioutil.ReadDir(tmpdir)
+	if err != nil {
+		return err
+	}
+	now := time.Now()
+	exp := 7 * 24 * time.Hour
+	for _, file := range files {
+		if len(file.Name()) == 40 {
+			if diff := now.Sub(file.ModTime()); diff > exp {
+				err = os.Remove(tmpdir + string(os.PathSeparator) + file.Name())
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+	return nil
+}

+ 22 - 0
vendor/github.com/vladimirok5959/golang-server-sessions/session/int.go

@@ -0,0 +1,22 @@
+package session
+
+func (this *session) IsSetInt(name string) bool {
+	if _, ok := this.v.Int[name]; ok {
+		return true
+	} else {
+		return false
+	}
+}
+
+func (this *session) GetInt(name string, def int) int {
+	if v, ok := this.v.Int[name]; ok {
+		return v
+	} else {
+		return def
+	}
+}
+
+func (this *session) SetInt(name string, value int) {
+	this.v.Int[name] = value
+	this.c = true
+}

+ 90 - 0
vendor/github.com/vladimirok5959/golang-server-sessions/session/session.go

@@ -0,0 +1,90 @@
+package session
+
+import (
+	"crypto/sha1"
+	"encoding/json"
+	"fmt"
+	"math/rand"
+	"net/http"
+	"os"
+	"time"
+)
+
+type vars struct {
+	Bool   map[string]bool
+	Int    map[string]int
+	String map[string]string
+}
+
+type session struct {
+	w http.ResponseWriter
+	r *http.Request
+	d string
+	v *vars
+	c bool
+	i string
+}
+
+func New(w http.ResponseWriter, r *http.Request, tmpdir string) *session {
+	sess := session{w: w, r: r, d: tmpdir, v: &vars{}, c: false, i: ""}
+
+	cookie, err := r.Cookie("session")
+	if err == nil && len(cookie.Value) == 40 {
+		// Load from file
+		sess.i = cookie.Value
+		f, err := os.Open(sess.d + string(os.PathSeparator) + sess.i)
+		if err == nil {
+			defer f.Close()
+			dec := json.NewDecoder(f)
+			err = dec.Decode(&sess.v)
+			if err == nil {
+				return &sess
+			}
+		}
+	} else {
+		// Create new
+		rand.Seed(time.Now().Unix())
+
+		sign := r.RemoteAddr + r.Header.Get("User-Agent") + fmt.Sprintf("%d", int64(time.Now().Unix())) + fmt.Sprintf("%d", int64(rand.Intn(9999999-99)+99))
+		sess.i = fmt.Sprintf("%x", sha1.Sum([]byte(sign)))
+
+		http.SetCookie(w, &http.Cookie{
+			Name:     "session",
+			Value:    sess.i,
+			Path:     "/",
+			Expires:  time.Now().Add(7 * 24 * time.Hour),
+			HttpOnly: true,
+		})
+	}
+
+	// Init empty
+	sess.v = &vars{
+		Bool:   map[string]bool{},
+		Int:    map[string]int{},
+		String: map[string]string{},
+	}
+	sess.c = true
+
+	return &sess
+}
+
+func (this *session) Close() bool {
+	if !this.c {
+		return false
+	}
+
+	r, err := json.Marshal(this.v)
+	if err == nil {
+		f, err := os.Create(this.d + string(os.PathSeparator) + this.i)
+		if err == nil {
+			defer f.Close()
+			_, err = f.Write(r)
+			if err == nil {
+				this.c = false
+				return true
+			}
+		}
+	}
+
+	return false
+}

+ 22 - 0
vendor/github.com/vladimirok5959/golang-server-sessions/session/string.go

@@ -0,0 +1,22 @@
+package session
+
+func (this *session) IsSetString(name string) bool {
+	if _, ok := this.v.String[name]; ok {
+		return true
+	} else {
+		return false
+	}
+}
+
+func (this *session) GetString(name string, def string) string {
+	if v, ok := this.v.String[name]; ok {
+		return v
+	} else {
+		return def
+	}
+}
+
+func (this *session) SetString(name string, value string) {
+	this.v.String[name] = value
+	this.c = true
+}