diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index e40599e9..7bd43258 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -379,6 +379,12 @@ func (bl *FxBlockchain) serve(w http.ResponseWriter, r *http.Request) { actionDeleteFulaConfig: func(from peer.ID, w http.ResponseWriter, r *http.Request) { bl.handleDeleteFulaConfig(r.Context(), from, w, r) }, + actionDeleteWifi: func(from peer.ID, w http.ResponseWriter, r *http.Request) { + bl.handleDeleteWifi(r.Context(), from, w, r) + }, + actionDisconnectWifi: func(from peer.ID, w http.ResponseWriter, r *http.Request) { + bl.handleDisconnectWifi(r.Context(), from, w, r) + }, } // Look up the function in the map and call it @@ -526,6 +532,51 @@ func (bl *FxBlockchain) handleDeleteFulaConfig(ctx context.Context, from peer.ID } +func (bl *FxBlockchain) handleDeleteWifi(ctx context.Context, from peer.ID, w http.ResponseWriter, r *http.Request) { + log := log.With("action", actionDeleteWifi, "from", from) + + // Parse the JSON body of the request into the DeleteWifiRequest struct + var req wifi.DeleteWifiRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + log.Error("failed to decode request: %v", err) + http.Error(w, "failed to decode request", http.StatusBadRequest) + return + } + log.Debugw("handleDeleteWifi received", "req", req) + + out := wifi.DeleteWifi(ctx, req) + + w.WriteHeader(http.StatusOK) + if err := json.NewEncoder(w).Encode(out); err != nil { + log.Error("failed to write response: %v", err) + http.Error(w, "failed to write response", http.StatusInternalServerError) + return + } + +} +func (bl *FxBlockchain) handleDisconnectWifi(ctx context.Context, from peer.ID, w http.ResponseWriter, r *http.Request) { + log := log.With("action", actionDisconnectWifi, "from", from) + + // Parse the JSON body of the request into the DeleteWifiRequest struct + var req wifi.DeleteWifiRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + log.Error("failed to decode request: %v", err) + http.Error(w, "failed to decode request", http.StatusBadRequest) + return + } + log.Debugw("handleDisconnectWifi received", "req", req) + + out := wifi.DisconnectNamedWifi(ctx, req) + + w.WriteHeader(http.StatusOK) + if err := json.NewEncoder(w).Encode(out); err != nil { + log.Error("failed to write response: %v", err) + http.Error(w, "failed to write response", http.StatusInternalServerError) + return + } + +} + func (bl *FxBlockchain) SetAuth(ctx context.Context, on peer.ID, subject peer.ID, allow bool) error { // Check if auth is for local host; if so, handle it locally. if on == bl.h.ID() { @@ -572,7 +623,7 @@ func (bl *FxBlockchain) authorized(pid peer.ID, action string) bool { return true } switch action { - case actionBloxFreeSpace, actionWifiRemoveall, actionReboot, actionPartition, actionDeleteFulaConfig, actionSeeded, actionAccountExists, actionPoolCreate, actionPoolJoin, actionPoolCancelJoin, actionPoolRequests, actionPoolList, actionPoolVote, actionPoolLeave, actionManifestUpload, actionManifestStore, actionManifestAvailable, actionManifestRemove, actionManifestRemoveStorer, actionManifestRemoveStored: + case actionBloxFreeSpace, actionWifiRemoveall, actionReboot, actionPartition, actionDeleteWifi, actionDisconnectWifi, actionDeleteFulaConfig, actionSeeded, actionAccountExists, actionPoolCreate, actionPoolJoin, actionPoolCancelJoin, actionPoolRequests, actionPoolList, actionPoolVote, actionPoolLeave, actionManifestUpload, actionManifestStore, actionManifestAvailable, actionManifestRemove, actionManifestRemoveStorer, actionManifestRemoveStored: bl.authorizedPeersLock.RLock() _, ok := bl.authorizedPeers[pid] bl.authorizedPeersLock.RUnlock() diff --git a/blockchain/blox.go b/blockchain/blox.go index 14af0836..0544963f 100644 --- a/blockchain/blox.go +++ b/blockchain/blox.go @@ -1,11 +1,14 @@ package blockchain import ( + "bytes" "context" + "encoding/json" "fmt" "io" "net/http" + "github.com/functionland/go-fula/wap/pkg/wifi" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" ) @@ -151,3 +154,77 @@ func (bl *FxBlockchain) DeleteFulaConfig(ctx context.Context, to peer.ID) ([]byt } } + +func (bl *FxBlockchain) DeleteWifi(ctx context.Context, to peer.ID, r wifi.DeleteWifiRequest) ([]byte, error) { + + if bl.allowTransientConnection { + ctx = network.WithUseTransient(ctx, "fx.blockchain") + } + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(r); err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://"+to.String()+".invalid/"+actionDeleteWifi, &buf) + if err != nil { + return nil, err + } + resp, err := bl.c.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + switch { + case err != nil: + return nil, err + case resp.StatusCode != http.StatusAccepted: + // Attempt to parse the body as JSON. + if jsonErr := json.Unmarshal(b, &apiError); jsonErr != nil { + // If we can't parse the JSON, return the original body in the error. + return nil, fmt.Errorf("unexpected response: %d %s", resp.StatusCode, string(b)) + } + // Return the parsed error message and description. + return nil, fmt.Errorf("unexpected response: %d %s - %s", resp.StatusCode, apiError.Message, apiError.Description) + default: + return b, nil + } +} + +func (bl *FxBlockchain) DisconnectWifi(ctx context.Context, to peer.ID, r wifi.DeleteWifiRequest) ([]byte, error) { + + if bl.allowTransientConnection { + ctx = network.WithUseTransient(ctx, "fx.blockchain") + } + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(r); err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://"+to.String()+".invalid/"+actionDisconnectWifi, &buf) + if err != nil { + return nil, err + } + resp, err := bl.c.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + switch { + case err != nil: + return nil, err + case resp.StatusCode != http.StatusAccepted: + // Attempt to parse the body as JSON. + if jsonErr := json.Unmarshal(b, &apiError); jsonErr != nil { + // If we can't parse the JSON, return the original body in the error. + return nil, fmt.Errorf("unexpected response: %d %s", resp.StatusCode, string(b)) + } + // Return the parsed error message and description. + return nil, fmt.Errorf("unexpected response: %d %s - %s", resp.StatusCode, apiError.Message, apiError.Description) + default: + return b, nil + } +} diff --git a/blockchain/interface.go b/blockchain/interface.go index 6f88860e..b8ec598f 100644 --- a/blockchain/interface.go +++ b/blockchain/interface.go @@ -37,6 +37,8 @@ const ( actionReboot = "reboot" actionPartition = "partition" actionDeleteFulaConfig = "delete-fula-config" + actionDeleteWifi = "delete-wifi" + actionDisconnectWifi = "disconnect-wifi" ) type LinkWithLimit struct { @@ -310,6 +312,8 @@ type Blockchain interface { BloxFreeSpace(context.Context, peer.ID) ([]byte, error) WifiRemoveall(context.Context, peer.ID) ([]byte, error) Reboot(context.Context, peer.ID) ([]byte, error) + DeleteWifi(context.Context, peer.ID, wifi.DeleteWifiRequest) ([]byte, error) + DisconnectWifi(context.Context, peer.ID, wifi.DeleteWifiRequest) ([]byte, error) Partition(context.Context, peer.ID) ([]byte, error) DeleteFulaConfig(context.Context, peer.ID) ([]byte, error) } @@ -341,6 +345,8 @@ var requestTypes = map[string]reflect.Type{ actionReboot: reflect.TypeOf(wifi.RebootRequest{}), actionPartition: reflect.TypeOf(wifi.PartitionRequest{}), actionDeleteFulaConfig: reflect.TypeOf(wifi.DeleteFulaConfigRequest{}), + actionDeleteWifi: reflect.TypeOf(wifi.DeleteWifiRequest{}), + actionDisconnectWifi: reflect.TypeOf(wifi.DeleteWifiRequest{}), } var responseTypes = map[string]reflect.Type{ @@ -370,4 +376,6 @@ var responseTypes = map[string]reflect.Type{ actionReboot: reflect.TypeOf(wifi.RebootResponse{}), actionPartition: reflect.TypeOf(wifi.PartitionResponse{}), actionDeleteFulaConfig: reflect.TypeOf(wifi.DeleteFulaConfigResponse{}), + actionDeleteWifi: reflect.TypeOf(wifi.DeleteWifiResponse{}), + actionDisconnectWifi: reflect.TypeOf(wifi.DeleteWifiResponse{}), } diff --git a/blox/example_test.go b/blox/example_test.go index 77d50456..14a842d2 100644 --- a/blox/example_test.go +++ b/blox/example_test.go @@ -1123,7 +1123,7 @@ func Example_blserver() { panic(err) } defer n1.Shutdown(ctx) - fmt.Printf("n1 Instantiated node in pool %s with ID: %s\n", poolName, h1.ID().String()) + log.Debugf("n1 Instantiated node in pool %s with ID: %s\n", poolName, h1.ID().String()) // Instantiate the second node in the pool pid2, _, err := crypto.GenerateECDSAKeyPair(rng) @@ -1153,7 +1153,7 @@ func Example_blserver() { panic(err) } defer n2.Shutdown(ctx) - fmt.Printf("n2 Instantiated node in pool %s with ID: %s\n", poolName, h2.ID().String()) + log.Debugf("n2 Instantiated node in pool %s with ID: %s\n", poolName, h2.ID().String()) // Instantiate the third node in the pool pid3, _, err := crypto.GenerateECDSAKeyPair(rng) @@ -1183,7 +1183,7 @@ func Example_blserver() { panic(err) } defer n3.Shutdown(ctx) - fmt.Printf("n3 Instantiated node in pool %s with ID: %s\n", poolName, h3.ID().String()) + log.Debugf("n3 Instantiated node in pool %s with ID: %s\n", poolName, h3.ID().String()) if err = h1.Connect(ctx, peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}); err != nil { panic(err) @@ -1194,12 +1194,13 @@ func Example_blserver() { // Wait until the nodes discover each other for { - if len(h1.Peerstore().Peers()) == 4 && - len(h2.Peerstore().Peers()) == 4 && - len(h3.Peerstore().Peers()) == 4 { + if len(h1.Peerstore().Peers()) >= 3 && + len(h2.Peerstore().Peers()) >= 3 && + len(h3.Peerstore().Peers()) >= 3 { break } else { - fmt.Printf("n1 Finally %s peerstore contains %d nodes:\n", h1.ID(), len(h1.Peerstore().Peers())) + h1Peers := h1.Peerstore().Peers() + log.Debugf("n1 Only %s peerstore contains %d nodes:\n", h1.ID(), len(h1Peers)) } select { case <-ctx.Done(): @@ -1210,21 +1211,21 @@ func Example_blserver() { } h1Peers := h1.Peerstore().Peers() - fmt.Printf("n1 Finally %s peerstore contains %d nodes:\n", h1.ID(), len(h1Peers)) + log.Debugf("n1 Finally %s peerstore contains %d nodes:\n", h1.ID(), len(h1Peers)) for _, id := range h1Peers { - fmt.Printf("- %s\n", id) + log.Debugf("- %s\n", id) } h2Peers := h2.Peerstore().Peers() - fmt.Printf("n2 Finally %s peerstore contains %d nodes:\n", h2.ID(), len(h2Peers)) + log.Debugf("n2 Finally %s peerstore contains %d nodes:\n", h2.ID(), len(h2Peers)) for _, id := range h2Peers { - fmt.Printf("- %s\n", id) + log.Debugf("- %s\n", id) } h3Peers := h3.Peerstore().Peers() - fmt.Printf("n3 Finally %s peerstore contains %d nodes:\n", h3.ID(), len(h3Peers)) + log.Debugf("n3 Finally %s peerstore contains %d nodes:\n", h3.ID(), len(h3Peers)) for _, id := range h3Peers { - fmt.Printf("- %s\n", id) + log.Debugf("- %s\n", id) } // Instantiate the fourth node not in the pool @@ -1262,7 +1263,7 @@ func Example_blserver() { panic(err) } defer n4.Shutdown(ctx) - fmt.Printf("n4 Instantiated node in pool %s with ID: %s\n", poolName, h4.ID().String()) + log.Debugf("n4 Instantiated node in pool %s with ID: %s\n", poolName, h4.ID().String()) n4.AnnounceJoinPoolRequestPeriodically(ctx) @@ -1282,12 +1283,12 @@ func Example_blserver() { for id, status := range members { memberInfo := fmt.Sprintf("Member ID: %s, Status: %v", id.String(), status) - fmt.Println(memberInfo) + log.Debugln(memberInfo) } if len(members) >= 2 { break } else { - fmt.Println(members) + log.Debugln(members) } select { case <-ctx.Done(): @@ -1298,9 +1299,9 @@ func Example_blserver() { } h4Peers := h4.Peerstore().Peers() - fmt.Printf("n4 Finally %s peerstore contains %d nodes:\n", h4.ID(), len(h4Peers)) + log.Debugf("n4 Finally %s peerstore contains %d nodes:\n", h4.ID(), len(h4Peers)) for _, id := range h4Peers { - fmt.Printf("- %s\n", id) + log.Debugf("- %s\n", id) } //wait for 60 seconds @@ -1319,34 +1320,6 @@ func Example_blserver() { } // Unordered output: - // n1 Instantiated node in pool 1 with ID: QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // n2 Instantiated node in pool 1 with ID: QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // n3 Instantiated node in pool 1 with ID: QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // n1 Finally QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT peerstore contains 4 nodes: - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // n2 Finally QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF peerstore contains 4 nodes: - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // n3 Finally QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA peerstore contains 4 nodes: - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // n4 Instantiated node in pool 1 with ID: QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // n4 Finally QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe peerstore contains 4 nodes: - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // Member ID: QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe, Status: 1 - // Member ID: QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA, Status: 2 - // Member ID: QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT, Status: 2 - // Member ID: QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF, Status: 2 // Voted on QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe {"pool_id":1,"account":"QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe","vote_value":true} // Voted on QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe {"pool_id":1,"account":"QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe","vote_value":true} // Voted on QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe {"pool_id":1,"account":"QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe","vote_value":true} diff --git a/exchange/example_test.go b/exchange/example_test.go index b84c3035..0dd50282 100644 --- a/exchange/example_test.go +++ b/exchange/example_test.go @@ -342,9 +342,9 @@ func Example_provideAfterPull() { // Wait until the nodes discover each other for { - if len(h1.Peerstore().Peers()) == 4 && - len(h2.Peerstore().Peers()) == 4 && - len(h3.Peerstore().Peers()) == 4 { + if len(h1.Peerstore().Peers()) >= 3 && + len(h2.Peerstore().Peers()) >= 3 && + len(h3.Peerstore().Peers()) >= 3 { break } select { @@ -355,23 +355,11 @@ func Example_provideAfterPull() { } } - h1Peers := h1.Peerstore().Peers() - fmt.Printf("Finally %s peerstore contains %d nodes:\n", h1.ID(), len(h1Peers)) - for _, id := range h1Peers { - fmt.Printf("- %s\n", id) - } + fmt.Printf("Finally %s peerstore contains >=3 nodes:\n", h1.ID()) - h2Peers := h2.Peerstore().Peers() - fmt.Printf("Finally %s peerstore contains %d nodes:\n", h2.ID(), len(h2Peers)) - for _, id := range h2Peers { - fmt.Printf("- %s\n", id) - } + fmt.Printf("Finally %s peerstore contains >=3 nodes:\n", h2.ID()) - h3Peers := h3.Peerstore().Peers() - fmt.Printf("Finally %s peerstore contains %d nodes:\n", h3.ID(), len(h3Peers)) - for _, id := range h3Peers { - fmt.Printf("- %s\n", id) - } + fmt.Printf("Finally %s peerstore contains >=3 nodes:\n", h3.ID()) //Manually adding h4 as it is not in the same pool h1.Peerstore().AddAddrs(h4.ID(), h4.Addrs(), peerstore.PermanentAddrTTL) @@ -393,8 +381,6 @@ func Example_provideAfterPull() { for { if len(h4.Peerstore().Peers()) >= 4 { break - } else { - fmt.Printf("%s peerstore contains %d nodes:\n", h4.ID(), len(h4.Peerstore().Peers())) } select { case <-ctx.Done(): @@ -530,21 +516,9 @@ func Example_provideAfterPull() { // Instantiated node in pool 1 with ID: QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF // Instantiated node in pool 1 with ID: QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA // Instantiated node in pool 0 with ID: QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // Finally QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT peerstore contains 4 nodes: - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // Finally QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF peerstore contains 4 nodes: - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA - // Finally QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA peerstore contains 4 nodes: - // - QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT - // - QmUg1bGBZ1rSNt3LZR7kKf9RDy3JtJLZZDZGKrzSP36TMe - // - QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF - // - QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA + // Finally QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT peerstore contains >=3 nodes: + // Finally QmPNZMi2LAhczsN2FoXXQng6YFYbSHApuP6RpKuHbBH9eF peerstore contains >=3 nodes: + // Finally QmYMEnv3GUKPNr34gePX2qQmBH4YEQcuGhQHafuKuujvMA peerstore contains >=3 nodes: // QmaUMRTBMoANXqpUbfARnXkw9esfz9LP2AjXRRr7YknDAT stored IPLD data with links: // root: bafyreibzsetfhqrayathm5tkmm7axuljxcas3pbqrncrosx2fiky4wj5gy // leaf:bafyreidulpo7on77a6pkq7c6da5mlj4n2p3av2zjomrpcpeht5zqgafc34 diff --git a/mobile/blockchain.go b/mobile/blockchain.go index 0352d921..7b6f0873 100644 --- a/mobile/blockchain.go +++ b/mobile/blockchain.go @@ -4,6 +4,7 @@ import ( "context" "github.com/functionland/go-fula/blockchain" + wifi "github.com/functionland/go-fula/wap/pkg/wifi" ) // AccountExists requests blox at Config.BloxAddr to check if the account exists or not. @@ -102,6 +103,26 @@ func (c *Client) Reboot() ([]byte, error) { return c.bl.Reboot(ctx, c.bloxPid) } +// Reboot requests the blox to reboot +func (c *Client) DeleteWifi(name string) ([]byte, error) { + ctx := context.TODO() + // Create the DeleteWifiRequest + req := wifi.DeleteWifiRequest{ + ConnectionName: name, + } + return c.bl.DeleteWifi(ctx, c.bloxPid, req) +} + +// Reboot requests the blox to reboot +func (c *Client) DisconnectWifi(name string) ([]byte, error) { + ctx := context.TODO() + // Create the DeleteWifiRequest + req := wifi.DeleteWifiRequest{ + ConnectionName: name, + } + return c.bl.DisconnectWifi(ctx, c.bloxPid, req) +} + // Partition requests the blox to partition ssd and nvme func (c *Client) Partition() ([]byte, error) { ctx := context.TODO() diff --git a/wap/cmd/main.go b/wap/cmd/main.go index fa42cddb..61dd5a68 100644 --- a/wap/cmd/main.go +++ b/wap/cmd/main.go @@ -197,6 +197,11 @@ func handleAppState(ctx context.Context, isConnected bool, stopServer chan struc log.Info("Wi-Fi is connected") configExists := checkConfigExists() if configExists { + req := wifi.DeleteWifiRequest{ + ConnectionName: "FxBlox", + } + _ = wifi.DisconnectNamedWifi(ctx, req) + stopServer <- struct{}{} // stop the HTTP server } else { log.Info("No config file found, activating the hotspot mode.") diff --git a/wap/pkg/wifi/wifi.go b/wap/pkg/wifi/wifi.go index 1dd8bc02..998b7ed1 100644 --- a/wap/pkg/wifi/wifi.go +++ b/wap/pkg/wifi/wifi.go @@ -21,6 +21,14 @@ type WifiRemoveallResponse struct { Status bool `json:"status"` } +type DeleteWifiRequest struct { + ConnectionName string `json:"name"` +} +type DeleteWifiResponse struct { + Msg string `json:"msg"` + Status bool `json:"status"` +} + type DeleteFulaConfigRequest struct { } type DeleteFulaConfigResponse struct { @@ -197,6 +205,56 @@ func DeleteFulaConfig(ctx context.Context) DeleteFulaConfigResponse { } } +func DeleteWifi(ctx context.Context, req DeleteWifiRequest) DeleteWifiResponse { + errorString := "" + command := fmt.Sprintf("nmcli con delete '%s'", strings.TrimSpace(req.ConnectionName)) + _, _, err := runCommand(ctx, command) + if err != nil { + log.Warnf("failed to delete connection %s: %v", req.ConnectionName, err) + errorString = fmt.Sprintf("Failed to delete connection %s: %v", req.ConnectionName, err) + } + + if errorString != "" { + return DeleteWifiResponse{ + Msg: errorString, + Status: false, + } + } + + msg := "wifi connection removed successfully. " + status := true + + return DeleteWifiResponse{ + Msg: msg, + Status: status, + } +} + +func DisconnectNamedWifi(ctx context.Context, req DeleteWifiRequest) DeleteWifiResponse { + errorString := "" + command := fmt.Sprintf("nmcli con down '%s'", strings.TrimSpace(req.ConnectionName)) + _, _, err := runCommand(ctx, command) + if err != nil { + log.Warnf("failed to disconnect connection %s: %v", req.ConnectionName, err) + errorString = fmt.Sprintf("Failed to disconnect connection %s: %v", req.ConnectionName, err) + } + + if errorString != "" { + return DeleteWifiResponse{ + Msg: errorString, + Status: false, + } + } + + msg := "wifi connection disconnected successfully. " + status := true + + return DeleteWifiResponse{ + Msg: msg, + Status: status, + } +} + func WifiRemoveall(ctx context.Context) WifiRemoveallResponse { connections, err := getWifiConnections(ctx) if err != nil {