webhook.go (6118B)
1 package webhook 2 3 import ( 4 "crypto/rand" 5 "crypto/tls" 6 "encoding/json" 7 "fmt" 8 "github.com/OpenHomeAuto/AiListener/pkg/dflow" 9 "github.com/OpenHomeAuto/AiListener/pkg/util" 10 "github.com/gorilla/mux" 11 df "github.com/leboncoin/dialogflow-go-webhook" 12 "golang.org/x/crypto/acme/autocert" 13 "golang.org/x/net/http2" 14 "log" 15 "net/http" 16 "strconv" 17 "time" 18 ) 19 20 func makeServerFromMux(mux http.Handler) *http.Server { 21 // set timeouts so that a slow or malicious client doesn't 22 // hold resources forever 23 return &http.Server{ 24 ReadTimeout: 5 * time.Second, 25 WriteTimeout: 5 * time.Second, 26 IdleTimeout: 120 * time.Second, 27 Handler: mux, 28 } 29 } 30 31 func Start() { 32 var m *autocert.Manager 33 var r = mux.NewRouter() 34 35 r.HandleFunc("/webhook", MessagesEndPoint).Methods("POST") 36 httpsserver := makeServerFromMux(r) 37 38 dataDir := "." 39 m = &autocert.Manager{ 40 Prompt: autocert.AcceptTOS, 41 Cache: autocert.DirCache(dataDir), 42 } 43 44 httpserver := makeServerFromMux(m.HTTPHandler(nil)) 45 46 httpserver.Addr = ":80" 47 48 go func() { 49 fmt.Printf("Starting HTTP server on %s\n", httpserver.Addr) 50 err := httpserver.ListenAndServe() 51 if err != nil { 52 log.Fatalf("httpsSrv.ListendAndServeTLS() failed with %s", err) 53 } 54 }() 55 56 tlsConfig := &tls.Config{ 57 Rand: rand.Reader, 58 Time: time.Now, 59 NextProtos: []string{http2.NextProtoTLS, "http/1.1"}, 60 MinVersion: tls.VersionTLS12, 61 GetCertificate: m.GetCertificate, 62 } 63 64 httpsserver.Addr = ":" + strconv.Itoa(*util.HTTPSPort) 65 httpsserver.TLSConfig = tlsConfig 66 67 fmt.Printf("Starting HTTPS server on %s\n", httpsserver.Addr) 68 err := httpsserver.ListenAndServeTLS("", "") 69 if err != nil { 70 log.Fatalf("httpsSrv.ListendAndServeTLS() failed with %s", err) 71 } 72 } 73 74 type OriginalResp struct { 75 Source string `json:"source"` 76 Version string `json:"version"` 77 Payload struct { 78 IsInSandbox bool `json:"isInSandbox"` 79 Surface struct { 80 Capabilities []struct { 81 Name string `json:"name"` 82 } `json:"capabilities"` 83 } `json:"surface"` 84 RequestType string `json:"requestType"` 85 Inputs []struct { 86 RawInputs []struct { 87 Query string `json:"query"` 88 InputType string `json:"inputType"` 89 } `json:"rawInputs"` 90 Arguments []struct { 91 RawText string `json:"rawText"` 92 TextValue string `json:"textValue"` 93 Name string `json:"name"` 94 } `json:"arguments"` 95 Intent string `json:"intent"` 96 } `json:"inputs"` 97 User struct { 98 LastSeen time.Time `json:"lastSeen"` 99 Locale string `json:"locale"` 100 UserID string `json:"userId"` 101 } `json:"user"` 102 Conversation struct { 103 ConversationID string `json:"conversationId"` 104 Type string `json:"type"` 105 ConversationToken string `json:"conversationToken"` 106 } `json:"conversation"` 107 AvailableSurfaces []struct { 108 Capabilities []struct { 109 Name string `json:"name"` 110 } `json:"capabilities"` 111 } `json:"availableSurfaces"` 112 } `json:"payload"` 113 } 114 115 func MessagesEndPoint(rw http.ResponseWriter, req *http.Request) { 116 var err error 117 var dfr *df.Request 118 //var p params 119 120 log.Println(req.Header) 121 122 decoder := json.NewDecoder(req.Body) 123 if err = decoder.Decode(&dfr); err != nil { 124 rw.WriteHeader(http.StatusBadRequest) 125 return 126 } 127 defer req.Body.Close() 128 129 // Filter on action, using a switch for example 130 131 // Retrieve the params of the request 132 /*if err = dfr.GetParams(&p); err != nil { 133 rw.WriteHeader(http.StatusBadRequest) 134 return 135 } 136 137 // Retrieve a specific context 138 if err = dfr.GetContext("my-awesome-context", &p); err != nil { 139 rw.WriteHeader(http.StatusBadRequest) 140 return 141 }*/ 142 switch dfr.QueryResult.Action { 143 case "play_music": 144 log.Println(dfr.QueryResult) 145 146 var oresp *OriginalResp 147 if err = json.Unmarshal(dfr.OriginalDetectIntentRequest, &oresp); err != nil { 148 rw.WriteHeader(http.StatusBadRequest) 149 return 150 } 151 152 if "" == "" { 153 resp := dflow.DoSignIn() 154 // Do things with the context you just retrieved 155 dff := &df.Fulfillment{ 156 FulfillmentMessages: df.Messages{ 157 df.ForGoogle(df.SingleSimpleResponse("Starting Auth Process", "Starting Auth Process")), 158 {RichMessage: df.Text{Text: []string{"Starting Auth Process"}}}, 159 }, 160 FollowupEventInput: resp, 161 } 162 163 rw.Header().Set("Content-Type", "application/json") 164 rw.WriteHeader(http.StatusOK) 165 json.NewEncoder(rw).Encode(dff) 166 167 return 168 } 169 170 // Do things with the context you just retrieved 171 dff := &df.Fulfillment{ 172 FulfillmentMessages: df.Messages{ 173 df.ForGoogle(df.SingleSimpleResponse("Starting Music", "Starting Music")), 174 {RichMessage: df.Text{Text: []string{"Starting Music"}}}, 175 }, 176 } 177 178 rw.Header().Set("Content-Type", "application/json") 179 rw.WriteHeader(http.StatusOK) 180 json.NewEncoder(rw).Encode(dff) 181 return 182 case "auth": 183 var oresp *OriginalResp 184 if err = json.Unmarshal(dfr.OriginalDetectIntentRequest, &oresp); err != nil { 185 rw.WriteHeader(http.StatusBadRequest) 186 return 187 } 188 189 log.Printf("OrespJ: \n %+v\n", oresp) 190 respPJ, _ := dfr.QueryResult.Parameters.MarshalJSON() 191 log.Println("respPJ: ", string(respPJ)) 192 for _, v := range dfr.QueryResult.OutputContexts { 193 log.Println(v) 194 respOCPJ, _ := v.Parameters.MarshalJSON() 195 log.Println("respOCPJ: ", string(respOCPJ)) 196 } 197 /* 198 type params struct { 199 200 } 201 202 var p *params 203 204 if err = dfr.GetParams(&p); err != nil { 205 rw.WriteHeader(http.StatusBadRequest) 206 return 207 } 208 209 log.Println(p) 210 */ 211 212 dff := &df.Fulfillment{ 213 FulfillmentMessages: df.Messages{ 214 df.ForGoogle(df.SingleSimpleResponse("Authentication finished", "Authentication finished")), 215 {RichMessage: df.Text{Text: []string{"Authentication finished"}}}, 216 }, 217 } 218 rw.Header().Set("Content-Type", "application/json") 219 rw.WriteHeader(http.StatusOK) 220 json.NewEncoder(rw).Encode(dff) 221 return 222 default: 223 log.Println(dfr.QueryResult) 224 225 dff := &df.Fulfillment{ 226 FulfillmentMessages: df.Messages{ 227 df.ForGoogle(df.SingleSimpleResponse("default", "default")), 228 {RichMessage: df.Text{Text: []string{"default"}}}, 229 }, 230 } 231 rw.Header().Set("Content-Type", "application/json") 232 rw.WriteHeader(http.StatusOK) 233 json.NewEncoder(rw).Encode(dff) 234 return 235 } 236 237 }