|
|
|
@@ -5,7 +5,6 @@ import ( |
|
|
|
"io/ioutil" |
|
|
|
"log" |
|
|
|
"os" |
|
|
|
"path/filepath" |
|
|
|
"time" |
|
|
|
) |
|
|
|
|
|
|
|
@@ -36,7 +35,18 @@ type openIDSessionData struct { |
|
|
|
state chatState |
|
|
|
} |
|
|
|
|
|
|
|
func writeSession(ss openIDSessionData) (err error) { |
|
|
|
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) |
|
|
|
@@ -47,6 +57,12 @@ func writeSession(ss openIDSessionData) (err error) { |
|
|
|
log.Println(err) |
|
|
|
} else { |
|
|
|
log.Println("write session to " + path) |
|
|
|
//save state |
|
|
|
err = ss.state.Save(openID, ss.Procedure) |
|
|
|
if err != nil { |
|
|
|
log.Printf("Error: cannot write session data %s", openID) |
|
|
|
log.Println(err) |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Printf("Error encoding session %s ", openID) |
|
|
|
@@ -66,22 +82,8 @@ func getSessionPath(openID string) (path string) { |
|
|
|
return path |
|
|
|
} |
|
|
|
|
|
|
|
func getProcedurePath(openID, ProcedureName string) (path string) { |
|
|
|
path = procedureDir + string(os.PathSeparator) + ProcedureName + 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) |
|
|
|
func (ss *openIDSessionData) Delete() { |
|
|
|
path := getSessionPath(ss.OpenID) |
|
|
|
if isFileExist(path) { |
|
|
|
err := os.Remove(path) |
|
|
|
if err != nil { |
|
|
|
@@ -90,30 +92,17 @@ func deleteSession(openID string) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
type initProcFunc func(openid string) (newstate chatState) |
|
|
|
type sendProcMsgFunc func(openid string) (newstate chatState) |
|
|
|
type recvProcMsgFunc func(openid string) (newstate chatState) |
|
|
|
type cleanProcFunc func(openid string) (newstate chatState) |
|
|
|
|
|
|
|
//Procedure a description about all procedure |
|
|
|
type Procedure struct { |
|
|
|
init initProcFunc //init function |
|
|
|
send sendProcMsgFunc //function for sending customized message |
|
|
|
recv recvProcMsgFunc //function for receiving message, possibly transfer to new state |
|
|
|
clean cleanProcFunc //function for cleanning up |
|
|
|
} |
|
|
|
|
|
|
|
func (c *openIDSessionData) Save() { |
|
|
|
func (ss *openIDSessionData) Save() { |
|
|
|
//invalid procedure |
|
|
|
if isExpired(c.Expire) || c.Procedure == "" { |
|
|
|
deleteSession(c.OpenID) |
|
|
|
if isExpired(ss.Expire) || ss.Procedure == "" { |
|
|
|
ss.Delete() |
|
|
|
} else { |
|
|
|
writeSession(*c) |
|
|
|
ss.writeSession() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//read sessions/openID.json to check whether its a Procedure for ongoing dialog |
|
|
|
func getCurrentSesssion(openID string) (result openIDSessionData, err error) { |
|
|
|
func (ss *openIDSessionData) Load(openID string) (result openIDSessionData, err error) { |
|
|
|
result = createEmptySession(openID, 3600) |
|
|
|
path := getSessionPath(openID) |
|
|
|
if isFileExist(path) { |
|
|
|
@@ -126,47 +115,46 @@ func getCurrentSesssion(openID string) (result openIDSessionData, err error) { |
|
|
|
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 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 (c *openIDSessionData) setProcedure(procedure string) { |
|
|
|
c.Procedure = procedure |
|
|
|
c.UpdateAt = int32(time.Now().Unix()) |
|
|
|
func (ss *openIDSessionData) setProcedure(procedure string) { |
|
|
|
ss.Procedure = procedure |
|
|
|
ss.UpdateAt = int32(time.Now().Unix()) |
|
|
|
} |
|
|
|
|
|
|
|
func (c *openIDSessionData) setKvPair(key, val string) { |
|
|
|
c.KvPair[key] = val |
|
|
|
c.UpdateAt = int32(time.Now().Unix()) |
|
|
|
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 (c *openIDSessionData) incomingMsg(v InWechatMsg) { |
|
|
|
func (ss *openIDSessionData) incomingMsg(v InWechatMsg) { |
|
|
|
openID := v.header.FromUserName |
|
|
|
//kfSendTxtAs(openID, "信息收到"+v.header.MsgType, "孙鹏") |
|
|
|
//are we in an existing procedure |
|
|
|
inProc, state := isInProc(openID) //if inside a procedure, resume last saved state |
|
|
|
if inProc { |
|
|
|
c.state = serveProc(state, v) //transit to new state |
|
|
|
ss.state = serveProc(state, v) //transit to new state |
|
|
|
} else { |
|
|
|
state, processed := serveCommand(openID, v) //menu or txt command e.g. search |
|
|
|
if !processed { // transfer to Customer Service (kf) |
|
|
|
kfSendTxt(openID, "未识别的命令,已转接校友会理事会,稍后答复您") |
|
|
|
ss.state.response, _ = BuildTextMsg(openID, "已转接校友会理事会,稍后答复您") |
|
|
|
} else { |
|
|
|
ss.state = state |
|
|
|
} |
|
|
|
c.state = state |
|
|
|
} |
|
|
|
|
|
|
|
if ss.state.response != "" { |
|
|
|
v.instantResponse <- ss.state.response |
|
|
|
} |
|
|
|
|
|
|
|
if !isEndingState(state) { |