Skip to content

Commit

Permalink
Implement asynchronous AMD for Twilio IVR
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanseymour committed Aug 10, 2021
1 parent 69cf6c4 commit ae8531e
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 10 deletions.
7 changes: 6 additions & 1 deletion core/ivr/ivr.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,11 @@ func ResumeIVRFlow(
return WriteErrorResponse(ctx, rt.DB, client, conn, w, errors.Errorf("active session: %d does not match connection: %d", session.ID(), *session.ConnectionID()))
}

// check connection is still marked as in progress
if conn.Status() != models.ConnectionStatusInProgress {
return WriteErrorResponse(ctx, rt.DB, client, conn, w, errors.Errorf("connection in invalid state: %s", conn.Status()))
}

// preprocess this request
body, err := client.PreprocessResume(ctx, rt.DB, rt.RP, conn, r)
if err != nil {
Expand Down Expand Up @@ -590,7 +595,7 @@ func HandleIVRStatus(ctx context.Context, rt *runtime.Runtime, oa *models.OrgAss
// no associated start? this is a permanent failure
if conn.StartID() == models.NilStartID {
conn.MarkFailed(ctx, rt.DB, time.Now())
return client.WriteEmptyResponse(w, "status updated: F")
return client.WriteEmptyResponse(w, "no flow start found, status updated: F")
}

// on errors we need to look up the flow to know how long to wait before retrying
Expand Down
18 changes: 9 additions & 9 deletions core/ivr/twiml/twiml.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func (c *client) RequestCall(number urns.URN, callbackURL string, statusURL stri
form.Set("StatusCallback", statusURL)
form.Set("MachineDetection", "Enable")
form.Set("AsyncAmd", "true")
form.Set("AsyncAmdStatusCallback", callbackURL)
form.Set("AsyncAmdStatusCallback", statusURL)

sendURL := c.baseURL + strings.Replace(callPath, "{AccountSID}", c.accountSID, -1)

Expand Down Expand Up @@ -289,14 +289,14 @@ func (c *client) ResumeForRequest(r *http.Request) (ivr.Resume, error) {

// StatusForRequest returns the current call status for the passed in status (and optional duration if known)
func (c *client) StatusForRequest(r *http.Request) (models.ConnectionStatus, int) {
// we re-use our status callback for AMD results which will have an AnsweredBy field but no CallStatus field
answeredBy := r.Form.Get("AnsweredBy")

switch answeredBy {
case "human", "unknown", "":
break

default:
return models.ConnectionStatusErrored, 0
if answeredBy != "" {
switch answeredBy {
case "machine_start", "fax":
return models.ConnectionStatusErrored, 0
}
return models.ConnectionStatusInProgress, 0
}

status := r.Form.Get("CallStatus")
Expand All @@ -316,7 +316,7 @@ func (c *client) StatusForRequest(r *http.Request) (models.ConnectionStatus, int
return models.ConnectionStatusErrored, 0

default:
logrus.WithField("call_status", status).Error("unknown call status in ivr callback")
logrus.WithField("call_status", status).Error("unknown call status in status callback")
return models.ConnectionStatusFailed, 0
}
}
Expand Down

0 comments on commit ae8531e

Please sign in to comment.