Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

163 lines
4.5KB

  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. ss.Delete()
  88. } else {
  89. ss.writeSession()
  90. }
  91. }
  92. //read sessions/openID.json to check whether its a Procedure for ongoing dialog
  93. func (ss *openIDSessionData) Load(openID string) (result openIDSessionData, err error) {
  94. result = createEmptySession(openID, 3600)
  95. path := getSessionPath(openID)
  96. if isFileExist(path) {
  97. log.Printf("read session from %s\r\n", path)
  98. body, err := ioutil.ReadFile(path)
  99. if err != nil { //read file error
  100. log.Println("Error session reading " + path)
  101. } else {
  102. err = json.Unmarshal(body, &result)
  103. if err != nil {
  104. log.Printf("Session Content [path=%s] not correct: ", path)
  105. result = createEmptySession(openID, 3600)
  106. } else { //load procedure state if any
  107. procedure := result.Procedure
  108. result.state, err = getCurrentState(openID, procedure)
  109. }
  110. }
  111. }
  112. *ss = result
  113. return
  114. }
  115. func (ss *openIDSessionData) setProcedure(procedure string) {
  116. ss.Procedure = procedure
  117. ss.UpdateAt = int32(time.Now().Unix())
  118. }
  119. func (ss *openIDSessionData) refreshExpire(seconds int32) {
  120. ss.UpdateAt = int32(time.Now().Unix())
  121. ss.Expire = ss.UpdateAt + seconds
  122. }
  123. func (ss *openIDSessionData) setKvPair(key, val string) {
  124. ss.KvPair[key] = val
  125. ss.UpdateAt = int32(time.Now().Unix())
  126. }
  127. //main entry point for processing each incoming message
  128. //this stage has session date available
  129. func (ss *openIDSessionData) incomingMsg(v InWechatMsg) {
  130. openID := v.header.FromUserName
  131. //kfSendTxtAs(openID, "信息收到"+v.header.MsgType, "孙鹏")
  132. //are we in an existing procedure
  133. proc, found := AllProc[ss.Procedure]
  134. if found {
  135. proc.serve(ss, v) //transit to new state
  136. } else {
  137. processed := ss.serveCommand(v) //menu or txt command e.g. search
  138. if !processed { // transfer to Customer Service (kf)
  139. //start transfer
  140. ss.state.response, _ = BuildKFTransferAnyOneMsg(openID)
  141. v.replyXML(ss.state.response)
  142. kfSendTxt(openID, "已转接校友会理事会,稍后答复您")
  143. }
  144. }
  145. return
  146. }