A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/arduino/arduino-cli/commit/ed88bd8d91cc3a09767177b00f93a963e4898a28 below:

Added `BoardIdentify` gRPC call. (#2794) · arduino/arduino-cli@ed88bd8 · GitHub

1 +

// This file is part of arduino-cli.

2 +

//

3 +

// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)

4 +

//

5 +

// This software is released under the GNU General Public License version 3,

6 +

// which covers the main part of arduino-cli.

7 +

// The terms of this license can be found at:

8 +

// https://www.gnu.org/licenses/gpl-3.0.en.html

9 +

//

10 +

// You can be released from the requirements of the above licenses by purchasing

11 +

// a commercial license. Buying such a license is mandatory if you want to

12 +

// modify or otherwise use the software for commercial activities involving the

13 +

// Arduino software without disclosing the source code of your own applications.

14 +

// To purchase a commercial license, send an email to license@arduino.cc.

15 + 16 +

package commands

17 + 18 +

import (

19 +

"context"

20 +

"encoding/json"

21 +

"errors"

22 +

"fmt"

23 +

"io"

24 +

"net/http"

25 +

"regexp"

26 +

"sort"

27 +

"strings"

28 +

"time"

29 + 30 +

"github.com/arduino/arduino-cli/commands/cmderrors"

31 +

"github.com/arduino/arduino-cli/commands/internal/instances"

32 +

"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"

33 +

"github.com/arduino/arduino-cli/internal/cli/configuration"

34 +

"github.com/arduino/arduino-cli/internal/i18n"

35 +

"github.com/arduino/arduino-cli/internal/inventory"

36 +

"github.com/arduino/arduino-cli/pkg/fqbn"

37 +

rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"

38 +

"github.com/arduino/go-properties-orderedmap"

39 +

"github.com/sirupsen/logrus"

40 +

)

41 + 42 +

// BoardIdentify identifies the board based on the provided properties

43 +

func (s *arduinoCoreServerImpl) BoardIdentify(ctx context.Context, req *rpc.BoardIdentifyRequest) (*rpc.BoardIdentifyResponse, error) {

44 +

pme, release, err := instances.GetPackageManagerExplorer(req.GetInstance())

45 +

if err != nil {

46 +

return nil, err

47 +

}

48 +

defer release()

49 + 50 +

props := properties.NewFromHashmap(req.GetProperties())

51 +

res, err := identify(pme, props, s.settings, !req.GetUseCloudApiForUnknownBoardDetection())

52 +

if err != nil {

53 +

return nil, err

54 +

}

55 +

return &rpc.BoardIdentifyResponse{

56 +

Boards: res,

57 +

}, nil

58 +

}

59 + 60 +

// identify returns a list of boards checking first the installed platforms or the Cloud API

61 +

func identify(pme *packagemanager.Explorer, properties *properties.Map, settings *configuration.Settings, skipCloudAPI bool) ([]*rpc.BoardListItem, error) {

62 +

if properties == nil {

63 +

return nil, nil

64 +

}

65 + 66 +

// first query installed cores through the Package Manager

67 +

boards := []*rpc.BoardListItem{}

68 +

logrus.Debug("Querying installed cores for board identification...")

69 +

for _, board := range pme.IdentifyBoard(properties) {

70 +

fqbn, err := fqbn.Parse(board.FQBN())

71 +

if err != nil {

72 +

return nil, &cmderrors.InvalidFQBNError{Cause: err}

73 +

}

74 +

fqbn.Configs = board.IdentifyBoardConfiguration(properties)

75 + 76 +

// We need the Platform maintaner for sorting so we set it here

77 +

platform := &rpc.Platform{

78 +

Metadata: &rpc.PlatformMetadata{

79 +

Maintainer: board.PlatformRelease.Platform.Package.Maintainer,

80 +

},

81 +

}

82 +

boards = append(boards, &rpc.BoardListItem{

83 +

Name: board.Name(),

84 +

Fqbn: fqbn.String(),

85 +

IsHidden: board.IsHidden(),

86 +

Platform: platform,

87 +

})

88 +

}

89 + 90 +

// if installed cores didn't recognize the board, try querying

91 +

// the builder API if the board is a USB device port

92 +

if len(boards) == 0 && !skipCloudAPI && !settings.SkipCloudApiForBoardDetection() {

93 +

items, err := identifyViaCloudAPI(properties, settings)

94 +

if err != nil {

95 +

// this is bad, but keep going

96 +

logrus.WithError(err).Debug("Error querying builder API")

97 +

}

98 +

boards = items

99 +

}

100 + 101 +

// Sort by FQBN alphabetically

102 +

sort.Slice(boards, func(i, j int) bool {

103 +

return strings.ToLower(boards[i].GetFqbn()) < strings.ToLower(boards[j].GetFqbn())

104 +

})

105 + 106 +

// Put Arduino boards before others in case there are non Arduino boards with identical VID:PID combination

107 +

sort.SliceStable(boards, func(i, j int) bool {

108 +

if boards[i].GetPlatform().GetMetadata().GetMaintainer() == "Arduino" && boards[j].GetPlatform().GetMetadata().GetMaintainer() != "Arduino" {

109 +

return true

110 +

}

111 +

return false

112 +

})

113 + 114 +

// We need the Board's Platform only for sorting but it shouldn't be present in the output

115 +

for _, board := range boards {

116 +

board.Platform = nil

117 +

}

118 + 119 +

return boards, nil

120 +

}

121 + 122 +

func identifyViaCloudAPI(props *properties.Map, settings *configuration.Settings) ([]*rpc.BoardListItem, error) {

123 +

// If the port is not USB do not try identification via cloud

124 +

if !props.ContainsKey("vid") || !props.ContainsKey("pid") {

125 +

return nil, nil

126 +

}

127 + 128 +

logrus.Debug("Querying builder API for board identification...")

129 +

return cachedAPIByVidPid(props.Get("vid"), props.Get("pid"), settings)

130 +

}

131 + 132 +

var (

133 +

vidPidURL = "https://builder.arduino.cc/v3/boards/byVidPid"

134 +

validVidPid = regexp.MustCompile(`0[xX][a-fA-F\d]{4}`)

135 +

)

136 + 137 +

func cachedAPIByVidPid(vid, pid string, settings *configuration.Settings) ([]*rpc.BoardListItem, error) {

138 +

var resp []*rpc.BoardListItem

139 + 140 +

cacheKey := fmt.Sprintf("cache.builder-api.v3/boards/byvid/pid/%s/%s", vid, pid)

141 +

if cachedResp := inventory.Store.GetString(cacheKey + ".data"); cachedResp != "" {

142 +

ts := inventory.Store.GetTime(cacheKey + ".ts")

143 +

if time.Since(ts) < time.Hour*24 {

144 +

// Use cached response

145 +

if err := json.Unmarshal([]byte(cachedResp), &resp); err == nil {

146 +

return resp, nil

147 +

}

148 +

}

149 +

}

150 + 151 +

resp, err := apiByVidPid(vid, pid, settings) // Perform API requrest

152 + 153 +

if err == nil {

154 +

if cachedResp, err := json.Marshal(resp); err == nil {

155 +

inventory.Store.Set(cacheKey+".data", string(cachedResp))

156 +

inventory.Store.Set(cacheKey+".ts", time.Now())

157 +

inventory.WriteStore()

158 +

}

159 +

}

160 +

return resp, err

161 +

}

162 + 163 +

func apiByVidPid(vid, pid string, settings *configuration.Settings) ([]*rpc.BoardListItem, error) {

164 +

// ensure vid and pid are valid before hitting the API

165 +

if !validVidPid.MatchString(vid) {

166 +

return nil, errors.New(i18n.Tr("Invalid vid value: '%s'", vid))

167 +

}

168 +

if !validVidPid.MatchString(pid) {

169 +

return nil, errors.New(i18n.Tr("Invalid pid value: '%s'", pid))

170 +

}

171 + 172 +

url := fmt.Sprintf("%s/%s/%s", vidPidURL, vid, pid)

173 +

req, _ := http.NewRequest("GET", url, nil)

174 +

req.Header.Set("Content-Type", "application/json")

175 + 176 +

httpClient, err := settings.NewHttpClient()

177 +

if err != nil {

178 +

return nil, fmt.Errorf("%s: %w", i18n.Tr("failed to initialize http client"), err)

179 +

}

180 + 181 +

res, err := httpClient.Do(req)

182 +

if err != nil {

183 +

return nil, fmt.Errorf("%s: %w", i18n.Tr("error querying Arduino Cloud Api"), err)

184 +

}

185 +

if res.StatusCode == 404 {

186 +

// This is not an error, it just means that the board is not recognized

187 +

return nil, nil

188 +

}

189 +

if res.StatusCode >= 400 {

190 +

return nil, errors.New(i18n.Tr("the server responded with status %s", res.Status))

191 +

}

192 + 193 +

resp, err := io.ReadAll(res.Body)

194 +

if err != nil {

195 +

return nil, err

196 +

}

197 +

if err := res.Body.Close(); err != nil {

198 +

return nil, err

199 +

}

200 + 201 +

var dat map[string]interface{}

202 +

if err := json.Unmarshal(resp, &dat); err != nil {

203 +

return nil, fmt.Errorf("%s: %w", i18n.Tr("error processing response from server"), err)

204 +

}

205 +

name, nameFound := dat["name"].(string)

206 +

fqbn, fbqnFound := dat["fqbn"].(string)

207 +

if !nameFound || !fbqnFound {

208 +

return nil, errors.New(i18n.Tr("wrong format in server response"))

209 +

}

210 + 211 +

return []*rpc.BoardListItem{

212 +

{

213 +

Name: name,

214 +

Fqbn: fqbn,

215 +

},

216 +

}, nil

217 +

}


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4