From 4167558e07a702deb2e868f9c5ccf172cc133680 Mon Sep 17 00:00:00 2001 From: Patrick Peng Sun Date: Fri, 26 May 2017 13:03:29 +1000 Subject: [PATCH] save, read session tested --- chagSession_test.go | 48 +++++++++++++++++ chatSession.go | 124 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 chagSession_test.go create mode 100644 chatSession.go diff --git a/chagSession_test.go b/chagSession_test.go new file mode 100644 index 0000000..d203968 --- /dev/null +++ b/chagSession_test.go @@ -0,0 +1,48 @@ +package main + +import ( + "log" + "testing" + "time" +) + +func TestSession(t *testing.T) { + id := "testopenid" + state := "testsate" + + //delete any existing + deleteSession(id) + path := getSessionPath(id) + AssertEqual(t, isFileExist(path), false, "Session file should not exist") + + //create new + setSessionState(id, state, 100) + + //wait 1 sec + log.Print("wait for 1 sec for testing timestamp ......") + time.Sleep(1 * time.Second) + log.Print("......waiting done") + + //read back , check state + s, _ := getCurrentSesssion(id) + AssertEqual(t, s.State, state, "") + now := int32(time.Now().Unix()) + + //check timing + AssertEqual(t, s.Expire > now, true, "Expire should be in future") + AssertEqual(t, s.UpdateAt < now, true, "Update should be in pass") + AssertEqual(t, s.CreateAt == s.UpdateAt, true, "Update should be equal to create") + AssertEqual(t, isExpired(now), false, "current time should not be expired") + + //update existing session + s, _ = setSessionState(id, state, 100) + //timeing should be exactly 1s diff + AssertEqual(t, s.CreateAt+1 == s.UpdateAt, true, "second Update should be bigger create") + n, _ := getCurrentSesssion(id) + AssertEqual(t, s, n, "session should be equal") + + //delete session, for clean up + deleteSession(id) + path = getSessionPath(id) + AssertEqual(t, isFileExist(path), false, "Session file should not exist") +} diff --git a/chatSession.go b/chatSession.go new file mode 100644 index 0000000..0d7eddd --- /dev/null +++ b/chatSession.go @@ -0,0 +1,124 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "log" + "os" + "path/filepath" + "time" +) + +//a state is a alphanumerical string lessthan 128 bytes. + +//when messages comes in we need to differentiate what state is this in. +//default state is where command can happen + +//where the state is stored, +// in sessions/openID.json + +//if there is no such file, we are in default state. + +//First state is to record user's name, email, and phone number. +// for individual state +// state/statename/openID.json + +var sessionDir = "sessions" +var stateDir = "state" + +//openIDSession openID user's session +type openIDSession struct { + State string `json:"State"` //name of the current state alphanumerical string + CreateAt int32 `json:"CreateAt"` //when is this session created + UpdateAt int32 `json:"UpdateAt"` //when is this session updated + Expire int32 `json:"Expire"` //unix timestamp of when this state expires +} + +//read sessions/openID.json to check whether its a state for ongoing dialog +func getCurrentSesssion(openID string) (result openIDSession, err error) { + path := getSessionPath(openID) + log.Printf("read session from %s\r\n", path) + body, err := ioutil.ReadFile(path) + if err != nil { //read file error + if isFileExist(path) { + log.Println("Error session reading " + path) + } + return //empty and expired session + } + err = json.Unmarshal(body, &result) + if err != nil { + log.Printf("Session Content [path=%s] not correct: ", path) + } + //we don't check Expire, we give the caller full control on + //how to deal wiht expired session + return +} + +func writeSession(openid string, ss openIDSession) (err error) { + path := getSessionPath(openid) + r, err := json.Marshal(ss) + if err == nil { + err = ioutil.WriteFile(path, r, 0600) + if err != nil { + log.Printf("Error writing session %s: \r\n %s \r\n", openid, r) + log.Println(err) + } else { + log.Println("write session to " + path) + } + } else { + log.Printf("Error encoding session %s ", openid) + log.Println(err) + } + return +} + +//create if not available +func setSessionState(openID, state string, expireAfter int32) (updatedSession openIDSession, err error) { + s, err := getCurrentSesssion(openID) + now := int32(time.Now().Unix()) + if s.CreateAt == 0 { + s.CreateAt = now + } + s.UpdateAt = now + s.State = state + s.Expire = now + expireAfter + err = writeSession(openID, s) + return s, err +} + +func isExpired(timestamp int32) bool { + now := int32(time.Now().Unix()) + return now > timestamp +} + +func getSessionPath(openID string) (path string) { + path = sessionDir + string(os.PathSeparator) + openID + ".json" + ensurePathExist(path) + return path +} + +func getStatePath(openID, stateName string) (path string) { + path = stateDir + string(os.PathSeparator) + stateName + string(os.PathSeparator) + openID + ".json" + ensurePathExist(path) + return +} + +func ensurePathExist(path string) { + d := filepath.Dir(path) + if !isFileExist(d) { + log.Println("Creating path [" + d + "]") + os.MkdirAll(d, 0700) + } +} + +func deleteSession(openID string) { + path := getSessionPath(openID) + if isFileExist(path) { + err := os.Remove(path) + if err != nil { + log.Println(err) + } else { + log.Println("delete session :" + path) + } + } +}