Added parallelization of App Service requests

This commit is contained in:
Derek Meer 2018-08-03 18:49:12 -07:00
parent 4b3bd45092
commit c6f49c1e88

View file

@ -7,6 +7,8 @@ import (
"github.com/matrix-org/util" "github.com/matrix-org/util"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"sync"
) )
// URIToUIDResponse represents response to an AppService URI to User Id // URIToUIDResponse represents response to an AppService URI to User Id
@ -15,6 +17,8 @@ type URIToUIDResponse struct {
UserID string `json:"user_id"` UserID string `json:"user_id"`
} }
const PathPrefixUnstableThirdPartyUser = "/_matrix/app/unstable/thirdparty/user/"
// URIToUID implements `/_matrix/app/r0/user?uri={url_encoded_uri}`, which // URIToUID implements `/_matrix/app/r0/user?uri={url_encoded_uri}`, which
// enables users to contact App Service users directly by taking an encoded // enables users to contact App Service users directly by taking an encoded
// URI and turning it into a Matrix ID on the homeserver. // URI and turning it into a Matrix ID on the homeserver.
@ -27,36 +31,51 @@ func URIToUID(req *http.Request, cfg config.Dendrite) util.JSONResponse {
JSON: nil, JSON: nil,
} }
} }
// contact the app services in parallel, rather than sequentially
var wg sync.WaitGroup
userIDs := make([]string, 0)
for _, appservice := range cfg.Derived.ApplicationServices { for _, appservice := range cfg.Derived.ApplicationServices {
// Check all the fields associated with each application service // Check all the fields associated with each application service
if !appservice.IsInterestedInUserID(uri) { if !appservice.IsInterestedInUserID(uri) {
continue continue
} }
// call the application service wg.Add(1)
reqURL := "http://" + appservice.URL + "/_matrix/app/unstable/thirdparty/user/" + // call the applicable application services in parallel
appservice.ID + "?access_token=" + appservice.HSToken + go func(as config.ApplicationService, ids *[]string) {
"&fields=" + uri defer wg.Done()
resp, err := http.Get(reqURL) reqURL, err := url.Parse(as.URL + PathPrefixUnstableThirdPartyUser + as.ID +
"?access_token=" + as.HSToken +
"&fields=" + uri)
if err != nil {
return
}
resp, err := http.Get(reqURL.String())
// take the first successful match and send that back to the user // take the first successful match and send that back to the user
if err != nil { if err != nil {
continue return
} }
// decode the JSON to get the field we want // decode the JSON to get the field we want
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
respMap := map[string]interface{}{} respMap := map[string]interface{}{}
if err := json.Unmarshal(body, &respMap); err != nil { if err := json.Unmarshal(body, &respMap); err != nil {
return util.JSONResponse{ return
Code: http.StatusBadRequest,
JSON: jsonerror.NotJSON("The request body could not be decoded into valid JSON. " + err.Error()),
}
} }
if userID, ok := respMap["userid"].(string); ok { if userID, ok := respMap["userid"].(string); ok {
*ids = append(*ids, userID)
}
}(appservice, &userIDs)
}
wg.Wait()
if len(userIDs) > 0 {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: URIToUIDResponse{UserID: userID}, JSON: URIToUIDResponse{UserID: userIDs[0]},
}
} }
} }
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusNotFound, Code: http.StatusNotFound,
JSON: jsonerror.NotFound("URI not supported by app services"), JSON: jsonerror.NotFound("URI not supported by app services"),