func AppendLogChunk(db database.Database, artifact *model.Artifact, logChunk *model.LogChunk) *HttpError { if artifact.State != model.APPENDING { return NewHttpError(http.StatusBadRequest, fmt.Sprintf("Unexpected artifact state: %s", artifact.State)) } if logChunk.Size <= 0 { return NewHttpError(http.StatusBadRequest, "Invalid chunk size %d", logChunk.Size) } if logChunk.Content == "" { return NewHttpError(http.StatusBadRequest, "Empty content string") } if int64(len(logChunk.Content)) != logChunk.Size { return NewHttpError(http.StatusBadRequest, "Content length does not match indicated size") } // Find previous chunk in DB - append only if nextByteOffset, err := db.GetLastByteSeenForArtifact(artifact.Id); err != nil { return NewHttpError(http.StatusInternalServerError, "Error while checking for previous byte range: %s", err) } else if nextByteOffset != logChunk.ByteOffset { return NewHttpError(http.StatusBadRequest, "Overlapping ranges detected, expected offset: %d, actual offset: %d", nextByteOffset, logChunk.ByteOffset) } logChunk.ArtifactId = artifact.Id // Expand artifact size - redundant after above change. if artifact.Size < logChunk.ByteOffset+logChunk.Size { artifact.Size = logChunk.ByteOffset + logChunk.Size if err := db.UpdateArtifact(artifact); err != nil { return NewHttpError(http.StatusInternalServerError, err.Error()) } } if err := db.InsertLogChunk(logChunk); err != nil { return NewHttpError(http.StatusBadRequest, "Error updating log chunk: %s", err) } return nil }