|
|
|
@@ -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) |
|
|
|
} |
|
|
|
} |
|
|
|
} |