I love coding unique Iris staff!!!
This commit is contained in:
Gerasimos Maropoulos 2016-10-27 03:17:09 +03:00
parent 6d65c00423
commit d32ae1377c
8 changed files with 503 additions and 30 deletions

View File

@ -2,6 +2,134 @@
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
## 5.0.1 -> 5.1.0
- **NEW FEATURE**: `CacheService` simple, cache service for your app's static body content(can work as external service if you are doing horizontal scaling, the `Cache` is just a `Handler` :) )
Cache any content, templates, static files, even the error handlers, anything.
> Bombardier: 5 million requests and 100k clients per second to this markdown static content(look below) with cache(3 seconds) can be served up to ~x12 times faster. Imagine what happens with bigger content like full page and templates!
**OUTLINE**
```go
// Cache is just a wrapper for a route's handler which you want to enable body caching
// Usage: iris.Get("/", iris.Cache(func(ctx *iris.Context){
// ctx.WriteString("Hello, world!") // or a template or anything else
// }, time.Duration(10*time.Second))) // duration of expiration
// if <=time.Second then it tries to find it though request header's "cache-control" maxage value
//
// Note that it depends on a station instance's cache service.
// Do not try to call it from default' station if you use the form of app := iris.New(),
// use the app.Cache instead of iris.Cache
Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc
// InvalidateCache clears the cache body for a specific key(request uri, can be retrieved by GetCacheKey(ctx))
//
// Note that it depends on a station instance's cache service.
// Do not try to call it from default' station if you use the form of app := iris.New(),
// use the app.Cache instead of iris.Cache
InvalidateCache(key string)
// GetCacheKey returns the cache key(string) from a Context
GetCacheKey(ctx *Context) string
```
**OVERVIEW**
```go
iris.Get("/hi", iris.Cache(func(c *iris.Context) {
c.WriteString("Hi this is a big content, do not try cache on small content it will not make any significant difference!")
}, time.Duration(10)*time.Second))
```
[EXAMPLE](https://github.com/iris-contrib/examples/tree/master/cache_body):
```go
package main
import (
"github.com/kataras/iris"
"time"
)
var testMarkdownContents = `## Hello Markdown from Iris
This is an example of Markdown with Iris
Features
--------
All features of Sundown are supported, including:
* **Compatibility**. The Markdown v1.0.3 test suite passes with
the --tidy option. Without --tidy, the differences are
mostly in whitespace and entity escaping, where blackfriday is
more consistent and cleaner.
* **Common extensions**, including table support, fenced code
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
* **Safety**. Blackfriday is paranoid when parsing, making it safe
to feed untrusted user input without fear of bad things
happening. The test suite stress tests this and there are no
known inputs that make it crash. If you find one, please let me
know and send me the input that does it.
NOTE: "safety" in this context means *runtime safety only*. In order to
protect yourself against JavaScript injection in untrusted content, see
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
* **Fast processing**. It is fast enough to render on-demand in
most web applications without having to cache the output.
* **Thread safety**. You can run multiple parsers in different
goroutines without ill effect. There is no dependence on global
shared state.
* **Minimal dependencies**. Blackfriday only depends on standard
library packages in Go. The source code is pretty
self-contained, so it is easy to add to any project, including
Google App Engine projects.
* **Standards compliant**. Output successfully validates using the
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
[this is a link](https://github.com/kataras/iris) `
func main() {
// if this is not setted then iris set this duration to the lowest expiration entry from the cache + 5 seconds
// recommentation is to left as it's or
// iris.Config.CacheGCDuration = time.Duration(5) * time.Minute
bodyHandler := func(ctx *iris.Context) {
ctx.Markdown(iris.StatusOK, testMarkdownContents)
}
expiration := time.Duration(5 * time.Second)
iris.Get("/", iris.Cache(bodyHandler, expiration))
// if expiration is <=time.Second then the cache tries to set the expiration from the "cache-control" maxage header's value(in seconds)
// // if this header doesn't founds then the default is 5 minutes
iris.Get("/cache_control", iris.Cache(func(ctx *iris.Context) {
ctx.HTML(iris.StatusOK, "<h1>Hello!</h1>")
}, -1))
iris.Listen(":8080")
}
```
## v4 -> 5.0.1

View File

@ -19,7 +19,7 @@
<br/>
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%205.0.1%20-blue.svg?style=flat-square" alt="Releases"></a>
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%205.1.0%20-blue.svg?style=flat-square" alt="Releases"></a>
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
@ -53,7 +53,7 @@ Ideally suited for both experienced and novice Developers.
- [20 Minute URL Shortener with Go and Redis - Iris+Docker+Redis](https://www.kieranajp.uk/articles/build-url-shortener-api-golang/) by Kieran Patel
- [The fastest web framework for Go](http://marcoscleison.xyz/the-fastest-web-framework-for-go-in-this-earth/) by Marcos Cleison
- [Iris vs Nginx vs Php vs Nodejs](https://www.ntossapo.me/2016/08/13/nginx-vs-nginx-php-fpm-vs-go-iris-vs-express-with-wrk/) by Tossapon Nuanchuay
- [Iris vs Nginx vs Php vs Nodejs](https://translate.google.com/translate?sl=auto&tl=en&js=y&prev=_t&hl=en&ie=UTF-8&u=http://webcache.googleusercontent.com/search?q=cache:https%3A%2F%2Fwww.ntossapo.me%2F2016%2F08%2F13%2Fnginx-vs-nginx-php-fpm-vs-go-iris-vs-express-with-wrk%2F&edit-text=&act=url) by Tossapon Nuanchuay
## Feature Overview
@ -865,7 +865,7 @@ The second is an article I just found(**3 October 2016**) which compares Iris vs
The results showed that the req / sec iris do best at around 70k-50k, followed by nginx and nginx-php-fpm and nodejs respectively.
The error golang-iris and nginx work equally, followed by the final nginx and php-fpm at a ratio of 1: 1.
You can read the full article [here](https://translate.google.com/translate?sl=auto&tl=en&js=y&prev=_t&hl=en&ie=UTF-8&u=https%3A%2F%2Fwww.ntossapo.me%2F2016%2F08%2F13%2Fnginx-vs-nginx-php-fpm-vs-go-iris-vs-express-with-wrk%2F&edit-text=&act=url).
You can read the full article [here](https://translate.google.com/translate?sl=auto&tl=en&js=y&prev=_t&hl=en&ie=UTF-8&u=http://webcache.googleusercontent.com/search?q=cache:https%3A%2F%2Fwww.ntossapo.me%2F2016%2F08%2F13%2Fnginx-vs-nginx-php-fpm-vs-go-iris-vs-express-with-wrk%2F&edit-text=&act=url).
Testing
@ -876,13 +876,14 @@ I recommend writing your API tests using this new library, [httpexpect](https://
Versioning
------------
Current: **5.0.1**
Current: **5.1.0**
Todo
------------
- [ ] Server-side React render, as requested [here](https://github.com/kataras/iris/issues/503)
- [x] Iris command line improvements, as requested [here](https://github.com/kataras/iris/issues/506)
- [x] Cache service, simple but can make your page renders up to 10 times faster, write your suggestions [here](https://github.com/kataras/iris/issues/513)
Iris is a **Community-Driven** Project, waiting for your suggestions and [feature requests](https://github.com/kataras/iris/issues?utf8=%E2%9C%93&q=label%3A%22feature%20request%22)!
@ -914,7 +915,7 @@ under the Apache Version 2 license found in the [LICENSE file](LICENSE).
[Travis]: http://travis-ci.org/kataras/iris
[License Widget]: https://img.shields.io/badge/license-Apache%20Version%202-E91E63.svg?style=flat-square
[License]: https://github.com/kataras/iris/blob/master/LICENSE
[Release Widget]: https://img.shields.io/badge/release-V5.0.1%20-blue.svg?style=flat-square
[Release Widget]: https://img.shields.io/badge/release-V5.1.0%20-blue.svg?style=flat-square
[Release]: https://github.com/kataras/iris/releases
[Chat Widget]: https://img.shields.io/badge/community-chat%20-00BCD4.svg?style=flat-square
[Chat]: https://kataras.rocket.chat/channel/iris

202
cache.go Normal file
View File

@ -0,0 +1,202 @@
package iris
import (
"sync"
"time"
)
type (
// CacheService is the cache service which caches the whole response body
// it's an interface because you can even set your own cache service inside framework!
CacheService interface {
// Start is the method which the CacheService starts the GC(check if expiration of each entry is passed , if yes then delete it from cache)
Start(time.Duration)
// Cache accepts a route's handler which will cache its response and a time.Duration(int64) which is the expiration duration
Cache(HandlerFunc, time.Duration) HandlerFunc
// Invalidate accepts a cache key (which can be retrieved by 'GetCacheKey') and remove its cache response body
InvalidateCache(string)
}
cacheService struct {
cache map[string]*cacheEntry
mu sync.RWMutex
// keep track of the minimum cache duration of all cache entries, this will be used when gcDuration inside .start() is <=time.Second
lowerExpiration time.Duration
}
cacheEntry struct {
statusCode int
contentType string
value []byte
expires time.Time
}
)
var _ CacheService = &cacheService{}
func newCacheService() *cacheService {
cs := &cacheService{
cache: make(map[string]*cacheEntry),
mu: sync.RWMutex{},
lowerExpiration: time.Second,
}
return cs
}
// Start is not called via newCacheService because
// if gcDuration is <=time.Second
// then start should check and set the gcDuration from the TOTAL CACHE ENTRIES lowest expiration duration
func (cs *cacheService) Start(gcDuration time.Duration) {
if gcDuration <= minimumAllowedCacheDuration {
gcDuration = cs.lowerExpiration
}
// start the timer to check for expirated cache entries
tick := time.Tick(gcDuration)
go func() {
for range tick {
cs.mu.Lock()
now := time.Now()
for k, v := range cs.cache {
if now.After(v.expires) {
delete(cs.cache, k)
}
}
cs.mu.Unlock()
}
}()
}
func (cs *cacheService) get(key string) *cacheEntry {
cs.mu.RLock()
if v, ok := cs.cache[key]; ok {
cs.mu.RUnlock()
return v
}
cs.mu.RUnlock()
return nil
}
// we don't set it to zero value, just 2050 year is enough xD
var expiresNever = time.Date(2050, time.January, 10, 23, 0, 0, 0, time.UTC)
var minimumAllowedCacheDuration = time.Second
func (cs *cacheService) set(key string, statusCode int, contentType string, value []byte, expiration time.Duration) {
if statusCode == 0 {
statusCode = StatusOK
}
if contentType == "" {
contentType = contentText
}
entry := &cacheEntry{contentType: contentType, statusCode: statusCode, value: value}
if expiration <= minimumAllowedCacheDuration {
// Cache function tries to set the expiration(seconds) from header "cache-control" if expiration <=minimumAllowedCacheDuration
// but if cache-control is missing then set it to 5 minutes
expiration = 5 * time.Minute
}
entry.expires = time.Now().Add(expiration)
cs.mu.Lock()
cs.cache[key] = entry
cs.mu.Unlock()
}
func (cs *cacheService) remove(key string) {
cs.mu.Lock()
delete(cs.cache, key)
cs.mu.Unlock()
}
// GetCacheKey returns the cache key(string) from a context
// it's just the RequestURI
func GetCacheKey(ctx *Context) string {
return string(ctx.Request.URI().RequestURI())
}
// InvalidateCache clears the cache body for a specific key(request uri, can be retrieved by GetCacheKey(ctx))
//
// Note that it depends on a station instance's cache service.
// Do not try to call it from default' station if you use the form of app := iris.New(),
// use the app.InvalidateCache instead of iris.InvalidateCache
//
// Example: https://github.com/iris-contrib/examples/tree/master/cache_body
func InvalidateCache(key string) {
Default.CacheService.InvalidateCache(key)
}
// InvalidateCache clears the cache body for a specific key(request uri, can be retrieved by GetCacheKey(ctx))
//
// Note that it depends on a station instance's cache service.
// Do not try to call it from default' station if you use the form of app := iris.New(),
// use the app.Cache instead of iris.Cache
//
// Example: https://github.com/iris-contrib/examples/tree/master/cache_body
func (cs *cacheService) InvalidateCache(key string) {
cs.remove(key)
}
// Cache is just a wrapper for a route's handler which you want to enable body caching
// Usage: iris.Get("/", iris.Cache(func(ctx *iris.Context){
// ctx.WriteString("Hello, world!") // or a template or anything else
// }, time.Duration(10*time.Second))) // duration of expiration
// if <=time.Second then it tries to find it though request header's "cache-control" maxage value
//
// Note that it depends on a station instance's cache service.
// Do not try to call it from default' station if you use the form of app := iris.New(),
// use the app.Cache instead of iris.Cache
//
// Example: https://github.com/iris-contrib/examples/tree/master/cache_body
func Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc {
return Default.CacheService.Cache(bodyHandler, expiration)
}
// Cache is just a wrapper for a route's handler which you want to enable body caching
// Usage: iris.Get("/", iris.Cache(func(ctx *iris.Context){
// ctx.WriteString("Hello, world!") // or a template or anything else
// }, time.Duration(10*time.Second))) // duration of expiration
// if <=time.Second then it tries to find it though request header's "cache-control" maxage value
//
// Note that it depends on a station instance's cache service.
// Do not try to call it from default' station if you use the form of app := iris.New(),
// use the app.Cache instead of iris.Cache
//
// Example: https://github.com/iris-contrib/examples/tree/master/cache_body
func (cs *cacheService) Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc {
// the first time the lowerExpiration should be > time.Second, so:
if cs.lowerExpiration == time.Second {
cs.lowerExpiration = expiration
} else if expiration > time.Second && expiration < cs.lowerExpiration {
cs.lowerExpiration = expiration
}
h := func(ctx *Context) {
key := GetCacheKey(ctx)
if v := cs.get(key); v != nil {
ctx.SetContentType(v.contentType)
ctx.SetStatusCode(v.statusCode)
ctx.RequestCtx.Write(v.value)
return
}
// if not found then serve this:
bodyHandler.Serve(ctx)
if expiration <= minimumAllowedCacheDuration {
// try to set the expiraion from header
expiration = time.Duration(ctx.MaxAge()) * time.Second
}
cType := string(ctx.Response.Header.Peek(contentType))
statusCode := ctx.RequestCtx.Response.StatusCode()
// and set the cache value as its response body in a goroutine, because we want to exit from the route's handler as soon as possible
go cs.set(key, statusCode, cType, ctx.Response.Body(), expiration)
}
return h
}

92
cache_test.go Normal file
View File

@ -0,0 +1,92 @@
package iris_test
import (
"github.com/kataras/iris"
"github.com/kataras/iris/httptest"
"testing"
"time"
)
var testMarkdownContents = `## Hello Markdown from Iris
This is an example of Markdown with Iris
Features
--------
All features of Sundown are supported, including:
* **Compatibility**. The Markdown v1.0.3 test suite passes with
the --tidy option. Without --tidy, the differences are
mostly in whitespace and entity escaping, where blackfriday is
more consistent and cleaner.
* **Common extensions**, including table support, fenced code
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
* **Safety**. Blackfriday is paranoid when parsing, making it safe
to feed untrusted user input without fear of bad things
happening. The test suite stress tests this and there are no
known inputs that make it crash. If you find one, please let me
know and send me the input that does it.
NOTE: "safety" in this context means *runtime safety only*. In order to
protect yourself against JavaScript injection in untrusted content, see
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
* **Fast processing**. It is fast enough to render on-demand in
most web applications without having to cache the output.
* **Thread safety**. You can run multiple parsers in different
goroutines without ill effect. There is no dependence on global
shared state.
* **Minimal dependencies**. Blackfriday only depends on standard
library packages in Go. The source code is pretty
self-contained, so it is easy to add to any project, including
Google App Engine projects.
* **Standards compliant**. Output successfully validates using the
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
[this is a link](https://github.com/kataras/iris) `
// 10 seconds test
// EXAMPLE: https://github.com/iris-contrib/examples/tree/master/cache_body
func TestCacheBody(t *testing.T) {
iris.ResetDefault()
iris.Config.CacheGCDuration = time.Duration(2) * time.Second
iris.Config.IsDevelopment = true
defer iris.Close()
var i = 1
bodyHandler := func(ctx *iris.Context) {
if i%2 == 0 { // only for testing
ctx.SetStatusCode(iris.StatusNoContent)
i++
return
}
i++
ctx.Markdown(iris.StatusOK, testMarkdownContents)
}
expiration := time.Duration(3 * time.Second)
iris.Get("/", iris.Cache(bodyHandler, expiration))
e := httptest.New(iris.Default, t)
expectedBody := iris.SerializeToString("text/markdown", testMarkdownContents)
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedBody)
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedBody) // the cache still son the corrrect body so no StatusNoContent fires
time.Sleep(time.Duration(5) * time.Second) // 4 depends on the CacheGCDuration not the expiration
// the cache should be cleared and now i = 2 then it should run the iris.StatusNoContent with empty body ( we don't use the EmitError)
e.GET("/").Expect().Status(iris.StatusNoContent).Body().Empty()
time.Sleep(time.Duration(5) * time.Second)
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedBody)
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedBody)
}

View File

@ -180,12 +180,12 @@ type Configuration struct {
LoggerPreffix string
// DisableTemplateEngines set to true to disable loading the default template engine (html/template) and disallow the use of iris.UseEngine
// default is false
// Defaults to false
DisableTemplateEngines bool
// IsDevelopment iris will act like a developer, for example
// If true then re-builds the templates on each request
// default is false
// Defaults to false
IsDevelopment bool
// TimeFormat time format for any kind of datetime parsing
@ -193,17 +193,26 @@ type Configuration struct {
// Charset character encoding for various rendering
// used for templates and the rest of the responses
// defaults to "UTF-8"
// Defaults to "UTF-8"
Charset string
// Gzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content
// If you don't want to enable it globaly, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
// defaults to false
// Defaults to false
Gzip bool
// Sessions contains the configs for sessions
Sessions SessionsConfiguration
// CacheGCDuration the cache gc duration,
// when this duration is passed then the cache is checking for each of the cache entries' expiration field
// this clears only the Cached handlers, so if you don't want cache then don't pass your handler arround the Cache wrapper
// it's like the session's GcDuration field
//
// Is if your app is big and not very changable (like a blog) set this duration big , like 5 hours
//
// Defaults to Auto, Auto means that is setted by the lowest expiration of all cach entries
CacheGCDuration time.Duration
// Websocket contains the configs for Websocket's server integration
Websocket WebsocketConfiguration
@ -425,6 +434,20 @@ var (
}
}
// OptionCacheGCDuration ses the cache gc duration,
// when this duration is passed then the cache is checking for each of the cache entries' expiration field
// this clears only the Cached handlers, so if you don't want cache then don't pass your handler arround the Cache wrapper
// it's like the session's GcDuration field
//
// Is if your app is big and not very changable (like a blog) set this duration big , like 5 hours
//
// Defaults to Auto, Auto means that is setted by the lowest expiration of all cach entries
OptionCacheGCDuration = func(val time.Duration) OptionSet {
return func(c *Configuration) {
c.CacheGCDuration = val
}
}
// OptionIsDevelopment iris will act like a developer, for example
// If true then re-builds the templates on each request
// Default is false
@ -542,6 +565,7 @@ func DefaultConfiguration() Configuration {
Charset: DefaultCharset,
Gzip: false,
Sessions: DefaultSessionsConfiguration(),
CacheGCDuration: minimumAllowedCacheDuration,
Websocket: DefaultWebsocketConfiguration(),
Other: options.Options{},
}
@ -552,7 +576,7 @@ func DefaultConfiguration() Configuration {
// first is the cookieName, the session's name (string) ["mysessionsecretcookieid"]
// second enable if you want to decode the cookie's key also
// third is the time which the client's cookie expires
// forth is the cookie length (sessionid) int, defaults to 32, do not change if you don't have any reason to do
// forth is the cookie length (sessionid) int, Defaults to 32, do not change if you don't have any reason to do
// fifth is the gcDuration (time.Duration) when this time passes it removes the unused sessions from the memory until the user come back
// sixth is the DisableSubdomainPersistence which you can set it to true in order dissallow your q subdomains to have access to the session cook
type SessionsConfiguration sessions.Config
@ -608,7 +632,7 @@ var (
}
// OptionSessionsDisableSubdomainPersistence set it to true in order dissallow your q subdomains to have access to the session cookie
// defaults to false
// Defaults to false
OptionSessionsDisableSubdomainPersistence = func(val bool) OptionSet {
return func(c *Configuration) {
c.Sessions.DisableSubdomainPersistence = val
@ -660,7 +684,7 @@ type WebsocketConfiguration struct {
MaxMessageSize int64
// BinaryMessages set it to true in order to denotes binary data messages instead of utf-8 text
// see https://github.com/kataras/iris/issues/387#issuecomment-243006022 for more
// defaults to false
// Defaults to false
BinaryMessages bool
// Endpoint is the path which the websocket server will listen for clients/connections
// Default value is empty string, if you don't set it the Websocket server is disabled.
@ -717,7 +741,7 @@ var (
}
// OptionWebsocketBinaryMessages set it to true in order to denotes binary data messages instead of utf-8 text
// see https://github.com/kataras/iris/issues/387#issuecomment-243006022 for more
// defaults to false
// Defaults to false
OptionWebsocketBinaryMessages = func(val bool) OptionSet {
return func(c *Configuration) {
c.Websocket.BinaryMessages = val

View File

@ -12,6 +12,7 @@ import (
"os"
"path"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
@ -62,6 +63,8 @@ const (
ifModifiedSince = "If-Modified-Since"
// ContentDisposition "Content-Disposition"
contentDisposition = "Content-Disposition"
// CacheControl "Cache-Control"
cacheControl = "Cache-Control"
// stopExecutionPosition used inside the Context, is the number which shows us that the context's middleware manualy stop the execution
stopExecutionPosition = 255
@ -1109,6 +1112,30 @@ func (ctx *Context) SessionDestroy() {
}
var maxAgeExp = regexp.MustCompile(`maxage=(\d+)`)
// MaxAge returns the "cache-control" request header's value
// seconds as int64
// if header not found or parse failed then it returns -1
func (ctx *Context) MaxAge() int64 {
header := ctx.RequestHeader(cacheControl)
if header == "" {
return -1
}
m := maxAgeExp.FindStringSubmatch(header)
if len(m) == 2 {
if v, err := strconv.Atoi(m[1]); err == nil {
return int64(v)
}
}
return -1
}
// InvalidateCache clears the cache manually for this request uri context's handler's route
func (ctx *Context) InvalidateCache() {
ctx.framework.CacheService.InvalidateCache(GetCacheKey(ctx))
}
// Log logs to the iris defined logger
func (ctx *Context) Log(format string, a ...interface{}) {
ctx.framework.Logger.Printf(format, a...)

View File

@ -1,16 +1,6 @@
// Black-box Testing
package iris_test
/*
The most part of the context covered,
the other part contains serving static methods,
find remote ip, GetInt and the view engine rendering(templates)
I am not waiting unexpected behaviors from the rest of the funcs,
so that's all with context's tests.
CONTRIBUTE & DISCUSSION ABOUT TESTS TO: https://github.com/iris-contrib/tests
*/
import (
"encoding/json"
"encoding/xml"

21
iris.go
View File

@ -79,7 +79,7 @@ const (
// IsLongTermSupport flag is true when the below version number is a long-term-support version
IsLongTermSupport = false
// Version is the current version number of the Iris web framework
Version = "5.0.1"
Version = "5.1.0"
banner = ` _____ _
|_ _| (_)
@ -142,6 +142,7 @@ type (
// FrameworkAPI contains the main Iris Public API
FrameworkAPI interface {
MuxAPI
CacheService
Set(...OptionSetter)
Must(error)
Build()
@ -175,6 +176,7 @@ type (
// Implements the FrameworkAPI
Framework struct {
*muxAPI
CacheService
// HTTP Server runtime fields is the iris' defined main server, developer can use unlimited number of servers
// note: they're available after .Build, and .Serve/Listen/ListenTLS/ListenLETSENCRYPT/ListenUNIX
ln net.Listener
@ -193,11 +195,10 @@ type (
sessions sessions.Sessions
serializers serializer.Serializers
templates *templateEngines
// configuration by instance.Logger.Config
Logger *log.Logger
Plugins PluginContainer
Websocket *WebsocketServer
SSH *SSHServer
Logger *log.Logger
Plugins PluginContainer
Websocket *WebsocketServer
SSH *SSHServer
}
)
@ -231,6 +232,8 @@ func New(setters ...OptionSetter) *Framework {
"url": s.URL,
"urlpath": s.Path,
})
// set the cache service
s.CacheService = newCacheService()
}
// websocket & sessions
@ -350,6 +353,9 @@ func (s *Framework) Build() {
s.sessions.Set(s.Config.Sessions, sessions.DisableAutoGC(false))
}
// set the cache gc duration and start service
s.CacheService.Start(s.Config.CacheGCDuration)
if s.Config.Websocket.Endpoint != "" {
// register the websocket server and listen to websocket connections when/if $instance.Websocket.OnConnection called by the dev
s.Websocket.RegisterTo(s, s.Config.Websocket)
@ -1111,6 +1117,9 @@ func SerializeToString(keyOrContentType string, obj interface{}, options ...map[
func (s *Framework) SerializeToString(keyOrContentType string, obj interface{}, options ...map[string]interface{}) string {
res, err := s.serializers.SerializeToString(keyOrContentType, obj, options...)
if err != nil {
if s.Config.IsDevelopment {
s.Logger.Printf("Error on SerializeToString, Key(content-type): %s. Trace: %s\n", keyOrContentType, err)
}
return ""
}
return res