Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unable to find resouces by coap://[address]:port/.well-known/core #166

Open
BrukT opened this issue Sep 10, 2020 · 2 comments
Open

unable to find resouces by coap://[address]:port/.well-known/core #166

BrukT opened this issue Sep 10, 2020 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@BrukT
Copy link

BrukT commented Sep 10, 2020

I am using a custom coap browser to discover what resouces are registered under a given coap server. In another word, list the paths available just like the one comes when we enter this on a coap browser bar:
coap.me/.well-known/core
But the simple server code you provided is not replying the list of url extension. I looked inside the code but I couldn't find any information. For now, I have managed to return one path when requested at /.well-known/core by changing the sever code like below. For next, could you tell me if the discovery feature I want is implemented in the library? if yes, please give me an example on how I can use it. In addition, I am checking if the libraryis it possible to change the registered paths on while the server is running?

Thanks in advance

package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"strings"
	"time"

	coap "github.com/plgd-dev/go-coap/v2"
	"github.com/plgd-dev/go-coap/v2/message"
	"github.com/plgd-dev/go-coap/v2/message/codes"
	"github.com/plgd-dev/go-coap/v2/mux"
)

func loggingMiddleware(next mux.Handler) mux.Handler {
	return mux.HandlerFunc(func(w mux.ResponseWriter, r *mux.Message) {
		log.Printf("ClientAddress %v, %v, %v\n", w.Client().RemoteAddr(), r.String(), r.Message.Code)
		next.ServeCOAP(w, r)
	})
}

func handleG(w mux.ResponseWriter, r *mux.Message) {
	err := w.SetResponse(codes.Content, message.TextPlain, bytes.NewReader([]byte("/a")))
	if err != nil {
		log.Printf("cannot set response: %v", err)
	}
}

func handleA(w mux.ResponseWriter, r *mux.Message) {
	if r.Message.Code == codes.PUT {
		log.Println("read the response from the server")
		buf := new(strings.Builder)
		log.Println("created the reply buffer")
		n, err := io.Copy(buf, r.Body)
		log.Println("done copying the reply body. n equals", n)
		if err != nil && n == 0 && n != 0 {
			log.Fatal("Is this here", err)
		}
		log.Printf("Payload of the Put request %v\n", buf.String())
	} else if r.Message.Code == codes.GET {
		log.Printf("Responding to A GET request as usual")
	}

	err := w.SetResponse(codes.Content, message.TextPlain, bytes.NewReader([]byte("hello world")))
	if err != nil {
		log.Printf("cannot set response: %v", err)
	}
}

func handleB(w mux.ResponseWriter, r *mux.Message) {
	customResp := message.Message{
		Code:    codes.Content,
		Token:   r.Token,
		Context: r.Context,
		Options: make(message.Options, 0, 16),
		Body:    bytes.NewReader([]byte("B hello world")),
	}
	optsBuf := make([]byte, 32)
	opts, used, err := customResp.Options.SetContentFormat(optsBuf, message.TextPlain)
	if err == message.ErrTooSmall {
		optsBuf = append(optsBuf, make([]byte, used)...)
		opts, used, err = customResp.Options.SetContentFormat(optsBuf, message.TextPlain)
	}
	if err != nil {
		log.Printf("cannot set options to response: %v", err)
		return
	}
	optsBuf = optsBuf[:used]
	customResp.Options = opts

	err = w.Client().WriteMessage(&customResp)
	if err != nil {
		log.Printf("cannot set response: %v", err)
	}
}

func main() {
	r := mux.NewRouter()
	r.Use(loggingMiddleware)
	r.Handle("/.well-known/core", mux.HandlerFunc(handleG))
	r.Handle("/a", mux.HandlerFunc(handleA))
	r.Handle("/b", mux.HandlerFunc(handleB))

	log.Fatal(coap.ListenAndServe("udp", ":5683", r))
	for {
		time.Sleep(5 * time.Second)
		r.HandleRemove("/a")
		fmt.Println("Not giving service")
		time.Sleep(5 * time.Second)
		r.Handle("/a", mux.HandlerFunc(handleA))
		fmt.Println("giving sevice")
	}
}
@emmanuelay
Copy link

Interesting. Im looking at solving the same issue.
I found this link that details examples of how to provide a proper /.well-known/core payload.

It seems like the payload should actually include information which I would consider implementation details of each endpoint.

Ideally this would be developed as a configurable middleware to go-coap, where you could provide details for each endpoint... but since the payload varies alot, I'm not sure its possible to provide a generic interface for creating a /.well-known/core payloads.

@niondir
Copy link
Collaborator

niondir commented Feb 22, 2023

I think this should be part of the router. Else the router should at least provide the required information about response types etc.

It's something very fundamental of CoAP that should be supported by the stack imho.

A very simple solution, based on mux.Router.Routes():

func buildWellKnownHandler(routes map[string]mux.Route) mux.HandlerFunc {
	var resources []string
	for k, _ := range routes {
		resources = append(resources, fmt.Sprintf("<%s>", k))
	}

	return func(w mux.ResponseWriter, r *mux.Message) {
		body := strings.Join(resources, ",")

		w.SetResponse(codes.Content, msg.AppLinkFormat, bytes.NewReader([]byte(body)))
	}
}

@jkralik jkralik added the enhancement New feature or request label Aug 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants