11package handlers
22
33import (
4+ "errors"
45 "net/http"
56 "strings"
6- "sync/atomic"
77
88 "log/slog"
99
1010 "go.bug.st/f"
1111
12- "github.com/arduino/arduino-app-cli/internal/orchestrator "
12+ "github.com/arduino/arduino-app-cli/internal/apt "
1313 "github.com/arduino/arduino-app-cli/pkg/render"
1414)
1515
16- var matchArduinoPackage = func (p orchestrator .UpgradablePackage ) bool {
16+ var matchArduinoPackage = func (p apt .UpgradablePackage ) bool {
1717 return strings .HasPrefix (p .Name , "arduino-" )
1818}
1919
20- var matchAllPackages = func (p orchestrator .UpgradablePackage ) bool {
20+ var matchAllPackages = func (p apt .UpgradablePackage ) bool {
2121 return true
2222}
2323
24- func HandleCheckUpgradable () http.HandlerFunc {
24+ func HandleCheckUpgradable (aptClient * apt. Service ) http.HandlerFunc {
2525 return func (w http.ResponseWriter , r * http.Request ) {
2626 queryParams := r .URL .Query ()
2727
@@ -35,8 +35,12 @@ func HandleCheckUpgradable() http.HandlerFunc {
3535 filterFunc = matchArduinoPackage
3636 }
3737
38- pkgs , err := orchestrator . GetUpgradablePackages (r .Context (), filterFunc )
38+ pkgs , err := aptClient . ListUpgradablePackages (r .Context (), filterFunc )
3939 if err != nil {
40+ if errors .Is (err , apt .ErrOperationAlreadyInProgress ) {
41+ render .EncodeResponse (w , http .StatusConflict , err .Error ())
42+ return
43+ }
4044 render .EncodeResponse (w , http .StatusBadRequest , "Error checking for upgradable packages: " + err .Error ())
4145 return
4246 }
@@ -53,25 +57,11 @@ func HandleCheckUpgradable() http.HandlerFunc {
5357}
5458
5559type UpdateCheckResult struct {
56- Packages []orchestrator .UpgradablePackage `json:"packages"`
60+ Packages []apt .UpgradablePackage `json:"packages"`
5761}
5862
59- var inProgress atomic.Bool
60-
61- func HandleUpdateApply (eventsBroker * UpdateEventsBroker ) http.HandlerFunc {
63+ func HandleUpdateApply (aptClient * apt.Service ) http.HandlerFunc {
6264 return func (w http.ResponseWriter , r * http.Request ) {
63- // Check if an upgrade is already in progress
64- if inProgress .Load () {
65- render .EncodeResponse (w , http .StatusConflict , "Upgrade already in progress" )
66- return
67- }
68-
69- // Set upgrade in progress
70- if ! inProgress .CompareAndSwap (false , true ) {
71- render .EncodeResponse (w , http .StatusConflict , "Upgrade already in progress" )
72- return
73- }
74-
7565 queryParams := r .URL .Query ()
7666 onlyArduinoPackages := false
7767 if val := queryParams .Get ("only-arduino" ); val != "" {
@@ -83,8 +73,12 @@ func HandleUpdateApply(eventsBroker *UpdateEventsBroker) http.HandlerFunc {
8373 filterFunc = matchArduinoPackage
8474 }
8575
86- pkgs , err := orchestrator . GetUpgradablePackages (r .Context (), filterFunc )
76+ pkgs , err := aptClient . ListUpgradablePackages (r .Context (), filterFunc )
8777 if err != nil {
78+ if errors .Is (err , apt .ErrOperationAlreadyInProgress ) {
79+ render .EncodeResponse (w , http .StatusConflict , err .Error ())
80+ return
81+ }
8882 slog .Error ("Unable to get upgradable packages" , slog .String ("error" , err .Error ()))
8983 render .EncodeResponse (w , http .StatusInternalServerError , "Error checking for upgradable packages" )
9084 return
@@ -95,41 +89,25 @@ func HandleUpdateApply(eventsBroker *UpdateEventsBroker) http.HandlerFunc {
9589 return
9690 }
9791
98- go func () {
99- defer inProgress .Store (false )
100-
101- names := f .Map (pkgs , func (p orchestrator.UpgradablePackage ) string {
102- return p .Name
103- })
104-
105- eventsBroker .PublishLog ("Upgrading: " + strings .Join (names , ", " ))
106-
107- iter , err := orchestrator .RunUpgradeCommand (r .Context (), names )
108- if err != nil {
109- slog .Error ("Error running upgrade command" , slog .String ("error" , err .Error ()))
110- eventsBroker .PublishError (render.SSEErrorData {Message : "failed to upgrade the packages" })
111- return
112- }
113-
114- for item := range iter {
115- eventsBroker .PublishLog (item )
116- }
117-
118- eventsBroker .Restarting ()
92+ names := f .Map (pkgs , func (p apt.UpgradablePackage ) string {
93+ return p .Name
94+ })
11995
120- err = orchestrator . RestartServices ( r . Context () )
121- if err != nil {
122- slog . Error ( "Error restarting services" , slog . String ( "error" , err . Error ()))
123- eventsBroker . PublishError (render. SSEErrorData { Message : "failed to restart services" } )
96+ err = aptClient . UpgradePackages ( names )
97+ if err != nil {
98+ if errors . Is ( err , apt . ErrOperationAlreadyInProgress ) {
99+ render . EncodeResponse ( w , http . StatusConflict , err . Error () )
124100 return
125101 }
126- }()
102+ render .EncodeResponse (w , http .StatusInternalServerError , "Error upgrading packages" )
103+ return
104+ }
127105
128106 render .EncodeResponse (w , http .StatusAccepted , "Upgrade started" )
129107 }
130108}
131109
132- func HandleUpdateEvents (eventsBroker * UpdateEventsBroker ) http.HandlerFunc {
110+ func HandleUpdateEvents (aptClient * apt. Service ) http.HandlerFunc {
133111 return func (w http.ResponseWriter , r * http.Request ) {
134112 sseStream , err := render .NewSSEStream (r .Context (), w )
135113 if err != nil {
@@ -139,13 +117,28 @@ func HandleUpdateEvents(eventsBroker *UpdateEventsBroker) http.HandlerFunc {
139117 }
140118 defer sseStream .Close ()
141119
142- ch := eventsBroker .Subscribe ()
143- defer eventsBroker .Unsubscribe (ch )
120+ ch := aptClient .Subscribe ()
121+ defer aptClient .Unsubscribe (ch )
144122
145123 for {
146124 select {
147- case event := <- ch :
148- sseStream .Send (event )
125+ case event , ok := <- ch :
126+ if ! ok {
127+ slog .Info ("APT event channel closed, stopping SSE stream" )
128+ return
129+ }
130+ if event .Type == apt .ErrorEvent {
131+ sseStream .SendError (render.SSEErrorData {
132+ Code : render .InternalServiceErr ,
133+ Message : event .Data ,
134+ })
135+ } else {
136+ sseStream .Send (render.SSEEvent {
137+ Type : event .Type .String (),
138+ Data : event .Data ,
139+ })
140+ }
141+
149142 case <- r .Context ().Done ():
150143 return
151144 }
0 commit comments