Skip to content

Commit b7841ed

Browse files
author
dusanb
committed
Refactor CoAP CLI tool
Change underlying lib and simplify code and options Signed-off-by: dusanb <borovcanindusan1@gmail.com.com>
1 parent de3784b commit b7841ed

File tree

757 files changed

+213601
-1284
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

757 files changed

+213601
-1284
lines changed

README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,26 @@ Simple CoAP cli client written in Go.
33

44

55
## Usage
6-
Pre-built binary can be found here: https://github.com/mainflux/coap-cli/releases/tag/v0.1.0.
6+
Pre-built binary can be found here: https://github.com/mainflux/coap-cli/releases/tag/v0.2.0.
77
When running, please provide following format:
88
`coap-cli` followed by method code (`get`, `put`, `post`, `delete`) and CoAP URL. After that, you can pass following flags:
99

10-
| Flag | Description | Default value |
11-
|-------|--------------------------------|----------------------------------------|
12-
| ACK | Acknowledgement | false |
13-
| C | Confirmable | false |
14-
| NC | Non-Confirmable | false |
15-
| O | Observe | false |
16-
| d | Data to be sent in POST or PUT | "" |
17-
| id | Message ID | 0 |
18-
| token | Token | Byte array of empty string: [49 50 51] |
10+
| Flag | Description | Default value |
11+
| ---- | ---------------------------------------------- | ------------- |
12+
| o | Observe option - only valid with Get request | false |
13+
| auth | Auth option sent as URI Query | "" |
14+
| h | Host | "localhost" |
15+
| p | port | "5683" |
16+
| d | Data to be sent in POST or PUT | "" |
17+
| cf | Content format | 50 - JSON |
1918
# Examples:
2019

2120
```bash
22-
coap-cli get coap://localhost/channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic\?authorization=1e1017e6-dee7-45b4-8a13-00e6afeb66eb -O
21+
coap-cli get channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth=1e1017e6-dee7-45b4-8a13-00e6afeb66eb -o
2322
```
2423
```bash
25-
coap-cli post coap://localhost/channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic\?authorization=1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world"
24+
coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth=1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world"
25+
```
26+
```bash
27+
coap-cli post channels/0bb5ba61-a66e-4972-bab6-26f19962678f/messages/subtopic -auth=1e1017e6-dee7-45b4-8a13-00e6afeb66eb -d "hello world" -h 0.0.0.0 -p 1234
2628
```

cmd/main.go

Lines changed: 49 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
package main
22

33
import (
4+
"context"
45
"errors"
56
"flag"
7+
"fmt"
68
"log"
7-
"net/url"
89
"os"
10+
"os/signal"
911
"strings"
12+
"syscall"
1013

11-
gocoap "github.com/dustin/go-coap"
1214
coap "github.com/mainflux/coap-cli/coap"
15+
"github.com/plgd-dev/go-coap/v2/message"
16+
coapmsg "github.com/plgd-dev/go-coap/v2/message"
17+
"github.com/plgd-dev/go-coap/v2/message/codes"
18+
"github.com/plgd-dev/go-coap/v2/udp/message/pool"
1319
)
1420

1521
const (
@@ -19,48 +25,23 @@ const (
1925
delete = "DELETE"
2026
)
2127

22-
func parseCode(code string) (gocoap.COAPCode, error) {
28+
func parseCode(code string) (codes.Code, error) {
2329
switch code {
2430
case get:
25-
return gocoap.GET, nil
31+
return codes.GET, nil
2632
case put:
27-
return gocoap.PUT, nil
33+
return codes.PUT, nil
2834
case post:
29-
return gocoap.POST, nil
35+
return codes.POST, nil
3036
case delete:
31-
return gocoap.DELETE, nil
37+
return codes.DELETE, nil
3238
}
3339
return 0, errors.New("Message can be GET, POST, PUT or DELETE")
3440
}
3541

36-
func checkType(c, n, a, r *bool) (gocoap.COAPType, error) {
37-
arr := []bool{*c, *n, *a, *r}
38-
var counter int
39-
for _, v := range arr {
40-
if v {
41-
counter++
42-
}
43-
}
44-
if counter > 1 {
45-
return 0, errors.New("invalid message type")
46-
}
47-
switch {
48-
case *c:
49-
return gocoap.Confirmable, nil
50-
case *n:
51-
return gocoap.NonConfirmable, nil
52-
case *a:
53-
return gocoap.Acknowledgement, nil
54-
case *r:
55-
return gocoap.Reset, nil
56-
}
57-
return gocoap.Confirmable, nil
58-
}
59-
60-
func printMsg(m *gocoap.Message) {
42+
func printMsg(m *pool.Message) {
6143
if m != nil {
62-
log.Printf("\nMESSAGE:\nType: %d\nCode: %s\nMessageID: %d\nToken: %s\nPayload: %s\n",
63-
m.Type, m.Code.String(), m.MessageID, m.Token, m.Payload)
44+
log.Printf("\nMESSAGE:\n %v", m)
6445
}
6546
}
6647

@@ -70,85 +51,56 @@ func main() {
7051
}
7152
code, err := parseCode(strings.ToUpper(os.Args[1]))
7253
if err != nil {
73-
log.Fatal("ERROR: ", err)
54+
log.Fatal("error: ", err)
7455
}
7556
if len(os.Args) < 3 {
7657
log.Fatal("Please enter valid CoAP URL")
7758
}
78-
addr := os.Args[2]
59+
path := os.Args[2]
7960
os.Args = os.Args[2:]
8061

81-
c := flag.Bool("C", false, "Confirmable")
82-
n := flag.Bool("NC", false, "Non-confirmable")
83-
a := flag.Bool("ACK", false, "Acknowledgement")
84-
r := flag.Bool("RST", false, "Reset")
85-
o := flag.Bool("O", false, "Observe")
62+
o := flag.Bool("o", false, "Observe")
63+
h := flag.String("h", "localhost", "Host")
64+
p := flag.String("p", "5683", "Port")
8665
// Default type is JSON.
87-
cf := flag.Int("CF", 50, "Content format")
66+
cf := flag.Int("q", 50, "Content format")
8867
d := flag.String("d", "", "Message data")
89-
id := flag.Uint("id", 0, "Message ID")
90-
token := flag.String("token", "", "Message data")
68+
a := flag.String("auth", "", "Auth token")
9169

9270
flag.Parse()
9371

94-
t, err := checkType(c, n, a, r)
95-
if err != nil {
96-
log.Fatal("ERR TYPE: ", err)
97-
}
98-
address, err := url.Parse(addr)
72+
fmt.Println(*h + ":" + *p)
73+
client, err := coap.New(*h + ":" + *p)
9974
if err != nil {
100-
log.Fatal("ERR PARSING ADDR:", err)
75+
log.Fatal("Error creating client: ", err)
10176
}
102-
client, err := coap.New(address)
103-
if err != nil {
104-
log.Fatal("ERROR CREATING CLIENT: ", err)
77+
var opts coapmsg.Options
78+
if a != nil {
79+
opts = append(opts, coapmsg.Option{ID: coapmsg.URIQuery, Value: []byte(fmt.Sprintf("auth=%s", *a))})
10580
}
10681

107-
opts := coap.ParseOptions(address)
108-
if *o {
109-
opts = append(opts, coap.Option{
110-
ID: gocoap.Observe,
111-
Value: 0,
112-
})
113-
}
114-
if *cf != 0 {
115-
opts = append(opts, coap.Option{
116-
ID: gocoap.ContentFormat,
117-
Value: *cf,
118-
})
119-
}
82+
if o == nil {
83+
pld := strings.NewReader(*d)
12084

121-
res, err := client.Send(t, code, uint16(*id), []byte(*token), []byte(*d), opts)
122-
if err != nil {
123-
log.Fatal("ERROR: ", err)
124-
}
125-
printMsg(res)
126-
if res == nil {
127-
os.Exit(0)
128-
}
129-
switch res.Code {
130-
case gocoap.Forbidden, gocoap.BadRequest, gocoap.InternalServerError, gocoap.NotFound:
131-
log.Fatalf("Response code: %s", res.Code)
132-
}
133-
if *o {
134-
if code != gocoap.GET {
135-
log.Fatalln("Can observe non GET requests.")
136-
}
137-
msgs := make(chan *gocoap.Message)
138-
go func() {
139-
for {
140-
msg, err := client.Receive()
141-
if err != nil {
142-
log.Fatal("ERROR RECEIVING: ", err)
143-
}
144-
msgs <- msg
145-
}
146-
}()
147-
for {
148-
select {
149-
case m := <-msgs:
150-
printMsg(m)
151-
}
85+
res, err := client.Send(path, code, message.MediaType(*cf), pld, opts...)
86+
if err != nil {
87+
log.Fatal("Error sending message: ", err)
15288
}
89+
printMsg(res)
90+
return
15391
}
92+
obs, err := client.Receive(path, opts...)
93+
if err != nil {
94+
log.Fatal("Error observing resource: ", err)
95+
}
96+
errs := make(chan error, 2)
97+
go func() {
98+
c := make(chan os.Signal)
99+
signal.Notify(c, syscall.SIGINT)
100+
errs <- fmt.Errorf("%s", <-c)
101+
}()
102+
103+
err = <-errs
104+
obs.Cancel(context.Background())
105+
log.Fatal("Observation terminated: ", err)
154106
}

coap/client.go

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,67 @@
11
package coap
22

33
import (
4-
"net/url"
4+
"context"
5+
"errors"
6+
"fmt"
7+
"io"
8+
"log"
9+
"time"
510

6-
gocoap "github.com/dustin/go-coap"
11+
"github.com/plgd-dev/go-coap/v2/message"
12+
"github.com/plgd-dev/go-coap/v2/message/codes"
13+
"github.com/plgd-dev/go-coap/v2/udp"
14+
"github.com/plgd-dev/go-coap/v2/udp/client"
15+
"github.com/plgd-dev/go-coap/v2/udp/message/pool"
716
)
817

918
// Client represents CoAP client.
1019
type Client struct {
11-
conn *conn
20+
conn *client.ClientConn
1221
}
1322

1423
// New returns new CoAP client connecting it to the server.
15-
func New(addr *url.URL) (Client, error) {
16-
address, err := parseAddr(addr)
24+
func New(addr string) (Client, error) {
25+
c, err := udp.Dial(addr)
1726
if err != nil {
18-
return Client{}, err
19-
}
20-
c, err := dial(address)
21-
if err != nil {
22-
return Client{}, err
27+
log.Fatalf("Error dialing: %v", err)
2328
}
29+
2430
return Client{conn: c}, nil
2531
}
2632

2733
// Send send a message.
28-
func (c Client) Send(msgType gocoap.COAPType, msgCode gocoap.COAPCode, msgID uint16, token, payload []byte, opts []Option) (*gocoap.Message, error) {
29-
msg := gocoap.Message{
30-
Type: msgType,
31-
Code: msgCode,
32-
MessageID: msgID,
33-
Token: token,
34-
Payload: payload,
35-
}
34+
func (c Client) Send(path string, msgCode codes.Code, cf message.MediaType, payload io.ReadSeeker, opts ...message.Option) (*pool.Message, error) {
35+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
36+
defer cancel()
3637

37-
for _, o := range opts {
38-
msg.SetOption(o.ID, o.Value)
38+
switch msgCode {
39+
case codes.GET:
40+
return c.conn.Get(ctx, path, opts...)
41+
case codes.POST:
42+
return c.conn.Post(ctx, path, cf, payload, opts...)
43+
case codes.PUT:
44+
return c.conn.Put(ctx, path, cf, payload, opts...)
45+
case codes.DELETE:
46+
return c.conn.Delete(ctx, path, opts...)
3947
}
40-
return c.conn.send(msg)
48+
return nil, errors.New("Invalid message code")
4149
}
4250

4351
// Receive receives a message.
44-
func (c Client) Receive() (*gocoap.Message, error) {
45-
return c.conn.receive()
52+
func (c Client) Receive(path string, opts ...message.Option) (*client.Observation, error) {
53+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
54+
defer cancel()
55+
56+
return c.conn.Observe(ctx, path, func(res *pool.Message) {
57+
fmt.Printf("\nRECEIVED OBSERVE: %v\n", res)
58+
body, err := res.ReadBody()
59+
if err != nil {
60+
fmt.Println("Error reading message body: ", err)
61+
return
62+
}
63+
if len(body) > 0 {
64+
fmt.Println("Payload: ", string(body))
65+
}
66+
}, opts...)
4667
}

coap/options.go

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)