add more comments, clean up module
This commit is contained in:
100
pathway.go
100
pathway.go
@@ -2,96 +2,82 @@ package pathway
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
// "nhooyr.io/websocket"
|
||||
)
|
||||
|
||||
var (
|
||||
// actual business end of the device
|
||||
paths *sync.Map
|
||||
debugging string
|
||||
)
|
||||
|
||||
func init() {
|
||||
paths = &sync.Map{}
|
||||
}
|
||||
|
||||
// Transfer holds a single tranferable connection to be read
|
||||
type Transfer struct {
|
||||
// httpTransfer holds a single tranferable connection to be read.
|
||||
// created by POSTs or PUBs, these are read from by GET requests.
|
||||
// once the reader is done, it can go and close the done channel.
|
||||
type httpTransfer struct {
|
||||
reader io.ReadCloser
|
||||
done chan struct{}
|
||||
contentlength string
|
||||
}
|
||||
|
||||
// NewTransfer returns a ready to use Transfer and it's writer
|
||||
func NewTransfer(contentlength string) (transfer Transfer, writer io.WriteCloser) {
|
||||
// newTransfer returns a ready to use httpTransfer and it's writer.
|
||||
func newTransfer(contentlength string) (transfer httpTransfer, writer io.WriteCloser) {
|
||||
var reader io.ReadCloser
|
||||
reader, writer = io.Pipe()
|
||||
|
||||
transfer = Transfer{
|
||||
reader: reader.(io.ReadCloser),
|
||||
transfer = httpTransfer{
|
||||
reader: reader,
|
||||
contentlength: contentlength,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Queue is where posts and gets can exchange transfers
|
||||
type Queue struct {
|
||||
ch chan Transfer
|
||||
// transferQueue holds all pending connections for a particular path stored in
|
||||
// the Pathway map.
|
||||
type transferQueue struct {
|
||||
ch chan httpTransfer
|
||||
posts int32
|
||||
gets int32
|
||||
}
|
||||
|
||||
func PathHandler(w http.ResponseWriter, r *http.Request) {
|
||||
pathID := r.URL.Path
|
||||
// Pathway keeps track of and allows one to handle all the different paths.
|
||||
type Pathway struct {
|
||||
sync.Map
|
||||
}
|
||||
|
||||
if len(pathID) < 2 {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("path to short"))
|
||||
return
|
||||
}
|
||||
// New returns a usable Pathway which HTTP Handler can be used to allow clients to
|
||||
// create and connect to eachother via arbitraty paths.
|
||||
func New() *Pathway {
|
||||
return new(Pathway)
|
||||
}
|
||||
|
||||
// ServeHTTP is a handler for incoming GET or POST request. It directs them to the
|
||||
// proper path: either by creating a new one or connecting it to an existing one.
|
||||
func (pw *Pathway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
pathID := r.URL.Path
|
||||
|
||||
if h := r.Header.Get("Connection"); len(h) > 0 && strings.ToLower(h) == "upgrade" {
|
||||
if h = r.Header.Get("Upgrade"); len(h) > 0 && strings.ToLower(h) == "websocket" {
|
||||
// c, err := websocket.Accept(w, r, nil)
|
||||
// if err != nil {
|
||||
// info("Websocket not accepted: %+s", err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// defer c.Close(websocket.StatusInternalError, "the sky is falling")
|
||||
info("Websocket connections not supported yet. Headers: %+v", r.Header)
|
||||
// return
|
||||
// websockets are special, and not supported
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("websockets are not supported"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if r.Method == "GET" {
|
||||
info("%s [GET] Connected", pathID)
|
||||
handleGet(pathID, w, r)
|
||||
} else if r.Method == "POST" {
|
||||
info("%s [POST] Connected", pathID)
|
||||
if r.Method == http.MethodGet {
|
||||
// handle an incoming GET request to connect to either POST or PUB
|
||||
pw.handleGet(pathID, w, r)
|
||||
} else if r.Method == http.MethodPost {
|
||||
if h := r.Header.Get("X-Pathway"); h == "pubsub" {
|
||||
debug("%s [PUBSUB] Upgrade POST to PUBSUB", pathID)
|
||||
handlePubSub(pathID, r)
|
||||
// handle an incoming PUB part of a PUBSUB.
|
||||
pw.handlePubSub(pathID, r)
|
||||
} else {
|
||||
handlePost(pathID, r)
|
||||
// handle an incoming POST.
|
||||
pw.handlePost(pathID, r)
|
||||
}
|
||||
} else {
|
||||
info("Unhandled request type: '%s'", r.Method)
|
||||
}
|
||||
}
|
||||
|
||||
func info(msg string, args ...interface{}) {
|
||||
log.Printf("INFO | "+msg, args...)
|
||||
}
|
||||
|
||||
func debug(msg string, args ...interface{}) {
|
||||
if len(debugging) > 0 {
|
||||
log.Printf("DEBUG | "+msg, args...)
|
||||
// if it's not a get or a post, then let the client know other methods
|
||||
// are not supported.
|
||||
w.Header().Set("Allow", http.MethodGet+", "+http.MethodPost)
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
w.Write([]byte(r.Method + " is not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user