From 8d112d61278a9abb29d9eadb4d6319c0f5810e41 Mon Sep 17 00:00:00 2001 From: ehsan shariati Date: Fri, 16 Feb 2024 15:00:42 -0500 Subject: [PATCH] Get folder size (#215) * added getfoldersize * minor bugs * Update blox.go --- blockchain/blockchain.go | 5 ++- blockchain/blox.go | 72 ++++++++++++++++++++++++++++++++++++++ blockchain/interface.go | 4 +++ mobile/blockchain.go | 7 ++++ wap/pkg/wifi/properties.go | 27 ++++++++++++++ 5 files changed, 114 insertions(+), 1 deletion(-) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 971df97..e3e3285 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -399,6 +399,9 @@ func (bl *FxBlockchain) serve(w http.ResponseWriter, r *http.Request) { actionFetchContainerLogs: func(from peer.ID, w http.ResponseWriter, r *http.Request) { bl.handleFetchContainerLogs(r.Context(), from, w, r) }, + actionGetFolderSize: func(from peer.ID, w http.ResponseWriter, r *http.Request) { + bl.handleGetFolderSize(r.Context(), from, w, r) + }, } // Look up the function in the map and call it @@ -674,7 +677,7 @@ func (bl *FxBlockchain) authorized(pid peer.ID, action string) bool { return true } switch action { - case actionBloxFreeSpace, actionAccountFund, actionAssetsBalance, actionFetchContainerLogs, actionEraseBlData, actionWifiRemoveall, actionReboot, actionPartition, actionDeleteWifi, actionDisconnectWifi, actionDeleteFulaConfig, actionGetAccount, actionSeeded, actionAccountExists, actionPoolCreate, actionPoolJoin, actionPoolCancelJoin, actionPoolRequests, actionPoolList, actionPoolVote, actionPoolLeave, actionManifestUpload, actionManifestStore, actionManifestAvailable, actionManifestRemove, actionManifestRemoveStorer, actionManifestRemoveStored: + case actionBloxFreeSpace, actionAccountFund, actionAssetsBalance, actionGetFolderSize, actionFetchContainerLogs, actionEraseBlData, actionWifiRemoveall, actionReboot, actionPartition, actionDeleteWifi, actionDisconnectWifi, actionDeleteFulaConfig, actionGetAccount, 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 65814f0..4954937 100644 --- a/blockchain/blox.go +++ b/blockchain/blox.go @@ -245,6 +245,43 @@ func (bl *FxBlockchain) FetchContainerLogs(ctx context.Context, to peer.ID, r wi } } +func (bl *FxBlockchain) GetFolderSize(ctx context.Context, to peer.ID, r wifi.GetFolderSizeRequest) ([]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/"+actionGetFolderSize, &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) DeleteWifi(ctx context.Context, to peer.ID, r wifi.DeleteWifiRequest) ([]byte, error) { if bl.allowTransientConnection { @@ -356,3 +393,38 @@ func (bl *FxBlockchain) handleFetchContainerLogs(ctx context.Context, from peer. } } + +func (bl *FxBlockchain) handleGetFolderSize(ctx context.Context, from peer.ID, w http.ResponseWriter, r *http.Request) { + log := log.With("action", actionGetFolderSize, "from", from) + + // Parse the JSON body of the request into the DeleteWifiRequest struct + var req wifi.GetFolderSizeRequest + 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("handleGetFolderSize received", "req", req) + + out := wifi.GetFolderSizeResponse{ + FolderPath: "", + SizeInBytes: "", + } + res, err := wifi.GetFolderSize(ctx, req) + if err != nil { + out = wifi.GetFolderSizeResponse{ + FolderPath: "", + SizeInBytes: "", + } + } else { + out = res + } + log.Debugw("handleGetFolderSize response", "out", out) + w.WriteHeader(http.StatusAccepted) + 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 + } + +} diff --git a/blockchain/interface.go b/blockchain/interface.go index dedb92f..1ce826e 100644 --- a/blockchain/interface.go +++ b/blockchain/interface.go @@ -45,6 +45,7 @@ const ( actionDisconnectWifi = "disconnect-wifi" actionGetAccount = "get-account" actionFetchContainerLogs = "fetch-container-logs" + actionGetFolderSize = "get-folder-size" ) type LinkWithLimit struct { @@ -356,6 +357,7 @@ type Blockchain interface { DeleteFulaConfig(context.Context, peer.ID) ([]byte, error) GetAccount(context.Context, peer.ID) ([]byte, error) FetchContainerLogs(context.Context, peer.ID, wifi.FetchContainerLogsRequest) ([]byte, error) + GetFolderSize(context.Context, peer.ID, wifi.GetFolderSizeRequest) ([]byte, error) } var requestTypes = map[string]reflect.Type{ @@ -393,6 +395,7 @@ var requestTypes = map[string]reflect.Type{ actionDisconnectWifi: reflect.TypeOf(wifi.DeleteWifiRequest{}), actionGetAccount: reflect.TypeOf(GetAccountRequest{}), actionFetchContainerLogs: reflect.TypeOf(wifi.FetchContainerLogsRequest{}), + actionGetFolderSize: reflect.TypeOf(wifi.GetFolderSizeRequest{}), } var responseTypes = map[string]reflect.Type{ @@ -430,4 +433,5 @@ var responseTypes = map[string]reflect.Type{ actionDisconnectWifi: reflect.TypeOf(wifi.DeleteWifiResponse{}), actionGetAccount: reflect.TypeOf(GetAccountResponse{}), actionFetchContainerLogs: reflect.TypeOf(wifi.FetchContainerLogsResponse{}), + actionGetFolderSize: reflect.TypeOf(wifi.GetFolderSizeResponse{}), } diff --git a/mobile/blockchain.go b/mobile/blockchain.go index 476c7c8..9012f4b 100644 --- a/mobile/blockchain.go +++ b/mobile/blockchain.go @@ -196,3 +196,10 @@ func (c *Client) FetchContainerLogs(ContainerName string, TailCount string) ([]b ctx := context.TODO() return c.bl.FetchContainerLogs(ctx, c.bloxPid, wifi.FetchContainerLogsRequest{ContainerName: ContainerName, TailCount: TailCount}) } + +// GetAccount requests blox at Config.BloxAddr to get the balance of the account. +// the addr must be a valid multiaddr that includes peer ID. +func (c *Client) GetFolderSize(folderPath string) ([]byte, error) { + ctx := context.TODO() + return c.bl.GetFolderSize(ctx, c.bloxPid, wifi.GetFolderSizeRequest{FolderPath: folderPath}) +} diff --git a/wap/pkg/wifi/properties.go b/wap/pkg/wifi/properties.go index 2e09169..9625930 100644 --- a/wap/pkg/wifi/properties.go +++ b/wap/pkg/wifi/properties.go @@ -30,6 +30,15 @@ type BloxFreeSpaceResponse struct { UsedPercentage float32 `json:"used_percentage"` } +type GetFolderSizeRequest struct { + FolderPath string `json:"folder_path"` +} + +type GetFolderSizeResponse struct { + FolderPath string `json:"folder_path"` + SizeInBytes string `json:"size"` +} + type FetchContainerLogsResponse struct { Status bool `json:"status"` Msg string `json:"msg"` @@ -111,6 +120,24 @@ func GenerateRandomString(length int) (string, error) { return base64.URLEncoding.EncodeToString(bytes), nil } +func GetFolderSize(ctx context.Context, req GetFolderSizeRequest) (GetFolderSizeResponse, error) { + cmd := fmt.Sprintf(`du -sb %s | cut -f1`, req.FolderPath) + out, err := exec.CommandContext(ctx, "sh", "-c", cmd).Output() + if err != nil { + return GetFolderSizeResponse{}, fmt.Errorf("error executing shell command: %v", err) + } + + sizeInBytes, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64) + if err != nil { + return GetFolderSizeResponse{}, fmt.Errorf("error parsing folder size: %v", err) + } + + return GetFolderSizeResponse{ + FolderPath: req.FolderPath, + SizeInBytes: fmt.Sprint(sizeInBytes), + }, nil +} + func GetBloxFreeSpace() (BloxFreeSpaceResponse, error) { cmd := `df -B1 2>/dev/null | grep -nE '/storage/(usb|sd[a-z]|nvme)' | awk '{sum2+=$2; sum3+=$3; sum4+=$4; sum5+=$5} END { print NR "," sum2 "," sum3 "," sum4 "," sum5}'` out, err := exec.Command("sh", "-c", cmd).Output()