mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-09 02:55:59 +08:00
* Add commands index to command datastore. Add simple test for commands index Add commands index endpoint (cherry picked from commit 4e2a2a2) * Add handler for GET /mdm/commands (cherry picked from commit ae71b8f) * Added Find() method to commands datastore so that the request that matches a response can be retrieved by the connect service. Added Find() method to command service (cherry picked from commit ebceb28) * Fix globally scoped vars in command datastore test suite * groob prefers inline definition of struct members. * Uppercase CommandUuid
159 lines
3.7 KiB
Go
159 lines
3.7 KiB
Go
package command
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
kitlog "github.com/go-kit/kit/log"
|
|
kithttp "github.com/go-kit/kit/transport/http"
|
|
"github.com/gorilla/mux"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
// ServiceHandler returns an HTTP Handler for the command service
|
|
func ServiceHandler(ctx context.Context, svc Service, logger kitlog.Logger) http.Handler {
|
|
opts := []kithttp.ServerOption{
|
|
kithttp.ServerErrorLogger(logger),
|
|
kithttp.ServerErrorEncoder(encodeError),
|
|
}
|
|
|
|
newCommandHandler := kithttp.NewServer(
|
|
ctx,
|
|
makeNewCommandEndpoint(svc),
|
|
decodeNewCommandRequest,
|
|
encodeResponse,
|
|
opts...,
|
|
)
|
|
nextCommandHandler := kithttp.NewServer(
|
|
ctx,
|
|
makeNextCommandEndpoint(svc),
|
|
decodeNextCommandRequest,
|
|
encodeResponse,
|
|
opts...,
|
|
)
|
|
deleteCommandHandler := kithttp.NewServer(
|
|
ctx,
|
|
makeDeleteCommandEndpoint(svc),
|
|
decodeDeleteCommandRequest,
|
|
encodeResponse,
|
|
opts...,
|
|
)
|
|
getCommandsHandler := kithttp.NewServer(
|
|
ctx,
|
|
makeGetCommandsEndpoint(svc),
|
|
decodeGetCommandsRequest,
|
|
encodeResponse,
|
|
opts...,
|
|
)
|
|
|
|
r := mux.NewRouter()
|
|
|
|
r.Handle("/mdm/commands/{udid}", getCommandsHandler).Methods("GET")
|
|
r.Handle("/mdm/commands", newCommandHandler).Methods("POST")
|
|
r.Handle("/mdm/commands/{udid}/next", nextCommandHandler).Methods("GET")
|
|
r.Handle("/mdm/commands/{udid}/{uuid}", deleteCommandHandler).Methods("DELETE")
|
|
|
|
return r
|
|
}
|
|
|
|
func decodeNewCommandRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
|
var request newCommandRequest
|
|
err := json.NewDecoder(r.Body).Decode(&request.CommandRequest)
|
|
return request, err
|
|
}
|
|
|
|
func decodeNextCommandRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
|
vars := mux.Vars(r)
|
|
udid, ok := vars["udid"]
|
|
if !ok {
|
|
return nil, errBadRouting
|
|
}
|
|
var request nextCommandRequest
|
|
request.UDID = udid
|
|
return request, nil
|
|
}
|
|
|
|
func decodeDeleteCommandRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
|
vars := mux.Vars(r)
|
|
udid, ok := vars["udid"]
|
|
if !ok {
|
|
return nil, errBadRouting
|
|
}
|
|
uuid, ok := vars["uuid"]
|
|
if !ok {
|
|
return nil, errBadRouting
|
|
}
|
|
var request deleteCommandRequest
|
|
request.UDID = udid
|
|
request.UUID = uuid
|
|
return request, nil
|
|
}
|
|
|
|
func decodeGetCommandsRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
|
vars := mux.Vars(r)
|
|
udid, ok := vars["udid"]
|
|
if !ok {
|
|
return nil, errBadRouting
|
|
}
|
|
|
|
request := getCommandsRequest{UDID: udid}
|
|
return request, nil
|
|
}
|
|
|
|
type errorer interface {
|
|
error() error
|
|
}
|
|
|
|
type statuser interface {
|
|
status() int
|
|
}
|
|
|
|
type listEncoder interface {
|
|
encodeList(w http.ResponseWriter) error
|
|
}
|
|
|
|
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
|
|
if e, ok := response.(errorer); ok && e.error() != nil {
|
|
encodeError(ctx, e.error(), w)
|
|
return nil
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
// for success responses
|
|
if e, ok := response.(statuser); ok {
|
|
w.WriteHeader(e.status())
|
|
if e.status() == http.StatusNoContent {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// check if this is a collection
|
|
if e, ok := response.(listEncoder); ok {
|
|
return e.encodeList(w)
|
|
|
|
}
|
|
return json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
// encode errors from business-logic
|
|
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
|
// unwrap if the error is wrapped by kit http in it's own error type
|
|
if httperr, ok := err.(kithttp.Error); ok {
|
|
err = httperr.Err
|
|
}
|
|
|
|
switch err {
|
|
// case ErrNotFound:
|
|
// w.WriteHeader(http.StatusNotFound)
|
|
// case errEmptyRequest, errBadUUID:
|
|
// w.WriteHeader(http.StatusBadRequest)
|
|
// case workflow.ErrExists:
|
|
// w.WriteHeader(http.StatusConflict)
|
|
default:
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|