go go restful static server, mighty restful static server!
This commit is contained in:
parent
9c507ae68e
commit
dd971fcc72
|
@ -7,6 +7,7 @@ Rudimentary go chat server as a fun project.
|
|||
```bash
|
||||
git clone https://git.coolaj86.com/coolaj86/chat.go.git
|
||||
go get gopkg.in/yaml.v2
|
||||
go get github.com/emicklei/go-restful
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
|
|
@ -16,19 +16,22 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// I'm not sure how to pass nested structs, so I de-nested this.
|
||||
// TODO: Learn if passing nested structs is desirable?
|
||||
type Conf struct {
|
||||
Port uint `yaml:"port,omitempty"`
|
||||
Mailer ConfMailer
|
||||
Port uint `yaml:"port,omitempty"`
|
||||
Mailer ConfMailer
|
||||
RootPath string `yaml:"root_path,omitempty"`
|
||||
}
|
||||
type ConfMailer struct {
|
||||
Url string `yaml:"url,omitempty"`
|
||||
|
@ -456,8 +459,34 @@ func sendAuthCode(cnf ConfMailer, to string) (string, error) {
|
|||
return code, nil
|
||||
}
|
||||
|
||||
type myServer struct {
|
||||
chans chan bufferedConn
|
||||
net.Listener
|
||||
}
|
||||
|
||||
func (m *myServer) Accept() (net.Conn, error) {
|
||||
bufConn := <-m.chans
|
||||
return bufConn, nil
|
||||
}
|
||||
|
||||
func newMyServer(l net.Listener) *myServer {
|
||||
return &myServer{make(chan bufferedConn), l}
|
||||
}
|
||||
|
||||
var config Conf
|
||||
|
||||
func serveStatic(req *restful.Request, resp *restful.Response) {
|
||||
actual := path.Join(config.RootPath, req.PathParameter("subpath"))
|
||||
fmt.Printf("serving %s ... (from %s)\n", actual, req.PathParameter("subpath"))
|
||||
http.ServeFile(
|
||||
resp.ResponseWriter,
|
||||
req.Request,
|
||||
actual)
|
||||
}
|
||||
func serveHello(req *restful.Request, resp *restful.Response) {
|
||||
fmt.Fprintf(resp, "{\"msg\":\"hello\"}")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
port := flag.Uint("telnet-port", 0, "tcp telnet chat port")
|
||||
|
@ -474,6 +503,10 @@ func main() {
|
|||
if nil != err {
|
||||
config = Conf{}
|
||||
}
|
||||
if "" == config.RootPath {
|
||||
// TODO Embed the public dir at the default
|
||||
config.RootPath = "./public"
|
||||
}
|
||||
|
||||
myRawConns := make(map[bufferedConn]bool)
|
||||
firstMsgs = make(chan myMsg, 128)
|
||||
|
@ -516,12 +549,38 @@ func main() {
|
|||
newConns <- conn
|
||||
}
|
||||
}()
|
||||
|
||||
// Learning by Example
|
||||
// https://github.com/emicklei/go-restful/blob/master/examples/restful-multi-containers.go
|
||||
// https://github.com/emicklei/go-restful/blob/master/examples/restful-basic-authentication.go
|
||||
// https://github.com/emicklei/go-restful/blob/master/examples/restful-serve-static.go
|
||||
// https://github.com/emicklei/go-restful/blob/master/examples/restful-pre-post-filters.go
|
||||
container := restful.NewContainer()
|
||||
|
||||
wsStatic := new(restful.WebService)
|
||||
wsStatic.Path("/")
|
||||
wsStatic.Route(wsStatic.GET("/").To(serveStatic))
|
||||
wsStatic.Route(wsStatic.GET("/{subpath:*}").To(serveStatic))
|
||||
container.Add(wsStatic)
|
||||
|
||||
wsApi := new(restful.WebService)
|
||||
wsApi.Path("/api")
|
||||
wsApi.Route(wsApi.GET("/api/hello").To(serveHello))
|
||||
/*
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: &myHandler{},
|
||||
}
|
||||
ws.Route(ws.POST("/api/authn").To(createAuth))
|
||||
ws.Route(ws.POST("/api/authn/{email}").To(createAuth))
|
||||
ws.Route(ws.GET("/api").Filter(basicAuthenticate).To(hello2))
|
||||
*/
|
||||
container.Add(wsApi)
|
||||
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: container,
|
||||
}
|
||||
myHttpServer := newMyServer(sock)
|
||||
go func() {
|
||||
server.Serve(myHttpServer)
|
||||
}()
|
||||
|
||||
// Main event loop handling most access to shared data
|
||||
for {
|
||||
|
@ -553,8 +612,9 @@ func main() {
|
|||
go handleSorted(bufConn)
|
||||
//case msg := <- myRooms["general"]:
|
||||
//delete(myRooms["general"], bufConn)
|
||||
//case bufConn := <-newHttpClient:
|
||||
//server.Serve(bufConn)
|
||||
case bufConn := <-newHttpClient:
|
||||
// this will be Accept()ed immediately by restful
|
||||
myHttpServer.chans <- bufConn
|
||||
case msg := <-myMsgs:
|
||||
t := msg.receivedAt
|
||||
tf := "%d-%02d-%02d %02d:%02d:%02d (%s)"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
port: 4080
|
||||
root_path: ./public
|
||||
mailer:
|
||||
service: 'mailgun'
|
||||
url: 'https://api.mailgun.net/v3/example.com/messages'
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Sample Chat</title></head>
|
||||
<body>
|
||||
<pre><code># Ask for an auth code (swap sub)
|
||||
curl -X POST https://localhost:4080/api/session \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{"sub":"jon@example.com"}'
|
||||
|
||||
# Validate auth code (swap session id, sub, and otp)
|
||||
curl -X POST https://localhost:4080/api/session/xyz \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{"sub":"jon@example.com","otp":"secret123"}'
|
||||
|
||||
# Post a message (swap api-token)
|
||||
curl -X POST https://localhost:4080/api/rooms/general \
|
||||
-H 'Authorization: Bearer api-token' \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{"msg":"hello"}'
|
||||
|
||||
# Get a room's messages (swap api-token, since unix-epoch)
|
||||
curl https://localhost:4080/api/rooms/general?since=0 \
|
||||
-H 'Authorization: Bearer api-token'
|
||||
</code></pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,3 @@
|
|||
"use strict"
|
||||
|
||||
console.log("Hello, World!");
|
Loading…
Reference in New Issue