owncast/utils/restendpointhelper.go

70 lines
2.1 KiB
Go
Raw Normal View History

Feature/oc 1316 add support for system message to single user (#1351) * add public func to lookup a ChatClient by its clientId * add facility to send a system message directly to a user * add clientId field to UserEvent * implement simple http endpoint to send a message to a user * let mux handle new directSystemMessageToUser endpoint * add ClientId to UserEvents across the codebase * render body of system-message to client * add clientId to Chat-Message * add tests showing how url-parsing should work * add simple rest endpoint helpers for parameter-parsing and easy routing * use newly added rest-endpoint helper to rout to Client-Messaging controller * use safe "ReadRestUrlParameter" to parse ClientId * remove empty HandleFunc in router * set Header directly to prevent built-in (platform-dependent) canonicalization to kick in * fix typo in "Parameter" message * remove debug-logging of HTTP headers in REST-helpers * convert to uint32 to prevent overruns when converting to wraptype uint later on * resolve linter-ouchies * resolve linter potential nil-deref warning * document the SendSystemMessageToClient endpoint in swaggerdoc * remove clientId assignment causing potential nil dereference in userDisabledEvent-case as the clientId isn't relevant here anyway * make findClientById private, so its not accessible outside of core/chat * remove redundant string type hint * Update PR based on linter requirements Co-authored-by: Raffael Rehberger <raffael@rtrace.io> Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2021-09-13 11:26:28 +03:00
package utils
import (
"errors"
"fmt"
"net/http"
"strings"
)
const restURLPatternHeaderKey = "Owncast-Resturl-Pattern"
// takes the segment pattern of an Url string and returns the segment before the first dynamic REST parameter.
func getPatternForRestEndpoint(pattern string) string {
firstIndex := strings.Index(pattern, "/{")
if firstIndex == -1 {
return pattern
}
return strings.TrimRight(pattern[:firstIndex], "/") + "/"
}
func zip2D(iterable1 *[]string, iterable2 *[]string) map[string]string {
var dict = make(map[string]string)
for index, key := range *iterable1 {
dict[key] = (*iterable2)[index]
}
return dict
}
func mapPatternWithRequestURL(pattern string, requestURL string) (map[string]string, error) {
patternSplit := strings.Split(pattern, "/")
requestURLSplit := strings.Split(requestURL, "/")
if len(patternSplit) == len(requestURLSplit) {
return zip2D(&patternSplit, &requestURLSplit), nil
}
return nil, errors.New("the length of pattern and request Url does not match")
Feature/oc 1316 add support for system message to single user (#1351) * add public func to lookup a ChatClient by its clientId * add facility to send a system message directly to a user * add clientId field to UserEvent * implement simple http endpoint to send a message to a user * let mux handle new directSystemMessageToUser endpoint * add ClientId to UserEvents across the codebase * render body of system-message to client * add clientId to Chat-Message * add tests showing how url-parsing should work * add simple rest endpoint helpers for parameter-parsing and easy routing * use newly added rest-endpoint helper to rout to Client-Messaging controller * use safe "ReadRestUrlParameter" to parse ClientId * remove empty HandleFunc in router * set Header directly to prevent built-in (platform-dependent) canonicalization to kick in * fix typo in "Parameter" message * remove debug-logging of HTTP headers in REST-helpers * convert to uint32 to prevent overruns when converting to wraptype uint later on * resolve linter-ouchies * resolve linter potential nil-deref warning * document the SendSystemMessageToClient endpoint in swaggerdoc * remove clientId assignment causing potential nil dereference in userDisabledEvent-case as the clientId isn't relevant here anyway * make findClientById private, so its not accessible outside of core/chat * remove redundant string type hint * Update PR based on linter requirements Co-authored-by: Raffael Rehberger <raffael@rtrace.io> Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2021-09-13 11:26:28 +03:00
}
func readParameter(pattern string, requestURL string, paramName string) (string, error) {
all, err := mapPatternWithRequestURL(pattern, requestURL)
if err != nil {
return "", err
}
if value, exists := all[fmt.Sprintf("{%s}", paramName)]; exists {
return value, nil
}
return "", fmt.Errorf("parameter with name %s not found", paramName)
Feature/oc 1316 add support for system message to single user (#1351) * add public func to lookup a ChatClient by its clientId * add facility to send a system message directly to a user * add clientId field to UserEvent * implement simple http endpoint to send a message to a user * let mux handle new directSystemMessageToUser endpoint * add ClientId to UserEvents across the codebase * render body of system-message to client * add clientId to Chat-Message * add tests showing how url-parsing should work * add simple rest endpoint helpers for parameter-parsing and easy routing * use newly added rest-endpoint helper to rout to Client-Messaging controller * use safe "ReadRestUrlParameter" to parse ClientId * remove empty HandleFunc in router * set Header directly to prevent built-in (platform-dependent) canonicalization to kick in * fix typo in "Parameter" message * remove debug-logging of HTTP headers in REST-helpers * convert to uint32 to prevent overruns when converting to wraptype uint later on * resolve linter-ouchies * resolve linter potential nil-deref warning * document the SendSystemMessageToClient endpoint in swaggerdoc * remove clientId assignment causing potential nil dereference in userDisabledEvent-case as the clientId isn't relevant here anyway * make findClientById private, so its not accessible outside of core/chat * remove redundant string type hint * Update PR based on linter requirements Co-authored-by: Raffael Rehberger <raffael@rtrace.io> Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2021-09-13 11:26:28 +03:00
}
// ReadRestURLParameter will return the parameter from the request of the requested name.
func ReadRestURLParameter(r *http.Request, parameterName string) (string, error) {
pattern, found := r.Header[restURLPatternHeaderKey]
if !found {
return "", fmt.Errorf("this HandlerFunc is not marked as REST-Endpoint. Cannot read Parameter '%s' from Request", parameterName)
Feature/oc 1316 add support for system message to single user (#1351) * add public func to lookup a ChatClient by its clientId * add facility to send a system message directly to a user * add clientId field to UserEvent * implement simple http endpoint to send a message to a user * let mux handle new directSystemMessageToUser endpoint * add ClientId to UserEvents across the codebase * render body of system-message to client * add clientId to Chat-Message * add tests showing how url-parsing should work * add simple rest endpoint helpers for parameter-parsing and easy routing * use newly added rest-endpoint helper to rout to Client-Messaging controller * use safe "ReadRestUrlParameter" to parse ClientId * remove empty HandleFunc in router * set Header directly to prevent built-in (platform-dependent) canonicalization to kick in * fix typo in "Parameter" message * remove debug-logging of HTTP headers in REST-helpers * convert to uint32 to prevent overruns when converting to wraptype uint later on * resolve linter-ouchies * resolve linter potential nil-deref warning * document the SendSystemMessageToClient endpoint in swaggerdoc * remove clientId assignment causing potential nil dereference in userDisabledEvent-case as the clientId isn't relevant here anyway * make findClientById private, so its not accessible outside of core/chat * remove redundant string type hint * Update PR based on linter requirements Co-authored-by: Raffael Rehberger <raffael@rtrace.io> Co-authored-by: Gabe Kangas <gabek@real-ity.com>
2021-09-13 11:26:28 +03:00
}
return readParameter(pattern[0], r.URL.Path, parameterName)
}
// RestEndpoint wraps a handler to use the rest endpoint helper.
func RestEndpoint(pattern string, handler http.HandlerFunc) (string, http.HandlerFunc) {
baseURL := getPatternForRestEndpoint(pattern)
return baseURL, func(w http.ResponseWriter, r *http.Request) {
r.Header[restURLPatternHeaderKey] = []string{pattern}
handler(w, r)
}
}