Skip to content

Commit 334e845

Browse files
committed
Cache cloud-api response for 24h to improve responsiveness
1 parent 79e6484 commit 334e845

File tree

2 files changed

+58
-29
lines changed

2 files changed

+58
-29
lines changed

Diff for: commands/board/list.go

+52-29
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"context"
2020
"encoding/json"
2121
"fmt"
22-
"io/ioutil"
22+
"io"
2323
"net/http"
2424
"regexp"
2525
"sort"
@@ -32,6 +32,7 @@ import (
3232
"github.com/arduino/arduino-cli/arduino/discovery"
3333
"github.com/arduino/arduino-cli/arduino/httpclient"
3434
"github.com/arduino/arduino-cli/commands"
35+
"github.com/arduino/arduino-cli/inventory"
3536
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
3637
"github.com/pkg/errors"
3738
"github.com/sirupsen/logrus"
@@ -59,52 +60,74 @@ func apiByVidPid(vid, pid string) ([]*rpc.BoardListItem, error) {
5960
return nil, errors.Errorf(tr("Invalid pid value: '%s'"), pid)
6061
}
6162

62-
url := fmt.Sprintf("%s/%s/%s", vidPidURL, vid, pid)
63-
retVal := []*rpc.BoardListItem{}
64-
req, _ := http.NewRequest("GET", url, nil)
65-
req.Header.Set("Content-Type", "application/json")
63+
var resp []byte
64+
cacheKey := fmt.Sprintf("cache.builder-api.v3/boards/byvid/pid/%s/%s", vid, pid)
65+
if cachedResp := inventory.Store.GetString(cacheKey + ".data"); cachedResp != "" {
66+
ts := inventory.Store.GetInt64(cacheKey + ".ts")
67+
if time.Now().Unix()-ts < 24*60*60 { // 24 hr timeout
68+
if cachedResp == "ErrNotFound" {
69+
return nil, ErrNotFound
70+
}
71+
resp = []byte(cachedResp)
72+
}
73+
}
6674

67-
// TODO: use proxy if set
75+
if resp == nil {
76+
url := fmt.Sprintf("%s/%s/%s", vidPidURL, vid, pid)
77+
req, _ := http.NewRequest("GET", url, nil)
78+
req.Header.Set("Content-Type", "application/json")
6879

69-
httpClient, err := httpclient.New()
80+
// TODO: use proxy if set
7081

71-
if err != nil {
72-
return nil, errors.Wrap(err, tr("failed to initialize http client"))
73-
}
82+
httpClient, err := httpclient.New()
7483

75-
if res, err := httpClient.Do(req); err == nil {
84+
if err != nil {
85+
return nil, errors.Wrap(err, tr("failed to initialize http client"))
86+
}
87+
88+
res, err := httpClient.Do(req)
89+
if err != nil {
90+
return nil, errors.Wrap(err, tr("error querying Arduino Cloud Api"))
91+
}
7692
if res.StatusCode >= 400 {
7793
if res.StatusCode == 404 {
94+
inventory.Store.Set(cacheKey+".data", "ErrNotFound")
95+
inventory.Store.Set(cacheKey+".ts", time.Now().Unix())
96+
inventory.WriteStore()
7897
return nil, ErrNotFound
7998
}
8099
return nil, errors.Errorf(tr("the server responded with status %s"), res.Status)
81100
}
82101

83-
body, _ := ioutil.ReadAll(res.Body)
84-
res.Body.Close()
85-
86-
var dat map[string]interface{}
87-
err = json.Unmarshal(body, &dat)
102+
resp, err = io.ReadAll(res.Body)
88103
if err != nil {
89-
return nil, errors.Wrap(err, tr("error processing response from server"))
104+
return nil, err
105+
}
106+
if err := res.Body.Close(); err != nil {
107+
return nil, err
90108
}
91109

92-
name, nameFound := dat["name"].(string)
93-
fqbn, fbqnFound := dat["fqbn"].(string)
110+
inventory.Store.Set(cacheKey+".data", string(resp))
111+
inventory.Store.Set(cacheKey+".ts", time.Now().Unix())
112+
inventory.WriteStore()
113+
}
94114

95-
if !nameFound || !fbqnFound {
96-
return nil, errors.New(tr("wrong format in server response"))
97-
}
115+
var dat map[string]interface{}
116+
if err := json.Unmarshal(resp, &dat); err != nil {
117+
return nil, errors.Wrap(err, tr("error processing response from server"))
118+
}
119+
name, nameFound := dat["name"].(string)
120+
fqbn, fbqnFound := dat["fqbn"].(string)
121+
if !nameFound || !fbqnFound {
122+
return nil, errors.New(tr("wrong format in server response"))
123+
}
98124

99-
retVal = append(retVal, &rpc.BoardListItem{
125+
return []*rpc.BoardListItem{
126+
{
100127
Name: name,
101128
Fqbn: fqbn,
102-
})
103-
} else {
104-
return nil, errors.Wrap(err, tr("error querying Arduino Cloud Api"))
105-
}
106-
107-
return retVal, nil
129+
},
130+
}, nil
108131
}
109132

110133
func identifyViaCloudAPI(port *discovery.Port) ([]*rpc.BoardListItem, error) {

Diff for: inventory/inventory.go

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020
"os"
2121
"path/filepath"
22+
"sync"
2223

2324
"github.com/arduino/arduino-cli/i18n"
2425
"github.com/gofrs/uuid"
@@ -77,9 +78,14 @@ func generateInstallationData() error {
7778
return nil
7879
}
7980

81+
var writeStoreMux sync.Mutex
82+
8083
// WriteStore writes the current information from Store to configFilePath.
8184
// Returns err if it fails.
8285
func WriteStore() error {
86+
writeStoreMux.Lock()
87+
defer writeStoreMux.Unlock()
88+
8389
configPath := filepath.Dir(configFilePath)
8490

8591
// Create config dir if not present,

0 commit comments

Comments
 (0)