Skip to content

Commit

Permalink
Merge pull request #20 from acoshift/dev
Browse files Browse the repository at this point in the history
remove app interface, add server config
  • Loading branch information
acoshift committed May 14, 2018
2 parents e3eda35 + 7dab9a0 commit 801dad9
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 184 deletions.
12 changes: 12 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
language: go

go:
- 1.9.x
- 1.10.x

before_install:
- go get github.com/mattn/goveralls

script:
- go test -v -covermode=count -coverprofile=profile.cov .
- $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Hime

[![Build Status](https://travis-ci.org/acoshift/hime.svg?branch=master)](https://travis-ci.org/acoshift/hime)
[![Coverage Status](https://coveralls.io/repos/github/acoshift/hime/badge.svg?branch=master)](https://coveralls.io/github/acoshift/hime?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/acoshift/hime)](https://goreportcard.com/report/github.com/acoshift/hime)
[![GoDoc](https://godoc.org/github.com/acoshift/hime?status.svg)](https://godoc.org/github.com/acoshift/hime)

Expand All @@ -26,7 +28,7 @@ Other framework don't allow this. They have built-in router, framework-specific
- Compatible with net/http middlewares without code change
- Use standard html/template for view
- Built-in core functions for build web server
- Reduce developer bug
- Reduce developer bugs

## What is this framework DO NOT focus

Expand All @@ -50,7 +52,7 @@ func main() {
ListenAndServe(":8080")
}

func router(app hime.App) http.Handler {
func router(app *hime.App) http.Handler {
mux := http.NewServeMux()
mux.Handle(app.Route("index"), hime.H(indexHandler))
return middleware.Chain(
Expand Down
120 changes: 69 additions & 51 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package hime

import (
"context"
"crypto/tls"
"html/template"
"log"
"mime"
"net"
"net/http"
"time"

Expand All @@ -14,8 +17,36 @@ import (
"github.com/tdewolff/minify/js"
)

type app struct {
srv *http.Server
// App is the hime app
type App struct {
// TLSConfig overrides http.Server TLSConfig
TLSConfig *tls.Config

// ReadTimeout overrides http.Server ReadTimeout
ReadTimeout time.Duration

// ReadHeaderTimeout overrides http.Server ReadHeaderTimeout
ReadHeaderTimeout time.Duration

// WriteTimeout overrides http.Server WriteTimeout
WriteTimeout time.Duration

// IdleTimeout overrides http.Server IdleTimeout
IdleTimeout time.Duration

// MaxHeaderBytes overrides http.Server MaxHeaderBytes
MaxHeaderBytes int

// TLSNextProto overrides http.Server TLSNextProto
TLSNextProto map[string]func(*http.Server, *tls.Conn, http.Handler)

// ConnState overrides http.Server ConnState
ConnState func(net.Conn, http.ConnState)

// ErrorLog overrides http.Server ErrorLog
ErrorLog *log.Logger

srv http.Server
handler http.Handler
templateFuncs []template.FuncMap
templateComponents []string
Expand All @@ -28,13 +59,6 @@ type app struct {
beforeRender middleware.Middleware
}

// consts
const (
defTemplateRoot = "layout"
defTemplateDir = "view"
defShutdownTimeout = 30 * time.Second
)

var (
ctxKeyApp = struct{}{}
)
Expand All @@ -44,76 +68,70 @@ func init() {
}

// New creates new app
func New() App {
app := &app{}
app.template = make(map[string]*template.Template)
app.templateRoot = defTemplateRoot
app.templateDir = defTemplateDir
app.routes = make(Routes)
app.globals = make(Globals)
return app
func New() *App {
return &App{}
}

// TemplateRoot sets template root to select when load
func (app *app) TemplateRoot(name string) App {
app.templateRoot = name
return app
}

// TemplateDir sets template dir
func (app *app) TemplateDir(path string) App {
app.templateDir = path
return app
}

// Handler sets app handler
func (app *app) Handler(h http.Handler) App {
// Handler sets the handler
func (app *App) Handler(h http.Handler) *App {
app.handler = h
return app
}

// Minify sets app minifier
func (app *app) Minify() App {
// Minify enables minify when render html, css, js
func (app *App) Minify() *App {
app.minifier = minify.New()
app.minifier.AddFunc("text/html", html.Minify)
app.minifier.AddFunc("text/css", css.Minify)
app.minifier.AddFunc("text/javascript", js.Minify)
return app
}

func (app *app) BeforeRender(m middleware.Middleware) App {
// BeforeRender runs given middleware for before render,
// ex. View, JSON, String, Bytes, CopyForm, etc
func (app *App) BeforeRender(m middleware.Middleware) *App {
app.beforeRender = m
return app
}

func (app *app) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(ctx, ctxKeyApp, app)
r = r.WithContext(ctx)
app.handler.ServeHTTP(w, r)
}

func (app *app) Server(server *http.Server) App {
app.srv = server
return app
func (app *App) configServer(addr string) {
app.srv.TLSConfig = app.TLSConfig
app.srv.ReadTimeout = app.ReadTimeout
app.srv.ReadHeaderTimeout = app.ReadHeaderTimeout
app.srv.WriteTimeout = app.WriteTimeout
app.srv.IdleTimeout = app.IdleTimeout
app.srv.MaxHeaderBytes = app.MaxHeaderBytes
app.srv.TLSNextProto = app.TLSNextProto
app.srv.ConnState = app.ConnState
app.srv.ErrorLog = app.ErrorLog
app.srv.Handler = app
app.srv.Addr = addr
}

// ListenAndServe is the shotcut for http.ListenAndServe
func (app *app) ListenAndServe(addr string) error {
if app.srv == nil {
app.srv = &http.Server{
Addr: addr,
Handler: app,
}
}
// ListenAndServe starts web server
func (app *App) ListenAndServe(addr string) error {
app.configServer(addr)

return app.srv.ListenAndServe()
}

// GracefulShutdown change app to graceful mode
func (app *app) GracefulShutdown() GracefulShutdownApp {
return &gracefulShutdownApp{
app: app,
timeout: defShutdownTimeout,
// ListenAndServeTLS starts web server in tls mode
func (app *App) ListenAndServeTLS(addr, certFile, keyFile string) error {
app.configServer(addr)

return app.srv.ListenAndServeTLS(certFile, keyFile)
}

// GracefulShutdown returns graceful shutdown server
func (app *App) GracefulShutdown() *GracefulShutdown {
return &GracefulShutdown{
App: app,
}
}
6 changes: 3 additions & 3 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ func NewContext(w http.ResponseWriter, r *http.Request) Context {
}

func newInternalContext(w http.ResponseWriter, r *http.Request) *appContext {
app, ok := r.Context().Value(ctxKeyApp).(*app)
app, ok := r.Context().Value(ctxKeyApp).(*App)
if !ok {
panic(ErrAppNotFound)
}
return newContext(app, w, r)
}

func newContext(app *app, w http.ResponseWriter, r *http.Request) *appContext {
func newContext(app *App, w http.ResponseWriter, r *http.Request) *appContext {
return &appContext{r.Context(), app, r, w, 0}
}

type appContext struct {
context.Context

app *app
app *App
r *http.Request
w http.ResponseWriter

Expand Down
2 changes: 1 addition & 1 deletion examples/net-http/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func main() {
}
}

func router(app hime.App) http.Handler {
func router(app *hime.App) http.Handler {
mux := http.NewServeMux()
mux.Handle(app.Route("index"), hime.H(indexHandler))
mux.Handle(app.Route("about"), hime.H(aboutHandler))
Expand Down
12 changes: 10 additions & 2 deletions global.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package hime

func (app *app) Globals(globals Globals) App {
// Globals registers global constants
func (app *App) Globals(globals Globals) *App {
if app.globals == nil {
app.globals = make(Globals)
}
for key, value := range globals {
app.globals[key] = value
}
return app
}

func (app *app) Global(key interface{}) interface{} {
// Global gets value from global storage
func (app *App) Global(key interface{}) interface{} {
if app.globals == nil {
return nil
}
return app.globals[key]
}

Expand Down
80 changes: 46 additions & 34 deletions graceful.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,56 @@ import (
"time"
)

// GracefulShutdownApp

type gracefulShutdownApp struct {
*app
// GracefulShutdown is the app in graceful shutdown mode
type GracefulShutdown struct {
App *App
timeout time.Duration
wait time.Duration
notiFns []func()
beforeFns []func()
}

// ShutdownTimeout sets shutdown timeout for graceful shutdown
func (app *gracefulShutdownApp) Timeout(d time.Duration) GracefulShutdownApp {
app.timeout = d
return app
// Timeout sets shutdown timeout for graceful shutdown,
// set to 0 to disable timeout
//
// default is 0
func (gs *GracefulShutdown) Timeout(d time.Duration) *GracefulShutdown {
gs.timeout = d
return gs
}

func (app *gracefulShutdownApp) Wait(d time.Duration) GracefulShutdownApp {
app.wait = d
return app
// Wait sets wait time before shutdown
func (gs *GracefulShutdown) Wait(d time.Duration) *GracefulShutdown {
gs.wait = d
return gs
}

func (app *gracefulShutdownApp) Notify(fn func()) GracefulShutdownApp {
// Notify calls fn when receive terminate signal from os
func (gs *GracefulShutdown) Notify(fn func()) *GracefulShutdown {
if fn != nil {
app.notiFns = append(app.notiFns, fn)
gs.notiFns = append(gs.notiFns, fn)
}
return app
return gs
}

func (app *gracefulShutdownApp) Before(fn func()) GracefulShutdownApp {
// Before runs fn before start waiting to SIGTERM
func (gs *GracefulShutdown) Before(fn func()) *GracefulShutdown {
if fn != nil {
app.beforeFns = append(app.beforeFns, fn)
gs.beforeFns = append(gs.beforeFns, fn)
}
return app
return gs
}

// ListenAndServe is the shotcut for http.ListenAndServe
func (app *gracefulShutdownApp) ListenAndServe(addr string) (err error) {
if app.srv == nil {
app.srv = &http.Server{
Addr: addr,
Handler: app,
}
}

func (gs *GracefulShutdown) start(listenAndServe func() error) (err error) {
serverCtx, cancelServer := context.WithCancel(context.Background())
defer cancelServer()
go func() {
if err = app.srv.ListenAndServe(); err != http.ErrServerClosed {
if err = listenAndServe(); err != http.ErrServerClosed {
cancelServer()
}
}()

for _, fn := range app.beforeFns {
for _, fn := range gs.beforeFns {
fn()
}

Expand All @@ -72,15 +69,30 @@ func (app *gracefulShutdownApp) ListenAndServe(addr string) (err error) {
case <-serverCtx.Done():
return
case <-stop:
for _, fn := range app.notiFns {
for _, fn := range gs.notiFns {
fn()
}
if app.wait > 0 {
time.Sleep(app.wait)
if gs.wait > 0 {
time.Sleep(gs.wait)
}

if gs.timeout > 0 {
ctx, cancel := context.WithTimeout(context.Background(), gs.timeout)
defer cancel()
err = gs.App.srv.Shutdown(ctx)
} else {
err = gs.App.srv.Shutdown(context.Background())
}
ctx, cancel := context.WithTimeout(context.Background(), app.timeout)
defer cancel()
err = app.srv.Shutdown(ctx)
}
return
}

// ListenAndServe starts web server in graceful shutdown mode
func (gs *GracefulShutdown) ListenAndServe(addr string) error {
return gs.start(func() error { return gs.App.ListenAndServe(addr) })
}

// ListenAndServeTLS starts web server in graceful shutdown and tls mode
func (gs *GracefulShutdown) ListenAndServeTLS(addr, certFile, keyFile string) error {
return gs.start(func() error { return gs.App.ListenAndServeTLS(addr, certFile, keyFile) })
}
Loading

0 comments on commit 801dad9

Please sign in to comment.