d6866cd85b
- Extend DesktopClientReleaseCheckResponse with platform, arch, and channel fields. - Introduce DesktopClientDownloadableRelease and DesktopClientDownloadableReleaseListResponse interfaces for managing downloadable releases. - Implement ListDownloadable method in DesktopClientReleaseService to retrieve downloadable releases based on the specified channel. - Update DesktopClientReleaseCheckResult to include platform, arch, and channel information. - Add resolveInstallerDownloadURL method to handle download URL resolution for releases. - Create new endpoint in DesktopReleaseHandler for listing downloadable releases. - Update router to include the new downloadable releases route. - Enhance tests to cover the new functionality for resolving download URLs and listing downloadable releases.
146 lines
4.1 KiB
Go
146 lines
4.1 KiB
Go
package transport
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/geo-platform/tenant-api/internal/bootstrap"
|
|
opsapp "github.com/geo-platform/tenant-api/internal/ops/app"
|
|
opsrepo "github.com/geo-platform/tenant-api/internal/ops/repository"
|
|
"github.com/geo-platform/tenant-api/internal/shared/response"
|
|
)
|
|
|
|
type DesktopReleaseHandler struct {
|
|
svc *opsapp.DesktopClientReleaseService
|
|
}
|
|
|
|
func NewDesktopReleaseHandler(a *bootstrap.App) *DesktopReleaseHandler {
|
|
return &DesktopReleaseHandler{
|
|
svc: opsapp.NewDesktopClientReleaseService(
|
|
opsrepo.NewDesktopClientReleaseRepository(a.DB),
|
|
a.ObjectStorage,
|
|
nil,
|
|
),
|
|
}
|
|
}
|
|
|
|
func (h *DesktopReleaseHandler) Latest(c *gin.Context) {
|
|
client := MustDesktopClient(c.Request.Context())
|
|
data, err := h.svc.CheckLatest(c.Request.Context(), opsapp.DesktopClientReleaseCheckInput{
|
|
Platform: c.Query("platform"),
|
|
Arch: c.Query("arch"),
|
|
Channel: defaultDesktopReleaseChannel(c.Query("channel"), client.Channel),
|
|
CurrentVersion: c.Query("version"),
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, data)
|
|
}
|
|
|
|
func (h *DesktopReleaseHandler) DownloadURL(c *gin.Context) {
|
|
client := MustDesktopClient(c.Request.Context())
|
|
data, err := h.svc.ResolveLatestDownloadURL(c.Request.Context(), opsapp.DesktopClientReleaseCheckInput{
|
|
Platform: c.Query("platform"),
|
|
Arch: c.Query("arch"),
|
|
Channel: defaultDesktopReleaseChannel(c.Query("channel"), client.Channel),
|
|
CurrentVersion: c.Query("version"),
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, data)
|
|
}
|
|
|
|
func (h *DesktopReleaseHandler) LatestPublic(c *gin.Context) {
|
|
data, err := h.svc.CheckLatest(c.Request.Context(), opsapp.DesktopClientReleaseCheckInput{
|
|
Platform: c.Query("platform"),
|
|
Arch: c.Query("arch"),
|
|
Channel: c.DefaultQuery("channel", "stable"),
|
|
CurrentVersion: c.Query("version"),
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, data)
|
|
}
|
|
|
|
func (h *DesktopReleaseHandler) DownloadURLPublic(c *gin.Context) {
|
|
data, err := h.svc.ResolveLatestDownloadURL(c.Request.Context(), opsapp.DesktopClientReleaseCheckInput{
|
|
Platform: c.Query("platform"),
|
|
Arch: c.Query("arch"),
|
|
Channel: c.DefaultQuery("channel", "stable"),
|
|
CurrentVersion: c.Query("version"),
|
|
})
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, data)
|
|
}
|
|
|
|
func (h *DesktopReleaseHandler) ListDownloadable(c *gin.Context) {
|
|
data, err := h.svc.ListDownloadable(c.Request.Context(), c.DefaultQuery("channel", "stable"))
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
response.Success(c, data)
|
|
}
|
|
|
|
func (h *DesktopReleaseHandler) UpdaterFeedPublic(c *gin.Context) {
|
|
feed, err := h.svc.ResolveLatestUpdaterFeed(c.Request.Context(), opsapp.DesktopClientReleaseCheckInput{
|
|
Platform: firstNonEmpty(c.Param("platform"), c.Query("platform")),
|
|
Arch: firstNonEmpty(c.Param("arch"), c.Query("arch")),
|
|
Channel: firstNonEmpty(c.Param("channel"), c.DefaultQuery("channel", "stable")),
|
|
CurrentVersion: firstNonEmpty(c.Param("version"), c.Query("version")),
|
|
}, c.Param("feed"))
|
|
if err != nil {
|
|
response.Error(c, err)
|
|
return
|
|
}
|
|
|
|
c.Header("Content-Type", "application/x-yaml; charset=utf-8")
|
|
c.Header("Cache-Control", "no-store")
|
|
c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, sanitizeHeaderFileName(feed.FileName)))
|
|
c.Data(http.StatusOK, "application/x-yaml; charset=utf-8", feed.Content)
|
|
}
|
|
|
|
func firstNonEmpty(values ...string) string {
|
|
for _, value := range values {
|
|
if strings.TrimSpace(value) != "" {
|
|
return value
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func defaultDesktopReleaseChannel(queryValue string, clientChannel *string) string {
|
|
if queryValue != "" {
|
|
return queryValue
|
|
}
|
|
if clientChannel != nil && *clientChannel != "" {
|
|
return *clientChannel
|
|
}
|
|
return "stable"
|
|
}
|
|
|
|
func sanitizeHeaderFileName(value string) string {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return "latest.yml"
|
|
}
|
|
return strings.Map(func(r rune) rune {
|
|
if r == '"' || r == '\\' || r == '\r' || r == '\n' {
|
|
return -1
|
|
}
|
|
return r
|
|
}, value)
|
|
}
|