Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

158 lines
4.1KB

  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. )
  9. //chat state that we might be use for collecting infomation from user
  10. type chatState struct {
  11. //back pointer style information
  12. OpenID string `json:"OpenID"` //whom is this belongs to
  13. Procedure string `json:"Procedure"` //which procedure this belongs to
  14. //real state information
  15. Name string `json:"Name"` //state name
  16. Expire int32 `json:"Expire"` //unix timestamp when this state expire
  17. Send struct { //anything we need to send?
  18. Type string `json:"Type"` //what type of message
  19. Message map[string]string `json:"Message"` //the message to be sent,key value pair to describe the message
  20. } `json:"Send"`
  21. Receive struct { //anything we expect to receive
  22. Validator string `json:"Validator"`
  23. Hint string `json:"Hint"`
  24. Message map[string]string `json:"Message"` //the description for receiving message
  25. } `json:"Receive"`
  26. Save map[string]string `json:"Save"` //the state save some data for later usage
  27. }
  28. //for individual state
  29. func getCurrentState(openID string, procedure string) (result chatState, err error) {
  30. path := getProcedurePath(openID, procedure)
  31. log.Printf("read state from %s\r\n", path)
  32. body, err := ioutil.ReadFile(path)
  33. if err != nil { //read file error
  34. if isFileExist(path) {
  35. log.Println("Error session reading " + path)
  36. }
  37. return //empty and expired session
  38. }
  39. err = json.Unmarshal(body, &result)
  40. if err != nil {
  41. log.Printf("Session Content [path=%s] not correct: ", path)
  42. log.Println(err)
  43. }
  44. //we don't check Expire, we give the caller full control on
  45. //how to deal wiht expired session
  46. return
  47. }
  48. func setCurrentState(openID, procedure string, state chatState) (newState chatState, err error) {
  49. state.OpenID = openID
  50. state.Procedure = procedure
  51. j, err := json.Marshal(state)
  52. if err != nil {
  53. return
  54. }
  55. path := getProcedurePath(openID, procedure)
  56. err = ioutil.WriteFile(path, j, 0600)
  57. if err != nil {
  58. log.Println("write state error" + path)
  59. log.Println(err)
  60. return
  61. }
  62. newState = state
  63. return
  64. }
  65. func deleteChatState(openID, procedure string) (err error) {
  66. path := getProcedurePath(openID, procedure)
  67. err = os.Remove(path)
  68. return
  69. }
  70. //ValidationResult After input validation, what is the result
  71. type ValidationResult struct {
  72. accept bool
  73. Hint string
  74. Error string
  75. Warning string
  76. }
  77. //Validator function type for validating all wechat inputs
  78. type Validator func(s chatState) ValidationResult
  79. //start a procedure
  80. func startProcedure(openID, procedure string) (err error) {
  81. //init procedure state
  82. init := getProcedureInit(openID, procedure)
  83. if init == nil {
  84. msg := "FATAL: cannot initialize procedure [" + procedure + "] "
  85. err = errors.New(msg)
  86. return
  87. }
  88. //init and get initial state
  89. state := init(openID)
  90. //do the real concret work for processing the state
  91. err = processProcedureState(state)
  92. return
  93. }
  94. //resume a previous Procedure's state
  95. func resumeProcedure(openID, procedure string) (err error) {
  96. state, err := getCurrentState(openID, procedure)
  97. if err != nil {
  98. return
  99. }
  100. return processProcedureState(state)
  101. }
  102. //finish a procedure, regardless its been finished or not
  103. //normally not finished normally
  104. func stopProcedure(openID, procedure string) {
  105. path := getProcedurePath(openID, procedure)
  106. os.Remove(path)
  107. log.Println("Clearing [" + openID + "] @ [" + procedure + "]")
  108. }
  109. func processProcedureState(state chatState) (err error) {
  110. //send what we need to send
  111. if isExpired(state.Expire) {
  112. return errors.New("State has expired " + stae.Name)
  113. }
  114. //mark we have sent.
  115. //do we need input? waiting for input
  116. //if not, what is next state
  117. log.Println(state)
  118. return
  119. }
  120. type initProcedureFunction func(openid string) (initState chatState)
  121. func getProcedureInit(openID, procedure string) initProcedureFunction {
  122. initFunc := map[string]initProcedureFunction{
  123. "TestDummy": nil,
  124. "TestEcho": initTestEcho,
  125. "GetBasicUserInfo": initGetBasicUserInfo,
  126. "GetEmailAddr": initGetBasicUserInfo,
  127. }
  128. return initFunc[procedure]
  129. }
  130. func initTestEcho(openid string) (r chatState) {
  131. r.Name = openid
  132. r.Expire = 0
  133. return
  134. }