diff --git a/.gitignore b/.gitignore index 5a5a4cb3..1ccd8037 100644 --- a/.gitignore +++ b/.gitignore @@ -223,3 +223,16 @@ $RECYCLE.BIN/ dist/ **/aem/home/ !pkg/instance/resource + + +# VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets +!*.code-workspace + +# Built Visual Studio Code Extensions +*.vsix \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..d90c716b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Print help", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/aem", + "args": ["--help"], + "env": {}, + "cwd": "${workspaceFolder}" + }, + { + "name": "Replicate node", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/aem", + "args": ["repl", "activate", "-A", "--path", "/content/projects/jcr:content"], + "env": {}, + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/pkg/repl.go b/pkg/repl.go index 8cc40884..391aedcf 100644 --- a/pkg/repl.go +++ b/pkg/repl.go @@ -2,11 +2,13 @@ package pkg import ( "fmt" + "io" + "strings" + log "github.com/sirupsen/logrus" "github.com/spf13/cast" "github.com/wttech/aemc/pkg/replication" "github.com/wttech/aemc/pkg/sling" - "io" ) type Replication struct { @@ -51,6 +53,7 @@ func (r Replication) Deactivate(path string) error { return nil } +// replicate a path to a specific agent; respect response format (older AEM uses HTML, newer uses JSON) func (r Replication) replicate(cmd string, path string) error { response, err := r.instance.http.Request(). SetFormData(map[string]string{ @@ -63,16 +66,27 @@ func (r Replication) replicate(cmd string, path string) error { } else if response.IsError() { return fmt.Errorf("%s > cannot do replication command '%s' for path '%s': %s", r.instance.IDColor(), cmd, path, response.Status()) } - htmlBytes, err := io.ReadAll(response.RawBody()) + + responseBytes, err := io.ReadAll(response.RawBody()) if err != nil { return fmt.Errorf("%s > cannot read replication command '%s' response for path '%s': %w", r.instance.IDColor(), cmd, path, err) } - htmlData, err := sling.HtmlData(string(htmlBytes)) + + contentType := response.Header().Get("Content-Type") + responseBody := string(responseBytes) + + var responseData sling.ResponseData + if strings.Contains(strings.ToLower(contentType), "application/json") || + (strings.HasPrefix(strings.TrimSpace(responseBody), "{") && strings.HasSuffix(strings.TrimSpace(responseBody), "}")) { + responseData, err = sling.JsonData(responseBody) + } else { + responseData, err = sling.HtmlData(responseBody) + } if err != nil { return fmt.Errorf("%s > cannot parse replication command '%s' response for path '%s': %w", r.instance.IDColor(), cmd, path, err) } - if htmlData.IsError() { - return fmt.Errorf("%s > cannot do replication command '%s' for path '%s': %s", r.instance.IDColor(), cmd, path, htmlData.Message) + if responseData.IsError() { + return fmt.Errorf("%s > replication command '%s' failed for path '%s': %s", r.instance.IDColor(), cmd, path, responseData.GetMessage()) } return nil } diff --git a/pkg/sling/html_response.go b/pkg/sling/html_response.go index bdc61031..03176e98 100644 --- a/pkg/sling/html_response.go +++ b/pkg/sling/html_response.go @@ -1,9 +1,10 @@ package sling import ( + "strings" + "github.com/PuerkitoBio/goquery" "github.com/spf13/cast" - "strings" ) type HTMLData struct { @@ -34,7 +35,11 @@ func HtmlData(html string) (data HTMLData, err error) { } func (d HTMLData) IsError() bool { - return d.Status <= 0 || d.Status > 399 + return d.Status < 200 || d.Status >= 400 +} + +func (d HTMLData) GetMessage() string { + return d.Message } func htmlElementText(doc *goquery.Document, selector string, defaultValue string) string { diff --git a/pkg/sling/json_response.go b/pkg/sling/json_response.go new file mode 100644 index 00000000..0d1642f0 --- /dev/null +++ b/pkg/sling/json_response.go @@ -0,0 +1,38 @@ +package sling + +import ( + "encoding/json" + + "github.com/spf13/cast" +) + +type JSONData struct { + Status int + Message string + Path []string + StatusMessage string + StatusCode int +} + +func JsonData(jsonStr string) (data JSONData, err error) { + var rawData map[string]any + if err := json.Unmarshal([]byte(jsonStr), &rawData); err != nil { + return data, err + } + + data.Path = cast.ToStringSlice(rawData["path"]) + data.StatusMessage = cast.ToString(rawData["status.message"]) + data.Message = data.StatusMessage + data.StatusCode = cast.ToInt(rawData["status.code"]) + data.Status = data.StatusCode + + return data, nil +} + +func (d JSONData) IsError() bool { + return d.Status < 200 || d.Status >= 400 +} + +func (d JSONData) GetMessage() string { + return d.Message +} diff --git a/pkg/sling/response.go b/pkg/sling/response.go new file mode 100644 index 00000000..18395c85 --- /dev/null +++ b/pkg/sling/response.go @@ -0,0 +1,6 @@ +package sling + +type ResponseData interface { + IsError() bool + GetMessage() string +}