package main import ( "encoding/json" "errors" "io/ioutil" "log" "os" ) //chat state that we might be use for collecting infomation from user type chatState struct { Name string `json:"Name"` //state name Expire int32 `json:"Expire"` //unix timestamp when this state expire Send struct { //anything we need to send? Type string `json:"Type"` //what type of message Message map[string]string `json:"Message"` //the message to be sent,key value pair to describe the message } `json:"Send"` Receive struct { //anything we expect to receive Validator string `json:"Validator"` Hint string `json:"Hint"` Message map[string]string `json:"Message"` //the description for receiving message } `json:"Receive"` Save map[string]string `json:"Save"` //the state save some data for later usage } //for individual state func getCurrentState(openID string, procedure string) (result chatState, err error) { path := getProcedurePath(openID, procedure) log.Printf("read state from %s\r\n", path) body, err := ioutil.ReadFile(path) if err != nil { //read file error if isFileExist(path) { log.Println("Error session reading " + path) } return //empty and expired session } err = json.Unmarshal(body, &result) if err != nil { log.Printf("Session Content [path=%s] not correct: ", path) log.Println(err) } //we don't check Expire, we give the caller full control on //how to deal wiht expired session return } func setCurrentState(openID, procedure string, state chatState) (newState chatState, err error) { j, err := json.Marshal(state) if err != nil { return } path := getProcedurePath(openID, procedure) err = ioutil.WriteFile(path, j, 0600) if err != nil { log.Println("write state error" + path) log.Println(err) return } newState = state return } func deleteChatState(openID, procedure string) (err error) { path := getProcedurePath(openID, procedure) err = os.Remove(path) return } //ValidationResult After input validation, what is the result type ValidationResult struct { accept bool Hint string Error string Warning string } //Validator function type for validating all wechat inputs type Validator func(s chatState) ValidationResult //start a procedure func startProcedure(openID, procedure string) (err error) { //init procedure state init := getProcedureInit(openID, procedure) if init == nil { msg := "FATAL: cannot initialize procedure [" + procedure + "] " err = errors.New(msg) return } //init and get initial state state := init(openID) //do the real concret work for processing the state err = processProcedureState(state) return } //resume a previous Procedure func resumeProcedure(procedure string) { } func stopProcedure(procedure string) { } func processProcedureState(state chatState) (err error) { log.Println(state) return } type initProcedureFunction func(openid string) (initState chatState) func getProcedureInit(openID, procedure string) initProcedureFunction { initFunc := map[string]initProcedureFunction{ "TestDummy": nil, "TestEcho": initTestEcho, "GetBasicUserInfo": initGetBasicUserInfo, "GetEmailAddr": initGetBasicUserInfo, } return initFunc[procedure] } func initTestEcho(openid string) (r chatState) { r.Name = openid r.Expire = 0 return }