|
- package main
-
- import (
- "encoding/json"
- "io/ioutil"
- "log"
- "os"
- "time"
- )
-
- //openSession is the biggest description for a user's openID
- // | it contains a name called procedure, whose data is stored elsewhere
- // |
- // +-- a Procedure name is a alphanumerical string lessthan 128 bytes.
- // |
- // +--- state is part of procedure, a procedure consists of sequence of states
-
- //where to find session data
- var sessionDir = "sessions"
-
- //where to find the procedure state information
- var procedureDir = "procedure"
-
- //openIDSessionData openID user's session
- type openIDSessionData struct {
- OpenID string `json:"OpenID"` //who's session this is belongs to
- Procedure string `json:"Procedure"` //name of the current current process, alphanumerical
- 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 Procedure expires
- KvPair map[string]string `json:"KvPair"` //key value pair persistant for this session
- //
- //
- //current state for the prcedure
- state chatState
- }
-
- func createEmptySession(openID string, expire int32) (result openIDSessionData) {
- result.OpenID = openID
- result.Procedure = ""
- now := int32(time.Now().Unix())
- result.CreateAt = now
- result.UpdateAt = now
- result.Expire = now + expire
- result.KvPair = map[string]string{}
- return
- }
-
- func (ss *openIDSessionData) writeSession() (err error) {
- openID := ss.OpenID
- 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)
- //save state
- err = ss.state.Save()
- if err != nil {
- log.Printf("Error: cannot write session data %s", openID)
- log.Println(err)
- }
- }
- } else {
- log.Printf("Error encoding session %s ", openID)
- log.Println(err)
- }
- return
- }
-
- 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 (ss *openIDSessionData) Delete() {
- path := getSessionPath(ss.OpenID)
- if isFileExist(path) {
- err := os.Remove(path)
- if err != nil {
- log.Println(err)
- }
- }
- }
-
- func (ss *openIDSessionData) Save() {
- //invalid procedure
- if isExpired(ss.Expire) || ss.Procedure == "" {
- ss.Delete()
- } else {
- ss.writeSession()
- }
- }
-
- //read sessions/openID.json to check whether its a Procedure for ongoing dialog
- func (ss *openIDSessionData) Load(openID string) (result openIDSessionData, err error) {
- result = createEmptySession(openID, 3600)
- path := getSessionPath(openID)
- if isFileExist(path) {
- log.Printf("read session from %s\r\n", path)
- body, err := ioutil.ReadFile(path)
- if err != nil { //read file error
- log.Println("Error session reading " + path)
- } else {
- err = json.Unmarshal(body, &result)
- if err != nil {
- log.Printf("Session Content [path=%s] not correct: ", path)
- result = createEmptySession(openID, 3600)
- } else { //load procedure state if any
- procedure := result.Procedure
- result.state, err = getCurrentState(openID, procedure)
- }
- }
- }
- *ss = result
- return
- }
-
- func (ss *openIDSessionData) setProcedure(procedure string) {
- ss.Procedure = procedure
- ss.UpdateAt = int32(time.Now().Unix())
- }
-
- func (ss *openIDSessionData) refreshExpire(seconds int32) {
- ss.UpdateAt = int32(time.Now().Unix())
- ss.Expire = ss.UpdateAt + seconds
- }
-
- func (ss *openIDSessionData) setKvPair(key, val string) {
- ss.KvPair[key] = val
- ss.UpdateAt = int32(time.Now().Unix())
- }
-
- //main entry point for processing each incoming message
- //this stage has session date available
- func (ss *openIDSessionData) incomingMsg(v InWechatMsg) {
- openID := v.header.FromUserName
- //kfSendTxtAs(openID, "信息收到"+v.header.MsgType, "孙鹏")
- //are we in an existing procedure
- proc, found := AllProc[ss.Procedure]
- if found {
- proc.serve(ss, v) //transit to new state
- } else {
- processed := ss.serveCommand(v) //menu or txt command e.g. search
- log.Println("处理完名利的 procedure=" + ss.Procedure)
- if !processed { // transfer to Customer Service (kf)
- //start transfer
- ss.state.response, _ = BuildKFTransferAnyOneMsg(openID)
- v.replyXML(ss.state.response)
- kfSendTxt(openID, "已转接校友会理事会,稍后答复您")
- }
- }
- return
- }
|