zubairhamed / canopus

CoAP Client/Server implementing RFC 7252 for the Go Language
Apache License 2.0
155 stars 41 forks source link

Canopus

GoDoc Build Status Coverage Status Go Report Card

Canopus is a client/server implementation of the Constrained Application Protocol (CoAP)

Updates

25.11.2016

I've added basic dTLS Support based on Julien Vermillard's implementation. Thanks Julien! It should now support PSK-based authentication. I've also gone ahead and refactored the APIs to make it that bit more Go idiomatic.

Building and running

  1. git submodule update --init --recursive
  2. cd openssl
  3. ./config && make
  4. You should then be able to run the examples in the /examples folder

Simple Example

    // Server
    // See /examples/simple/server/main.go
    server := canopus.NewServer()

    server.Get("/hello", func(req canopus.Request) canopus.Response {
        msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
        msg.SetStringPayload("Acknowledged: " + req.GetMessage().GetPayload().String())

        res := canopus.NewResponse(msg, nil)
        return res
    })

    server.ListenAndServe(":5683")

    // Client
    // See /examples/simple/client/main.go
    conn, err := canopus.Dial("localhost:5683")
    if err != nil {
        panic(err.Error())
    }

    req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID()).(*canopus.CoapRequest)
    req.SetStringPayload("Hello, canopus")
    req.SetRequestURI("/hello")

    resp, err := conn.Send(req)
    if err != nil {
        panic(err.Error())
    }

    fmt.Println("Got Response:" + resp.GetMessage().GetPayload().String())

Observe / Notify

    // Server
    // See /examples/observe/server/main.go
    server := canopus.NewServer()
    server.Get("/watch/this", func(req canopus.Request) canopus.Response {
        msg := canopus.NewMessageOfType(canopus.MessageAcknowledgment, req.GetMessage().GetMessageId(), canopus.NewPlainTextPayload("Acknowledged"))
        res := canopus.NewResponse(msg, nil)

        return res
    })

    ticker := time.NewTicker(3 * time.Second)
    go func() {
        for {
            select {
            case <-ticker.C:
                changeVal := strconv.Itoa(rand.Int())
                fmt.Println("[SERVER << ] Change of value -->", changeVal)

                server.NotifyChange("/watch/this", changeVal, false)
            }
        }
    }()

    server.OnObserve(func(resource string, msg canopus.Message) {
        fmt.Println("[SERVER << ] Observe Requested for " + resource)
    })

    server.ListenAndServe(":5683")

    // Client
    // See /examples/observe/client/main.go
    conn, err := canopus.Dial("localhost:5683")

    tok, err := conn.ObserveResource("/watch/this")
    if err != nil {
        panic(err.Error())
    }

    obsChannel := make(chan canopus.ObserveMessage)
    done := make(chan bool)
    go conn.Observe(obsChannel)

    notifyCount := 0
    for {
        select {
        case obsMsg, _ := <-obsChannel:
            if notifyCount == 5 {
                fmt.Println("[CLIENT >> ] Canceling observe after 5 notifications..")
                go conn.CancelObserveResource("watch/this", tok)
                go conn.StopObserve(obsChannel)
                return
            } else {
                notifyCount++
                // msg := obsMsg.Msg\
                resource := obsMsg.GetResource()
                val := obsMsg.GetValue()

                fmt.Println("[CLIENT >> ] Got Change Notification for resource and value: ", notifyCount, resource, val)
            }
        }
    }

dTLS with PSK

    // Server
    // See /examples/dtls/simple-psk/server/main.go
    server := canopus.NewServer()

    server.Get("/hello", func(req canopus.Request) canopus.Response {
        msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
        msg.SetStringPayload("Acknowledged: " + req.GetMessage().GetPayload().String())
        res := canopus.NewResponse(msg, nil)

        return res
    })

    server.HandlePSK(func(id string) []byte {
        return []byte("secretPSK")
    })

    server.ListenAndServeDTLS(":5684")

    // Client
    // See /examples/dtls/simple-psk/client/main.go
    conn, err := canopus.DialDTLS("localhost:5684", "canopus", "secretPSK")
    if err != nil {
        panic(err.Error())
    }

    req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID())
    req.SetStringPayload("Hello, canopus")
    req.SetRequestURI("/hello")

    resp, err := conn.Send(req)
    if err != nil {
        panic(err.Error())
    }

    fmt.Println("Got Response:" + resp.GetMessage().GetPayload().String())

CoAP-CoAP Proxy

    // Server
    // See /examples/proxy/coap/server/main.go
    server := canopus.NewServer()

    server.Get("/proxycall", func(req canopus.Request) canopus.Response {
        msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
        msg.SetStringPayload("Data from :5685 -- " + req.GetMessage().GetPayload().String())
        res := canopus.NewResponse(msg, nil)

        return res
    })
    server.ListenAndServe(":5685")

    // Proxy Server
    // See /examples/proxy/coap/proxy/main.go
    server := canopus.NewServer()
    server.ProxyOverCoap(true)

    server.Get("/proxycall", func(req canopus.Request) canopus.Response {
        canopus.PrintMessage(req.GetMessage())
        msg := canopus.ContentMessage(req.GetMessage().GetMessageId(), canopus.MessageAcknowledgment)
        msg.SetStringPayload("Acknowledged: " + req.GetMessage().GetPayload().String())
        res := canopus.NewResponse(msg, nil)

        return res
    })
    server.ListenAndServe(":5683")

    // Client
    // See /examples/proxy/coap/client/main.go
    conn, err := canopus.Dial("localhost:5683")
    if err != nil {
        panic(err.Error())
    }

    req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID())
    req.SetProxyURI("coap://localhost:5685/proxycall")

    resp, err := conn.Send(req)
    if err != nil {
        println("err", err)
    }
    canopus.PrintMessage(resp.GetMessage())

CoAP-HTTP Proxy

    // Server
    // See /examples/proxy/http/server/main.go
    server := canopus.NewServer()
    server.ProxyOverHttp(true)

    server.ListenAndServe(":5683")

    // Client
    // See /examples/proxy/http/client/main.go
    conn, err := canopus.Dial("localhost:5683")
    if err != nil {
        panic(err.Error())
    }

    req := canopus.NewRequest(canopus.MessageConfirmable, canopus.Get, canopus.GenerateMessageID())
    req.SetProxyURI("https://httpbin.org/get")

    resp, err := conn.Send(req)
    if err != nil {
        println("err", err)
    }
    canopus.PrintMessage(resp.GetMessage())