2016-06-14 07:45:40 +02:00
package iris
import (
"fmt"
"os"
"sync"
"time"
2016-07-03 16:21:57 +02:00
"github.com/gavv/httpexpect"
2016-06-14 07:45:40 +02:00
"github.com/kataras/iris/config"
"github.com/kataras/iris/logger"
"github.com/kataras/iris/render/rest"
"github.com/kataras/iris/render/template"
"github.com/kataras/iris/sessions"
2016-06-28 11:50:26 +02:00
"github.com/kataras/iris/websocket"
2016-06-14 07:45:40 +02:00
///NOTE: register the session providers, but the s.Config.Sessions.Provider will be used only, if this empty then sessions are disabled.
_ "github.com/kataras/iris/sessions/providers/memory"
_ "github.com/kataras/iris/sessions/providers/redis"
)
// Default entry, use it with iris.$anyPublicFunc
var (
Default * Framework
Config * config . Iris
Logger * logger . Logger
Plugins PluginContainer
Websocket websocket . Server
HTTPServer * Server
2016-07-01 18:06:11 +02:00
// Available is a channel type of bool, fired to true when the server is opened and all plugins ran
2016-07-03 02:01:48 +02:00
// never fires false, if the .Close called then the channel is re-allocating.
2016-07-05 15:26:47 +02:00
// the channel is closed only when .ListenVirtual is used, otherwise it remains open until you close it.
2016-07-01 18:06:11 +02:00
//
// Note: it is a simple channel and decided to put it here and no inside HTTPServer, doesn't have statuses just true and false, simple as possible
// Where to use that?
// this is used on extreme cases when you don't know which .Listen/.NoListen will be called
// and you want to run/declare something external-not-Iris (all Iris functionality declared before .Listen/.NoListen) AFTER the server is started and plugins finished.
2016-07-03 16:21:57 +02:00
// see the server_test.go for an example
2016-07-01 18:06:11 +02:00
Available chan bool
2016-06-14 07:45:40 +02:00
)
func init ( ) {
2016-07-05 13:37:10 +02:00
initDefault ( )
}
func initDefault ( ) {
2016-06-14 07:45:40 +02:00
Default = New ( )
Config = Default . Config
Logger = Default . Logger
Plugins = Default . Plugins
Websocket = Default . Websocket
HTTPServer = Default . HTTPServer
2016-07-01 18:06:11 +02:00
Available = Default . Available
2016-06-14 07:45:40 +02:00
}
const (
/* conversional */
2016-06-28 17:06:52 +02:00
2016-06-14 07:45:40 +02:00
// HTMLEngine conversion for config.HTMLEngine
HTMLEngine = config . HTMLEngine
// PongoEngine conversion for config.PongoEngine
PongoEngine = config . PongoEngine
// MarkdownEngine conversion for config.MarkdownEngine
MarkdownEngine = config . MarkdownEngine
// JadeEngine conversion for config.JadeEngine
JadeEngine = config . JadeEngine
// AmberEngine conversion for config.AmberEngine
AmberEngine = config . AmberEngine
2016-06-28 11:50:26 +02:00
// HandlebarsEngine conversion for config.HandlebarsEngine
HandlebarsEngine = config . HandlebarsEngine
2016-06-14 07:45:40 +02:00
// DefaultEngine conversion for config.DefaultEngine
DefaultEngine = config . DefaultEngine
// NoEngine conversion for config.NoEngine
NoEngine = config . NoEngine
// NoLayout to disable layout for a particular template file
// conversion for config.NoLayout
NoLayout = config . NoLayout
/* end conversional */
)
// Framework is our God |\| Google.Search('Greek mythology Iris')
//
// Implements the FrameworkAPI
type Framework struct {
* muxAPI
2016-06-24 00:34:49 +02:00
rest * rest . Render
templates * template . Template
sessions * sessions . Manager
2016-06-14 07:45:40 +02:00
// fields which are useful to the user/dev
HTTPServer * Server
Config * config . Iris
Logger * logger . Logger
Plugins PluginContainer
Websocket websocket . Server
2016-07-01 18:06:11 +02:00
Available chan bool
2016-07-03 16:21:57 +02:00
// this is setted once when .Tester(t) is called
testFramework * httpexpect . Expect
2016-06-14 07:45:40 +02:00
}
// New creates and returns a new Iris station aka Framework.
//
// Receives an optional config.Iris as parameter
// If empty then config.Default() is used instead
func New ( cfg ... config . Iris ) * Framework {
c := config . Default ( ) . Merge ( cfg )
// we always use 's' no 'f' because 's' is easier for me to remember because of 'station'
// some things never change :)
2016-07-01 18:20:27 +02:00
s := & Framework { Config : & c , Available : make ( chan bool ) }
2016-06-14 07:45:40 +02:00
{
///NOTE: set all with s.Config pointer
// set the Logger
s . Logger = logger . New ( s . Config . Logger )
// set the plugin container
s . Plugins = & pluginContainer { logger : s . Logger }
// set the websocket server
s . Websocket = websocket . NewServer ( s . Config . Websocket )
// set the servemux, which will provide us the public API also, with its context pool
2016-06-16 04:24:01 +02:00
mux := newServeMux ( sync . Pool { New : func ( ) interface { } { return & Context { framework : s } } } , s . Logger )
2016-06-14 07:45:40 +02:00
// set the public router API (and party)
s . muxAPI = & muxAPI { mux : mux , relativePath : "/" }
2016-07-05 15:26:47 +02:00
// set the server with the default configuration, which is changed on Listen functions
defaultServerCfg := config . DefaultServer ( )
s . HTTPServer = newServer ( & defaultServerCfg )
2016-06-14 07:45:40 +02:00
}
return s
}
func ( s * Framework ) initialize ( ) {
// set sessions
if s . Config . Sessions . Provider != "" {
s . sessions = sessions . New ( s . Config . Sessions )
}
2016-06-22 15:01:31 +02:00
// set the rest
2016-06-14 07:45:40 +02:00
s . rest = rest . New ( s . Config . Render . Rest )
2016-06-24 00:34:49 +02:00
// set templates if not already setted
2016-06-14 07:45:40 +02:00
s . prepareTemplates ( )
// listen to websocket connections
websocket . RegisterServer ( s , s . Websocket , s . Logger )
2016-06-17 06:18:09 +02:00
// prepare the mux & the server
2016-06-14 07:45:40 +02:00
s . mux . setCorrectPath ( ! s . Config . DisablePathCorrection )
s . mux . setEscapePath ( ! s . Config . DisablePathEscape )
2016-06-16 04:24:01 +02:00
s . mux . setHostname ( s . HTTPServer . VirtualHostname ( ) )
2016-06-14 07:45:40 +02:00
// set the debug profiling handlers if ProfilePath is setted
if debugPath := s . Config . ProfilePath ; debugPath != "" {
s . Handle ( MethodGet , debugPath + "/*action" , profileMiddleware ( debugPath ) ... )
}
2016-06-29 19:07:35 +02:00
if s . Config . MaxRequestBodySize > config . DefaultMaxRequestBodySize {
2016-06-14 07:45:40 +02:00
s . HTTPServer . MaxRequestBodySize = int ( s . Config . MaxRequestBodySize )
}
}
// prepareTemplates sets the templates if not nil, we make this check because of .TemplateString, which can be called before Listen
func ( s * Framework ) prepareTemplates ( ) {
// prepare the templates
if s . templates == nil {
// These functions are directly contact with Iris' functionality.
funcs := map [ string ] interface { } {
"url" : s . URL ,
"urlpath" : s . Path ,
}
template . RegisterSharedFuncs ( funcs )
s . templates = template . New ( s . Config . Render . Template )
}
}
// openServer is internal method, open the server with specific options passed by the Listen and ListenTLS
// it's a blocking func
func ( s * Framework ) openServer ( ) ( err error ) {
s . initialize ( )
s . Plugins . DoPreListen ( s )
2016-06-17 06:18:09 +02:00
// set the server's handler now, in order to give the chance to the plugins to add their own middlewares and routes to this station
s . HTTPServer . SetHandler ( s . mux )
2016-06-15 23:13:56 +02:00
if err = s . HTTPServer . Open ( ) ; err == nil {
2016-07-05 14:29:32 +02:00
2016-06-14 07:45:40 +02:00
// print the banner
2016-06-25 06:38:47 +02:00
if ! s . Config . DisableBanner {
2016-06-14 07:45:40 +02:00
s . Logger . PrintBanner ( banner ,
fmt . Sprintf ( "%s: Running at %s\n" , time . Now ( ) . Format ( config . TimeFormat ) ,
s . HTTPServer . Host ( ) ) )
}
s . Plugins . DoPostListen ( s )
2016-07-05 15:26:47 +02:00
go func ( ) { s . Available <- true } ( )
ch := make ( chan os . Signal )
<- ch
s . Close ( )
2016-07-05 14:29:32 +02:00
2016-06-14 07:45:40 +02:00
}
return
}
// closeServer is used to close the tcp listener from the server, returns an error
func ( s * Framework ) closeServer ( ) error {
s . Plugins . DoPreClose ( s )
2016-07-03 02:01:48 +02:00
s . Available = make ( chan bool )
2016-06-29 15:25:17 +02:00
return s . HTTPServer . Close ( )
2016-06-14 07:45:40 +02:00
}