ailistener

git clone git://archive.git.mtrnord.blog/OpenHomeAuto/ailistener.git
Log | Files | Refs | LICENSE

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 }