diff --git a/backend/go-app/docker.go b/backend/go-app/docker.go index 38041ecf..f9c27eef 100644 --- a/backend/go-app/docker.go +++ b/backend/go-app/docker.go @@ -3,13 +3,16 @@ package main // Docker import ( "archive/tar" + "github.com/shuffle/shuffle-shared" + //"bufio" "path/filepath" //"strconv" "bytes" "context" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -756,7 +759,7 @@ func getDockerImage(resp http.ResponseWriter, request *http.Request) { tagFound = version.Name } - buildSwaggerApp(resp, []byte(openApiApp.Body), user) + buildSwaggerApp(resp, []byte(openApiApp.Body), user, false) } } } @@ -802,6 +805,92 @@ func getDockerImage(resp http.ResponseWriter, request *http.Request) { //resp.WriteHeader(200) } +// Downloads and activates an app from shuffler.io if possible +func handleRemoteDownloadApp(resp http.ResponseWriter, ctx context.Context, user shuffle.User, appId string) { + url := fmt.Sprintf("https://shuffler.io/api/v1/apps/%s/config", appId) + log.Printf("Downloading API from %s", url) + req, err := http.NewRequest( + "GET", + url, + nil, + ) + + if err != nil { + log.Printf("[ERROR] Failed auto-downloading app %s: %s", appId, err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + httpClient := &http.Client{} + newresp, err := httpClient.Do(req) + if err != nil { + log.Printf("[ERROR] Failed running auto-download request for %s: %s", appId, err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + respBody, err := ioutil.ReadAll(newresp.Body) + if err != nil { + log.Printf("[ERROR] Failed setting respbody for workflow download: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + if len(respBody) > 0 { + type tmpapp struct { + Success bool `json:"success"` + OpenAPI string `json:"openapi"` + } + + app := tmpapp{} + err := json.Unmarshal(respBody, &app) + if err != nil || app.Success == false || len(app.OpenAPI) == 0 { + log.Printf("[ERROR] Failed app unmarshal during auto-download. Success%#v. Applength: %d: %s", app.Success, len(app.OpenAPI), err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + key, err := base64.StdEncoding.DecodeString(app.OpenAPI) + if err != nil { + log.Printf("[ERROR] Failed auto-setting OpenAPI app: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + cacheKey := fmt.Sprintf("workflowapps-sorted-100") + shuffle.DeleteCache(ctx, cacheKey) + cacheKey = fmt.Sprintf("workflowapps-sorted-500") + shuffle.DeleteCache(ctx, cacheKey) + cacheKey = fmt.Sprintf("workflowapps-sorted-1000") + shuffle.DeleteCache(ctx, cacheKey) + + newapp := shuffle.ParsedOpenApi{} + err = json.Unmarshal(key, &newapp) + if err != nil { + log.Printf("[ERROR] Failed openapi unmarshal during auto-download: %s", app.Success, len(app.OpenAPI), err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + err = json.Unmarshal(key, &newapp) + if err != nil { + log.Printf("[ERROR] Failed openapi unmarshal during auto-download: %s", app.Success, len(app.OpenAPI), err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + return + } + + buildSwaggerApp(resp, []byte(newapp.Body), user, true) + return + } +} + func activateWorkflowAppDocker(resp http.ResponseWriter, request *http.Request) { cors := shuffle.HandleCors(resp, request) if cors { @@ -845,9 +934,9 @@ func activateWorkflowAppDocker(resp http.ResponseWriter, request *http.Request) apps, err := shuffle.FindWorkflowAppByName(ctx, appName) //log.Printf("[INFO] Found %d apps for %s", len(apps), appName) if err != nil || len(apps) == 0 { - log.Printf("[WARNING] Error getting app %s (app config): %s", appName, err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + log.Printf("[WARNING] Error getting app %s (app config). Starting remote download.: %s", appName, err) + + handleRemoteDownloadApp(resp, ctx, user, fileId) return } @@ -868,10 +957,12 @@ func activateWorkflowAppDocker(resp http.ResponseWriter, request *http.Request) app = &selectedApp } else { - log.Printf("[WARNING] Error getting app with ID %s (app config): %s", fileId, err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + log.Printf("[WARNING] Error getting app with ID %s (app config): %s. Starting remote download(2)", fileId, err) + handleRemoteDownloadApp(resp, ctx, user, fileId) return + //resp.WriteHeader(401) + //resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`)) + //return } } diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 8192107a..4c9b21b5 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -3153,18 +3153,19 @@ func handleSwaggerValidation(body []byte) (shuffle.ParsedOpenApi, error) { return parsed, err } -func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) { +func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, skipEdit bool) { type Test struct { - Editing bool `datastore:"editing"` - Id string `datastore:"id"` - Image string `datastore:"image"` + Editing bool `json:"editing" datastore:"editing"` + Id string `json:"id" datastore:"id"` + Image string `json:"image" datastore:"image"` + Body string `json:"body" datastore:"body"` } var test Test err := json.Unmarshal(body, &test) if err != nil { - log.Printf("[WARNING] Failed unmarshalling test: %s", err) - resp.WriteHeader(401) + log.Printf("[ERROR] Failed unmarshalling in swagger build: %s", err) + resp.WriteHeader(400) resp.Write([]byte(`{"success": false}`)) return } @@ -3174,13 +3175,13 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) { hasher.Write(body) newmd5 := hex.EncodeToString(hasher.Sum(nil)) - if test.Editing && len(user.Id) > 0 { + if test.Editing && len(user.Id) > 0 && skipEdit != true { // Quick verification test ctx := context.Background() app, err := shuffle.GetApp(ctx, test.Id, user, false) if err != nil { - log.Printf("[WARNING] Error getting app when editing: %s", app.Name) - resp.WriteHeader(401) + log.Printf("[ERROR] Error getting app when editing: %s", app.Name) + resp.WriteHeader(400) resp.Write([]byte(`{"success": false}`)) return } @@ -3188,7 +3189,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) { // FIXME: Check whether it's in use. if user.Id != app.Owner && user.Role != "admin" { log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name) - resp.WriteHeader(401) + resp.WriteHeader(400) resp.Write([]byte(`{"success": false}`)) return } @@ -3212,7 +3213,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) { } if swagger.Info == nil { - log.Printf("[ERORR] Info is nil?: %#v", swagger) + log.Printf("[ERORR] Info is nil in swagger?") resp.WriteHeader(500) resp.Write([]byte(`{"success": false, "reason": "Info not parsed"}`)) return @@ -3322,7 +3323,7 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User) { //log.Println(stitched) // 3. Zip and stream it directly in the directory - _, err = shuffle.StreamZipdata(ctx, identifier, stitched, "requests\nurllib3", "") + _, err = shuffle.StreamZipdata(ctx, identifier, stitched, shuffle.GetAppRequirements(), "") if err != nil { log.Printf("[ERROR] Zipfile error: %s", err) resp.WriteHeader(500) @@ -3473,7 +3474,7 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) { return } - buildSwaggerApp(resp, body, user) + buildSwaggerApp(resp, body, user, false) } // Creates osfs from folderpath with a basepath as directory base @@ -3544,7 +3545,6 @@ func handleAppHotload(ctx context.Context, location string, forceUpdate bool) er return err } - //log.Printf("Reading app folder: %#v", dir) _, _, err = IterateAppGithubFolders(ctx, fs, dir, "", "", forceUpdate) if err != nil { log.Printf("[WARNING] Githubfolders error: %s", err)