Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
286f010346 | |||
f938487884 | |||
7c03a40ef0 | |||
f0fc5fa44f |
47
app.go
47
app.go
@ -1,8 +1,11 @@
|
|||||||
package nf
|
package nf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -12,6 +15,7 @@ type App struct {
|
|||||||
config *Config
|
config *Config
|
||||||
router *router
|
router *router
|
||||||
groups []*RouterGroup
|
groups []*RouterGroup
|
||||||
|
server *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
func (a *App) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
@ -36,9 +40,46 @@ func (a *App) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Run(address string) error {
|
func (a *App) run(ln net.Listener) error {
|
||||||
|
srv := &http.Server{Handler: a}
|
||||||
|
a.server = srv
|
||||||
|
|
||||||
if !a.config.DisableBanner {
|
if !a.config.DisableBanner {
|
||||||
fmt.Println(banner + "nf serve at: " + address + "\n")
|
fmt.Println(banner + "nf serve at: " + ln.Addr().String() + "\n")
|
||||||
}
|
}
|
||||||
return http.ListenAndServe(address, a)
|
|
||||||
|
err := a.server.Serve(ln)
|
||||||
|
if !errors.Is(err, http.ErrServerClosed) || a.config.ErrServeClose {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Run(address string) error {
|
||||||
|
ln, err := net.Listen("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.run(ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RunTLS(address string, tlsConfig *tls.Config) error {
|
||||||
|
ln, err := tls.Listen("tcp", address, tlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.run(ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) RunListener(ln net.Listener) error {
|
||||||
|
a.server = &http.Server{Addr: ln.Addr().String()}
|
||||||
|
|
||||||
|
return a.run(ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Shutdown(ctx context.Context) error {
|
||||||
|
return a.server.Shutdown(ctx)
|
||||||
}
|
}
|
||||||
|
72
ctx.go
72
ctx.go
@ -3,8 +3,11 @@ package nf
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -91,6 +94,11 @@ func (c *Ctx) Form(key string) string {
|
|||||||
return c.Request.FormValue(key)
|
return c.Request.FormValue(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) FormFile(key string) (*multipart.FileHeader, error) {
|
||||||
|
_, fh, err := c.Request.FormFile(key)
|
||||||
|
return fh, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Ctx) Query(key string) string {
|
func (c *Ctx) Query(key string) string {
|
||||||
return c.Request.URL.Query().Get(key)
|
return c.Request.URL.Query().Get(key)
|
||||||
}
|
}
|
||||||
@ -104,6 +112,14 @@ func (c *Ctx) Get(key string, defaultValue ...string) string {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) IP() string {
|
||||||
|
ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Ctx) BodyParser(out interface{}) error {
|
func (c *Ctx) BodyParser(out interface{}) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
@ -152,5 +168,61 @@ func (c *Ctx) BodyParser(out interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ctx) QueryParser(out interface{}) error {
|
func (c *Ctx) QueryParser(out interface{}) error {
|
||||||
|
//v := reflect.ValueOf(out)
|
||||||
|
//
|
||||||
|
//if v.Kind() == reflect.Ptr && v.Elem().Kind() != reflect.Map {
|
||||||
|
//}
|
||||||
|
|
||||||
return parseToStruct("query", out, c.Request.URL.Query())
|
return parseToStruct("query", out, c.Request.URL.Query())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===============================================================
|
||||||
|
|| Handle Ctx Response Part
|
||||||
|
=============================================================== */
|
||||||
|
|
||||||
|
func (c *Ctx) Status(code int) *Ctx {
|
||||||
|
c.StatusCode = code
|
||||||
|
c.Writer.WriteHeader(code)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) Set(key string, value string) {
|
||||||
|
c.Writer.Header().Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) SetHeader(key string, value string) {
|
||||||
|
c.Writer.Header().Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) SendString(data string) error {
|
||||||
|
c.SetHeader("Content-Type", "text/plain")
|
||||||
|
_, err := c.Write([]byte(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) Writef(format string, values ...interface{}) (int, error) {
|
||||||
|
c.SetHeader("Content-Type", "text/plain")
|
||||||
|
return c.Writer.Write([]byte(fmt.Sprintf(format, values...)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) JSON(data interface{}) error {
|
||||||
|
c.SetHeader("Content-Type", "application/json")
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(c.Writer)
|
||||||
|
|
||||||
|
if err := encoder.Encode(data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) Write(data []byte) (int, error) {
|
||||||
|
return c.Writer.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ctx) HTML(html string) error {
|
||||||
|
c.SetHeader("Content-Type", "text/html")
|
||||||
|
_, err := c.Writer.Write([]byte(html))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
4
nf.go
4
nf.go
@ -9,6 +9,10 @@ type Map map[string]interface{}
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
// Default: 4 * 1024 * 1024
|
// Default: 4 * 1024 * 1024
|
||||||
BodyLimit int64 `json:"-"`
|
BodyLimit int64 `json:"-"`
|
||||||
|
|
||||||
|
// if report http.ErrServerClosed as run err
|
||||||
|
ErrServeClose bool `json:"-"`
|
||||||
|
|
||||||
DisableBanner bool `json:"-"`
|
DisableBanner bool `json:"-"`
|
||||||
DisableLogger bool `json:"-"`
|
DisableLogger bool `json:"-"`
|
||||||
DisableRecover bool `json:"-"`
|
DisableRecover bool `json:"-"`
|
||||||
|
67
readme.md
Normal file
67
readme.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# NF Web Framework
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
##### basic usage
|
||||||
|
|
||||||
|
- get param
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
app := nf.New()
|
||||||
|
|
||||||
|
app.Get("/hello/:name", func(c *nf.Ctx) error {
|
||||||
|
name := c.Param("name")
|
||||||
|
return c.JSON(nf.Map{"status": 200, "data": "hello, " + name})
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Fatal(app.Run("0.0.0.0:80"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- parse request query
|
||||||
|
```go
|
||||||
|
func handleQuery(c *nf.Ctx) error {
|
||||||
|
type Req struct {
|
||||||
|
Name string `query:"name"`
|
||||||
|
Addr []string `query:"addr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
req = Req{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = c.QueryParser(&req); err != nil {
|
||||||
|
return nf.NewNFError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(nf.Map{"query": req})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- parse application/json body
|
||||||
|
```go
|
||||||
|
func handlePost(c *nf.Ctx) error {
|
||||||
|
type Req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Addr []string `json:"addr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
req = Req{}
|
||||||
|
reqMap = make(map[string]any)
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = c.BodyParser(&req); err != nil {
|
||||||
|
return nf.NewNFError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// can parse body multi times
|
||||||
|
if err = c.BodyParser(&reqMap); err != nil {
|
||||||
|
return nf.NewNFError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(nf.Map{"struct": req, "map": reqMap})
|
||||||
|
}
|
||||||
|
```
|
48
resp.go
48
resp.go
@ -1,49 +1 @@
|
|||||||
package nf
|
package nf
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Ctx) Status(code int) *Ctx {
|
|
||||||
c.StatusCode = code
|
|
||||||
c.Writer.WriteHeader(code)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Ctx) SetHeader(key string, value string) {
|
|
||||||
c.Writer.Header().Set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Ctx) SendString(data string) error {
|
|
||||||
c.SetHeader("Content-Type", "text/plain")
|
|
||||||
_, err := c.Write([]byte(data))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Ctx) Writef(format string, values ...interface{}) (int, error) {
|
|
||||||
c.SetHeader("Content-Type", "text/plain")
|
|
||||||
return c.Writer.Write([]byte(fmt.Sprintf(format, values...)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Ctx) JSON(data interface{}) error {
|
|
||||||
c.SetHeader("Content-Type", "application/json")
|
|
||||||
|
|
||||||
encoder := json.NewEncoder(c.Writer)
|
|
||||||
|
|
||||||
if err := encoder.Encode(data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Ctx) Write(data []byte) (int, error) {
|
|
||||||
return c.Writer.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Ctx) HTML(html string) error {
|
|
||||||
c.SetHeader("Content-Type", "text/html")
|
|
||||||
_, err := c.Writer.Write([]byte(html))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/loveuer/nf"
|
"github.com/loveuer/nf"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -13,5 +14,6 @@ func main() {
|
|||||||
return c.JSON(nf.Map{"status": 200, "data": "hello, " + name})
|
return c.JSON(nf.Map{"status": 200, "data": "hello, " + name})
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Fatal(app.Run("0.0.0.0:80"))
|
ln, _ := net.Listen("tcp", ":80")
|
||||||
|
log.Fatal(app.RunListener(ln))
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,18 @@ func main() {
|
|||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
req = new(Req)
|
req = new(Req)
|
||||||
|
rm = make(map[string]any)
|
||||||
)
|
)
|
||||||
|
|
||||||
if err = c.QueryParser(req); err != nil {
|
//if err = c.QueryParser(req); err != nil {
|
||||||
return nf.NewNFError(400, err.Error())
|
// return nf.NewNFError(400, "1:"+err.Error())
|
||||||
|
//}
|
||||||
|
|
||||||
|
if err = c.QueryParser(&rm); err != nil {
|
||||||
|
return nf.NewNFError(400, "2:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.JSON(nf.Map{"status": 200, "data": req})
|
return c.JSON(nf.Map{"status": 200, "data": req, "map": rm})
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Fatal(app.Run("0.0.0.0:80"))
|
log.Fatal(app.Run("0.0.0.0:80"))
|
||||||
|
49
xtest/quit/main.go
Normal file
49
xtest/quit/main.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/loveuer/nf"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := nf.New()
|
||||||
|
quit := make(chan bool)
|
||||||
|
|
||||||
|
app.Get("/name", handleGet)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := app.Run(":7383")
|
||||||
|
log.Print("run with err=", err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
err := app.Shutdown(context.TODO())
|
||||||
|
log.Print("quit with err=", err)
|
||||||
|
quit <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-quit
|
||||||
|
|
||||||
|
log.Print("quited")
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGet(c *nf.Ctx) error {
|
||||||
|
type Req struct {
|
||||||
|
Name string `query:"name"`
|
||||||
|
Addr []string `query:"addr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
req = Req{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = c.QueryParser(&req); err != nil {
|
||||||
|
return nf.NewNFError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(nf.Map{"req_map": req})
|
||||||
|
}
|
Reference in New Issue
Block a user