Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile.server
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ RUN cd bytetrade.io/web3os/market && \

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM golang:1.23.11-alpine
FROM alpine:3.23
WORKDIR /opt/app
COPY --from=builder /workspace/bytetrade.io/web3os/market/market .

CMD ["/opt/app/market", "-v", "2", "--logtostderr"]
ENTRYPOINT ["/opt/app/market", "-v", "2", "--logtostderr"]
14 changes: 9 additions & 5 deletions internal/v2/appinfo/localrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func (lr *LocalRepo) UploadAppPackage(userID, sourceID string, fileBytes []byte,
}

// Add source field
if err := writer.WriteField("source", "upload"); err != nil {
if err := writer.WriteField("source", sourceID); err != nil {
return nil, fmt.Errorf("failed to write source field: %w", err)
}

Expand Down Expand Up @@ -353,13 +353,17 @@ func (lr *LocalRepo) UploadAppPackage(userID, sourceID string, fileBytes []byte,
return latest.RawData, nil
}

func (lr *LocalRepo) DeleteApp(userID, appName, appVersion string, token string) error {
glog.V(2).Infof("Deleting app: %s, version: %s, user: %s", appName, appVersion, userID)
func (lr *LocalRepo) DeleteApp(userID, appName, appVersion, sourceID string, token string) error {
glog.V(2).Infof("Deleting app: %s, version: %s, source: %s, user: %s", appName, appVersion, sourceID, userID)

if sourceID == "" {
sourceID = "upload"
}

// Check if the app is currently being installed
if lr.taskModule != nil {
taskType, source, found, completed := lr.taskModule.GetLatestTaskByAppNameAndUser(appName, userID)
if found && !completed && taskType == "install" && source == "upload" {
if found && !completed && taskType == "install" && source == sourceID {
glog.V(3).Infof("Cannot delete app %s: app is currently being installed (task type: %s, source: %s)", appName, taskType, source)
return fmt.Errorf("cannot delete app %s: app is currently being installed", appName)
}
Expand All @@ -381,7 +385,7 @@ func (lr *LocalRepo) DeleteApp(userID, appName, appVersion string, token string)
bodyMap := map[string]string{
"app_name": appName,
"app_version": appVersion,
"source_id": "upload",
"source_id": sourceID,
}
bodyBytes, err := json.Marshal(bodyMap)
if err != nil {
Expand Down
43 changes: 25 additions & 18 deletions pkg/v2/api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,7 @@ func (s *Server) createSafeTagCopy(tag *types.Tag) map[string]interface{} {
type DeleteLocalAppRequest struct {
AppName string `json:"app_name"`
AppVersion string `json:"app_version"`
Source string `json:"source"`
}

// deleteLocalApp handles DELETE /api/v2/apps/delete
Expand Down Expand Up @@ -1912,20 +1913,26 @@ func (s *Server) deleteLocalApp(w http.ResponseWriter, r *http.Request) {
return
}

glog.V(2).Infof("Received delete request for app: %s, version: %s from user: %s", request.AppName, request.AppVersion, userID)
// Default source_id to "upload" for backward compatibility
sourceID := request.Source
if sourceID == "" {
sourceID = "upload"
}

glog.V(2).Infof("Received delete request for app: %s, version: %s, source: %s from user: %s", request.AppName, request.AppVersion, sourceID, userID)

// Step 5: Check if app exists in upload source
// Step 5: Check if app exists in the specified source
userData := s.cacheManager.GetUserData(userID)
if userData == nil {
glog.V(3).Infof("User data not found for user: %s", userID)
s.sendResponse(w, http.StatusNotFound, false, "User data not found", nil)
return
}

sourceData, exists := userData.Sources["upload"]
sourceData, exists := userData.Sources[sourceID]
if !exists {
glog.V(3).Infof("upload source not found for user: %s", userID)
s.sendResponse(w, http.StatusNotFound, false, "upload source not found", nil)
glog.V(3).Infof("Source '%s' not found for user: %s", sourceID, userID)
s.sendResponse(w, http.StatusNotFound, false, fmt.Sprintf("Source '%s' not found", sourceID), nil)
return
}

Expand Down Expand Up @@ -1963,18 +1970,18 @@ func (s *Server) deleteLocalApp(w http.ResponseWriter, r *http.Request) {
}

if !appExists {
glog.V(3).Infof("App %s version %s not found in upload source for user: %s", request.AppName, request.AppVersion, userID)
s.sendResponse(w, http.StatusNotFound, false, "App not found in upload source", nil)
glog.V(3).Infof("App %s version %s not found in source '%s' for user: %s", request.AppName, request.AppVersion, sourceID, userID)
s.sendResponse(w, http.StatusNotFound, false, fmt.Sprintf("App not found in source '%s'", sourceID), nil)
return
}

// Step 6.5: Check if app is uninstalled in upload source (including clone apps)
// Step 6.5: Check if app is uninstalled in the source (including clone apps)
// Only allow deletion if the app is uninstalled or not found in AppStateLatest
glog.V(3).Infof("Checking if app %s is uninstalled in upload source for user: %s", request.AppName, userID)
glog.V(3).Infof("Checking if app %s is uninstalled in source '%s' for user: %s", request.AppName, sourceID, userID)
appInstalled := false
var installedAppName string

// Check upload source for installed instances of this app
// Check the source for installed instances of this app
if sourceData.AppStateLatest != nil {
for _, appState := range sourceData.AppStateLatest {
if appState == nil {
Expand All @@ -1997,42 +2004,42 @@ func (s *Server) deleteLocalApp(w http.ResponseWriter, r *http.Request) {
// Treat installFailed same as uninstalled so deletion can proceed
if appState.Status.State != "uninstalled" && appState.Status.State != "installFailed" && appState.Status.State != "downloadFailed" && appState.Status.State != "installingCanceled" && appState.Status.State != "downloadingCanceled" {
appInstalled = true
glog.V(2).Infof("App %s (or its clone %s) is still installed in upload source with state: %s",
request.AppName, installedAppName, appState.Status.State)
glog.V(2).Infof("App %s (or its clone %s) is still installed in source '%s' with state: %s",
request.AppName, installedAppName, sourceID, appState.Status.State)
break
}
}
}
}

if appInstalled {
glog.V(2).Infof("Cannot delete app %s: app (or its clone %s) is still installed in upload source",
request.AppName, installedAppName)
glog.V(2).Infof("Cannot delete app %s: app (or its clone %s) is still installed in source '%s'",
request.AppName, installedAppName, sourceID)
s.sendResponse(w, http.StatusBadRequest, false,
fmt.Sprintf("Cannot delete app: app (or its clone %s) is still installed. Please uninstall it first.",
installedAppName), nil)
return
}

glog.V(3).Infof("App %s is uninstalled in upload source, proceeding with deletion", request.AppName)
glog.V(3).Infof("App %s is uninstalled in source '%s', proceeding with deletion", request.AppName, sourceID)

// Step 7: Delete chart files using LocalRepo
// Delete chart package file
if err := s.localRepo.DeleteApp(userID, request.AppName, request.AppVersion, token); err != nil {
if err := s.localRepo.DeleteApp(userID, request.AppName, request.AppVersion, sourceID, token); err != nil {
glog.Errorf("Failed to delete chart package: %v", err)
// Continue with deletion even if chart file doesn't exist
s.sendResponse(w, http.StatusInternalServerError, false, "Failed to delete chart package", nil)
return
}

// Step 8: Remove app from AppStateLatest
if err := s.cacheManager.RemoveAppStateData(userID, "upload", request.AppName); err != nil {
if err := s.cacheManager.RemoveAppStateData(userID, sourceID, request.AppName); err != nil {
glog.Errorf("Failed to remove app from AppStateLatest: %v", err)
// Continue with deletion even if app state doesn't exist
}

// Step 9: Remove app from AppInfoLatest
if err := s.cacheManager.RemoveAppInfoLatestData(userID, "upload", request.AppName); err != nil {
if err := s.cacheManager.RemoveAppInfoLatestData(userID, sourceID, request.AppName); err != nil {
glog.Errorf("Failed to remove app from AppInfoLatest: %v", err)
s.sendResponse(w, http.StatusInternalServerError, false, "Failed to remove app from cache", nil)
return
Expand Down
Loading