feat: initial open-source release of Pipely
OTA update server designed for high-concurrency, low-bandwidth deployments. GORM-backed PostgreSQL, JWT auth, device management, artefact versioning, deployment rollout with gated rate-limited downloads, and a React admin panel.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package delta
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Handler provides delta patch generation for JAR artefacts.
|
||||
type Handler struct {
|
||||
artefactDir string
|
||||
}
|
||||
|
||||
func NewHandler(artefactDir string) *Handler {
|
||||
return &Handler{artefactDir: artefactDir}
|
||||
}
|
||||
|
||||
// GenerateDelta creates a delta patch between two artefact versions.
|
||||
// POST /api/v1/delta/generate
|
||||
// Form fields: oldVersion, newVersion
|
||||
func (h *Handler) GenerateDelta(c *gin.Context) {
|
||||
oldVersion := c.PostForm("oldVersion")
|
||||
newVersion := c.PostForm("newVersion")
|
||||
if oldVersion == "" || newVersion == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "oldVersion and newVersion are required"})
|
||||
return
|
||||
}
|
||||
|
||||
oldDir := filepath.Join(h.artefactDir, oldVersion)
|
||||
newDir := filepath.Join(h.artefactDir, newVersion)
|
||||
|
||||
if _, err := os.Stat(oldDir); os.IsNotExist(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Old version not found: " + oldVersion})
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(newDir); os.IsNotExist(err) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "New version not found: " + newVersion})
|
||||
return
|
||||
}
|
||||
|
||||
// Find JAR files in each version directory
|
||||
oldJar, err := findJarInDir(oldDir)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "No JAR found in old version: " + err.Error()})
|
||||
return
|
||||
}
|
||||
newJar, err := findJarInDir(newDir)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "No JAR found in new version: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
patchPath := filepath.Join(h.artefactDir, "patches", oldVersion+"-to-"+newVersion+".patch")
|
||||
if err := os.MkdirAll(filepath.Dir(patchPath), 0755); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create patch directory"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := GenerateJarDelta(oldJar, newJar, patchPath); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Delta generation failed: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": "generated",
|
||||
"patchPath": patchPath,
|
||||
"oldVersion": oldVersion,
|
||||
"newVersion": newVersion,
|
||||
})
|
||||
}
|
||||
|
||||
func findJarInDir(dir string) (string, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() && filepath.Ext(e.Name()) == ".jar" {
|
||||
return filepath.Join(dir, e.Name()), nil
|
||||
}
|
||||
}
|
||||
return "", os.ErrNotExist
|
||||
}
|
||||
Reference in New Issue
Block a user