瀏覽代碼

go go restful static server, mighty restful static server!

master
AJ ONeal 6 年前
父節點
當前提交
dd971fcc72
  1. 1
      README.md
  2. 76
      chatserver.go
  3. 1
      config.sample.yml
  4. 26
      public/index.html
  5. 3
      public/js/app.js

1
README.md

@ -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

76
chatserver.go

@ -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
config.sample.yml

@ -1,4 +1,5 @@
port: 4080
root_path: ./public
mailer:
service: 'mailgun'
url: 'https://api.mailgun.net/v3/example.com/messages'

26
public/index.html

@ -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>

3
public/js/app.js

@ -0,0 +1,3 @@
"use strict"
console.log("Hello, World!");
載入中…
取消
儲存