client.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. Copyright © 2021-2022 Ettore Di Giacinto <[email protected]>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package client
  14. import (
  15. "context"
  16. "encoding/base64"
  17. "encoding/json"
  18. "fmt"
  19. "io/ioutil"
  20. "net"
  21. "net/http"
  22. "strings"
  23. "time"
  24. "github.com/mudler/edgevpn/api"
  25. "github.com/mudler/edgevpn/pkg/blockchain"
  26. "github.com/mudler/edgevpn/pkg/types"
  27. )
  28. type (
  29. Client struct {
  30. host string
  31. httpClient *http.Client
  32. }
  33. )
  34. func WithHost(host string) func(c *Client) error {
  35. return func(c *Client) error {
  36. c.host = host
  37. if strings.HasPrefix(host, "unix://") {
  38. socket := strings.ReplaceAll(host, "unix://", "")
  39. c.host = "http://unix"
  40. c.httpClient = &http.Client{
  41. Transport: &http.Transport{
  42. DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
  43. return net.Dial("unix", socket)
  44. },
  45. },
  46. }
  47. }
  48. return nil
  49. }
  50. }
  51. func WithTimeout(d time.Duration) func(c *Client) error {
  52. return func(c *Client) error {
  53. c.httpClient.Timeout = d
  54. return nil
  55. }
  56. }
  57. func WithHTTPClient(cl *http.Client) func(c *Client) error {
  58. return func(c *Client) error {
  59. c.httpClient = cl
  60. return nil
  61. }
  62. }
  63. type Option func(c *Client) error
  64. func NewClient(o ...Option) *Client {
  65. c := &Client{
  66. httpClient: &http.Client{},
  67. }
  68. for _, oo := range o {
  69. oo(c)
  70. }
  71. return c
  72. }
  73. func (c *Client) do(method, endpoint string, params map[string]string) (*http.Response, error) {
  74. baseURL := fmt.Sprintf("%s%s", c.host, endpoint)
  75. req, err := http.NewRequest(method, baseURL, nil)
  76. if err != nil {
  77. return nil, err
  78. }
  79. req.Header.Add("Content-Type", "application/json")
  80. q := req.URL.Query()
  81. for key, val := range params {
  82. q.Set(key, val)
  83. }
  84. req.URL.RawQuery = q.Encode()
  85. return c.httpClient.Do(req)
  86. }
  87. // Get methods (Services, Users, Files, Ledger, Blockchain, Machines)
  88. func (c *Client) Services() (resp []types.Service, err error) {
  89. res, err := c.do(http.MethodGet, api.ServiceURL, nil)
  90. if err != nil {
  91. return
  92. }
  93. defer res.Body.Close()
  94. body, err := ioutil.ReadAll(res.Body)
  95. if err != nil {
  96. return resp, err
  97. }
  98. if err = json.Unmarshal(body, &resp); err != nil {
  99. return resp, err
  100. }
  101. return
  102. }
  103. func (c *Client) Files() (data []types.File, err error) {
  104. res, err := c.do(http.MethodGet, api.FileURL, nil)
  105. if err != nil {
  106. return
  107. }
  108. defer res.Body.Close()
  109. body, err := ioutil.ReadAll(res.Body)
  110. if err != nil {
  111. return data, err
  112. }
  113. if err = json.Unmarshal(body, &data); err != nil {
  114. return data, err
  115. }
  116. return
  117. }
  118. func (c *Client) Users() (data []types.User, err error) {
  119. res, err := c.do(http.MethodGet, api.UsersURL, nil)
  120. if err != nil {
  121. return
  122. }
  123. defer res.Body.Close()
  124. body, err := ioutil.ReadAll(res.Body)
  125. if err != nil {
  126. return data, err
  127. }
  128. if err = json.Unmarshal(body, &data); err != nil {
  129. return data, err
  130. }
  131. return
  132. }
  133. func (c *Client) Ledger() (data map[string]map[string]blockchain.Data, err error) {
  134. res, err := c.do(http.MethodGet, api.LedgerURL, nil)
  135. if err != nil {
  136. return
  137. }
  138. defer res.Body.Close()
  139. body, err := ioutil.ReadAll(res.Body)
  140. if err != nil {
  141. return data, err
  142. }
  143. if err = json.Unmarshal(body, &data); err != nil {
  144. return data, err
  145. }
  146. return
  147. }
  148. func (c *Client) Summary() (data types.Summary, err error) {
  149. res, err := c.do(http.MethodGet, api.SummaryURL, nil)
  150. if err != nil {
  151. return
  152. }
  153. defer res.Body.Close()
  154. body, err := ioutil.ReadAll(res.Body)
  155. if err != nil {
  156. return data, err
  157. }
  158. if err = json.Unmarshal(body, &data); err != nil {
  159. return data, err
  160. }
  161. return
  162. }
  163. func (c *Client) Blockchain() (data blockchain.Block, err error) {
  164. res, err := c.do(http.MethodGet, api.BlockchainURL, nil)
  165. if err != nil {
  166. return
  167. }
  168. defer res.Body.Close()
  169. body, err := ioutil.ReadAll(res.Body)
  170. if err != nil {
  171. return data, err
  172. }
  173. if err = json.Unmarshal(body, &data); err != nil {
  174. return data, err
  175. }
  176. return
  177. }
  178. func (c *Client) Machines() (resp []types.Machine, err error) {
  179. res, err := c.do(http.MethodGet, api.MachineURL, nil)
  180. if err != nil {
  181. return
  182. }
  183. defer res.Body.Close()
  184. body, err := ioutil.ReadAll(res.Body)
  185. if err != nil {
  186. return resp, err
  187. }
  188. if err = json.Unmarshal(body, &resp); err != nil {
  189. return resp, err
  190. }
  191. return
  192. }
  193. func (c *Client) GetBucket(b string) (resp map[string]blockchain.Data, err error) {
  194. res, err := c.do(http.MethodGet, fmt.Sprintf("%s/%s", api.LedgerURL, b), nil)
  195. if err != nil {
  196. return
  197. }
  198. defer res.Body.Close()
  199. body, err := ioutil.ReadAll(res.Body)
  200. if err != nil {
  201. return resp, err
  202. }
  203. if err = json.Unmarshal(body, &resp); err != nil {
  204. return resp, err
  205. }
  206. return
  207. }
  208. func (c *Client) GetBucketKeys(b string) (resp []string, err error) {
  209. d, err := c.GetBucket(b)
  210. if err != nil {
  211. return resp, err
  212. }
  213. for k := range d {
  214. resp = append(resp, k)
  215. }
  216. return
  217. }
  218. func (c *Client) GetBuckets() (resp []string, err error) {
  219. d, err := c.Ledger()
  220. if err != nil {
  221. return resp, err
  222. }
  223. for k := range d {
  224. resp = append(resp, k)
  225. }
  226. return
  227. }
  228. func (c *Client) GetBucketKey(b, k string) (resp blockchain.Data, err error) {
  229. res, err := c.do(http.MethodGet, fmt.Sprintf("%s/%s/%s", api.LedgerURL, b, k), nil)
  230. if err != nil {
  231. return
  232. }
  233. defer res.Body.Close()
  234. body, err := ioutil.ReadAll(res.Body)
  235. if err != nil {
  236. return resp, err
  237. }
  238. var r string
  239. if err = json.Unmarshal(body, &r); err != nil {
  240. return resp, err
  241. }
  242. if err = json.Unmarshal([]byte(r), &r); err != nil {
  243. return resp, err
  244. }
  245. d, err := base64.URLEncoding.DecodeString(r)
  246. if err != nil {
  247. return resp, err
  248. }
  249. resp = blockchain.Data(string(d))
  250. return
  251. }
  252. func (c *Client) Put(b, k string, v interface{}) (err error) {
  253. s := struct{ State string }{}
  254. dat, err := json.Marshal(v)
  255. if err != nil {
  256. return
  257. }
  258. d := base64.URLEncoding.EncodeToString(dat)
  259. res, err := c.do(http.MethodPut, fmt.Sprintf("%s/%s/%s/%s", api.LedgerURL, b, k, d), nil)
  260. if err != nil {
  261. return
  262. }
  263. defer res.Body.Close()
  264. body, err := ioutil.ReadAll(res.Body)
  265. if err != nil {
  266. return err
  267. }
  268. if err = json.Unmarshal(body, &s); err != nil {
  269. return err
  270. }
  271. if s.State != "Announcing" {
  272. return fmt.Errorf("unexpected state '%s'", s.State)
  273. }
  274. return
  275. }
  276. func (c *Client) Delete(b, k string) (err error) {
  277. s := struct{ State string }{}
  278. res, err := c.do(http.MethodDelete, fmt.Sprintf("%s/%s/%s", api.LedgerURL, b, k), nil)
  279. if err != nil {
  280. return
  281. }
  282. defer res.Body.Close()
  283. body, err := ioutil.ReadAll(res.Body)
  284. if err != nil {
  285. return err
  286. }
  287. if err = json.Unmarshal(body, &s); err != nil {
  288. return err
  289. }
  290. if s.State != "Announcing" {
  291. return fmt.Errorf("unexpected state '%s'", s.State)
  292. }
  293. return
  294. }
  295. func (c *Client) DeleteBucket(b string) (err error) {
  296. s := struct{ State string }{}
  297. res, err := c.do(http.MethodDelete, fmt.Sprintf("%s/%s", api.LedgerURL, b), nil)
  298. if err != nil {
  299. return
  300. }
  301. defer res.Body.Close()
  302. body, err := ioutil.ReadAll(res.Body)
  303. if err != nil {
  304. return err
  305. }
  306. if err = json.Unmarshal(body, &s); err != nil {
  307. return err
  308. }
  309. if s.State != "Announcing" {
  310. return fmt.Errorf("unexpected state '%s'", s.State)
  311. }
  312. return
  313. }