Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

174 linhas
4.8KB

  1. package main
  2. import (
  3. "encoding/json"
  4. "io/ioutil"
  5. "log"
  6. "os"
  7. "time"
  8. )
  9. //openSession is the biggest description for a user's openID
  10. // | it contains a name called procedure, whose data is stored elsewhere
  11. // |
  12. // +-- a Procedure name is a alphanumerical string lessthan 128 bytes.
  13. // |
  14. // +--- state is part of procedure, a procedure consists of sequence of states
  15. //where to find session data
  16. var sessionDir = "sessions"
  17. //where to find the procedure state information
  18. var procedureDir = "procedure"
  19. //openIDSessionData openID user's session
  20. type openIDSessionData struct {
  21. OpenID string `json:"OpenID"` //who's session this is belongs to
  22. Procedure string `json:"Procedure"` //name of the current current process, alphanumerical
  23. CreateAt int32 `json:"CreateAt"` //when is this session created
  24. UpdateAt int32 `json:"UpdateAt"` //when is this session updated
  25. Expire int32 `json:"Expire"` //unix timestamp of when this Procedure expires
  26. KvPair map[string]string `json:"KvPair"` //key value pair persistant for this session
  27. //
  28. //
  29. //current state for the prcedure
  30. state chatState
  31. }
  32. func createEmptySession(openID string, expire int32) (result openIDSessionData) {
  33. result.OpenID = openID
  34. result.Procedure = ""
  35. now := int32(time.Now().Unix())
  36. result.CreateAt = now
  37. result.UpdateAt = now
  38. result.Expire = now + expire
  39. result.KvPair = map[string]string{}
  40. return
  41. }
  42. func (ss *openIDSessionData) writeSession() (err error) {
  43. openID := ss.OpenID
  44. path := getSessionPath(openID)
  45. r, err := json.Marshal(ss)
  46. if err == nil {
  47. err = ioutil.WriteFile(path, r, 0600)
  48. if err != nil {
  49. log.Printf("Error writing session %s: \r\n %s \r\n", openID, r)
  50. log.Println(err)
  51. } else {
  52. log.Println("write session to " + path)
  53. //save state
  54. err = ss.state.Save()
  55. if err != nil {
  56. log.Printf("Error: cannot write session data %s", openID)
  57. log.Println(err)
  58. }
  59. }
  60. } else {
  61. log.Printf("Error encoding session %s ", openID)
  62. log.Println(err)
  63. }
  64. return
  65. }
  66. func isExpired(timestamp int32) bool {
  67. now := int32(time.Now().Unix())
  68. return now > timestamp
  69. }
  70. func getSessionPath(openID string) (path string) {
  71. path = sessionDir + string(os.PathSeparator) + openID + ".json"
  72. ensurePathExist(path)
  73. return path
  74. }
  75. func (ss *openIDSessionData) Delete() {
  76. path := getSessionPath(ss.OpenID)
  77. if isFileExist(path) {
  78. err := os.Remove(path)
  79. if err != nil {
  80. log.Println(err)
  81. }
  82. }
  83. }
  84. func (ss *openIDSessionData) Save() {
  85. //invalid procedure
  86. if isExpired(ss.Expire) || ss.Procedure == "" {
  87. log.Printf("delete session [%s], %d, now=%d", ss.Procedure, ss.Expire, time.Now().Unix())
  88. ss.Delete()
  89. } else {
  90. ss.writeSession()
  91. }
  92. }
  93. //read sessions/openID.json to check whether its a Procedure for ongoing dialog
  94. func (ss *openIDSessionData) Load(openID string) (result openIDSessionData, err error) {
  95. result = createEmptySession(openID, 3600)
  96. path := getSessionPath(openID)
  97. if isFileExist(path) {
  98. log.Printf("read session from %s\r\n", path)
  99. body, err := ioutil.ReadFile(path)
  100. if err != nil { //read file error
  101. log.Println("Error session reading " + path)
  102. } else {
  103. err = json.Unmarshal(body, &result)
  104. if err != nil {
  105. log.Printf("Session Content [path=%s] not correct: ", path)
  106. result = createEmptySession(openID, 3600)
  107. } else { //load procedure state if any
  108. if !isExpired(result.Expire) {
  109. procedure := result.Procedure
  110. result.state, err = getCurrentState(openID, procedure)
  111. } else {
  112. result = createEmptySession(openID, 3600)
  113. }
  114. }
  115. }
  116. }
  117. *ss = result
  118. return
  119. }
  120. func (ss *openIDSessionData) setProcedure(procedure string) {
  121. ss.Procedure = procedure
  122. ss.UpdateAt = int32(time.Now().Unix())
  123. }
  124. func (ss *openIDSessionData) refreshExpire(seconds int32) {
  125. ss.UpdateAt = int32(time.Now().Unix())
  126. ss.Expire = ss.UpdateAt + seconds
  127. }
  128. func (ss *openIDSessionData) setKvPair(key, val string) {
  129. ss.KvPair[key] = val
  130. ss.UpdateAt = int32(time.Now().Unix())
  131. }
  132. func (ss *openIDSessionData) getVal(key string) string {
  133. return ss.KvPair[key]
  134. }
  135. //main entry point for processing each incoming message
  136. //this stage has session date available
  137. func (ss *openIDSessionData) incomingMsg(v InWechatMsg) {
  138. openID := v.header.FromUserName
  139. //kfSendTxtAs(openID, "信息收到"+v.header.MsgType, "孙鹏")
  140. //are we in an existing procedure
  141. log.Printf("current procedure = %s", ss.Procedure)
  142. proc, found := AllProc[ss.Procedure]
  143. if found {
  144. proc.serve(ss, v) //transit to new state
  145. } else {
  146. processed := ss.serveCommand(v) //menu or txt command e.g. search
  147. log.Printf("current procedure after command = %s", ss.Procedure)
  148. if !processed { // transfer to Customer Service (kf)
  149. //start transfer
  150. xml, _ := BuildKFTransferAnyOneMsg(openID)
  151. v.replyXML(xml)
  152. kfSendTxt(openID, "已转接校友会理事会,稍后答复您")
  153. }
  154. }
  155. return
  156. }