client.go 7.4 KB

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