mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
resolve conflicts with current master v11.1.1
Former-commit-id: 659ff392e889f3a8552d7da3d44848f1a364f7b2
This commit is contained in:
commit
736709aa75
5
.github/FUNDING.yml
vendored
Normal file
5
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# patreon: # Replace with a single Patreon username
|
||||||
|
# open_collective: # Replace with a single Open Collective username
|
||||||
|
# ko_fi: # Replace with a single Ko-fi username
|
||||||
|
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
custom: https://iris-go.com/donate # Replace with a single custom sponsorship URL
|
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
2
_examples/cache/simple/main.go
vendored
2
_examples/cache/simple/main.go
vendored
|
@ -61,7 +61,7 @@ func main() {
|
||||||
app.Logger().SetLevel("debug")
|
app.Logger().SetLevel("debug")
|
||||||
app.Get("/", cache.Handler(10*time.Second), writeMarkdown)
|
app.Get("/", cache.Handler(10*time.Second), writeMarkdown)
|
||||||
// saves its content on the first request and serves it instead of re-calculating the content.
|
// saves its content on the first request and serves it instead of re-calculating the content.
|
||||||
// After 10 seconds it will be cleared and resetted.
|
// After 10 seconds it will be cleared and reset.
|
||||||
|
|
||||||
app.Run(iris.Addr(":8080"))
|
app.Run(iris.Addr(":8080"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func main() {
|
||||||
ctx.Writef("Hello from %s", ctx.Path())
|
ctx.Writef("Hello from %s", ctx.Path())
|
||||||
})
|
})
|
||||||
|
|
||||||
// Any custom fields here. Handler and ErrorLog are setted to the server automatically
|
// Any custom fields here. Handler and ErrorLog are set to the server automatically
|
||||||
srv := &http.Server{Addr: ":8080"}
|
srv := &http.Server{Addr: ":8080"}
|
||||||
|
|
||||||
// http://localhost:8080/
|
// http://localhost:8080/
|
||||||
|
|
|
@ -22,10 +22,10 @@ func newApp() *iris.Application {
|
||||||
// it tries to find the language by:
|
// it tries to find the language by:
|
||||||
// ctx.Values().GetString("language")
|
// ctx.Values().GetString("language")
|
||||||
// if that was empty then
|
// if that was empty then
|
||||||
// it tries to find from the URLParameter setted on the configuration
|
// it tries to find from the URLParameter set on the configuration
|
||||||
// if not found then
|
// if not found then
|
||||||
// it tries to find the language by the "language" cookie
|
// it tries to find the language by the "language" cookie
|
||||||
// if didn't found then it it set to the Default setted on the configuration
|
// if didn't found then it it set to the Default set on the configuration
|
||||||
|
|
||||||
// hi is the key, 'iris' is the %s on the .ini file
|
// hi is the key, 'iris' is the %s on the .ini file
|
||||||
// the second parameter is optional
|
// the second parameter is optional
|
||||||
|
|
|
@ -966,7 +966,7 @@ type Context interface {
|
||||||
// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
|
// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
|
||||||
ContentType(cType string)
|
ContentType(cType string)
|
||||||
// GetContentType returns the response writer's header value of "Content-Type"
|
// GetContentType returns the response writer's header value of "Content-Type"
|
||||||
// which may, setted before with the 'ContentType'.
|
// which may, set before with the 'ContentType'.
|
||||||
GetContentType() string
|
GetContentType() string
|
||||||
// GetContentType returns the request's header value of "Content-Type".
|
// GetContentType returns the request's header value of "Content-Type".
|
||||||
GetContentTypeRequested() string
|
GetContentTypeRequested() string
|
||||||
|
@ -1259,7 +1259,7 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// This function may be used in the following cases:
|
// This function may be used in the following cases:
|
||||||
//
|
//
|
||||||
// * if response body is too big (more than iris.LimitRequestBodySize(if setted)).
|
// * if response body is too big (more than iris.LimitRequestBodySize(if set)).
|
||||||
// * if response body is streamed from slow external sources.
|
// * if response body is streamed from slow external sources.
|
||||||
// * if response body must be streamed to the client in chunks.
|
// * if response body must be streamed to the client in chunks.
|
||||||
// (aka `http server push`).
|
// (aka `http server push`).
|
||||||
|
@ -1299,7 +1299,7 @@ type Context interface {
|
||||||
// is being called afterwards, in the same request.
|
// is being called afterwards, in the same request.
|
||||||
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
|
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
|
||||||
//
|
//
|
||||||
// Note that the 'layoutTmplFile' argument can be setted to iris.NoLayout || view.NoLayout
|
// Note that the 'layoutTmplFile' argument can be set to iris.NoLayout || view.NoLayout
|
||||||
// to disable the layout for a specific view render action,
|
// to disable the layout for a specific view render action,
|
||||||
// it disables the engine's configuration's layout property.
|
// it disables the engine's configuration's layout property.
|
||||||
//
|
//
|
||||||
|
|
|
@ -44,7 +44,7 @@ func main() {
|
||||||
//set session values
|
//set session values
|
||||||
s.Set("name", "iris")
|
s.Set("name", "iris")
|
||||||
|
|
||||||
//test if setted here
|
//test if set here
|
||||||
ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name"))
|
ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func main() {
|
||||||
// set session values
|
// set session values
|
||||||
s.Set(key, value)
|
s.Set(key, value)
|
||||||
|
|
||||||
// test if setted here
|
// test if set here
|
||||||
ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key))
|
ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ func main() {
|
||||||
//set session values
|
//set session values
|
||||||
s.Set("name", "iris")
|
s.Set("name", "iris")
|
||||||
|
|
||||||
//test if setted here
|
//test if set here
|
||||||
ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name"))
|
ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ func main() {
|
||||||
// set session values
|
// set session values
|
||||||
s.Set(key, value)
|
s.Set(key, value)
|
||||||
|
|
||||||
// test if setted here
|
// test if set here
|
||||||
ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key))
|
ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ func main() {
|
||||||
//set session values
|
//set session values
|
||||||
s.Set("name", "iris")
|
s.Set("name", "iris")
|
||||||
|
|
||||||
//test if setted here
|
//test if set here
|
||||||
ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name"))
|
ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func main() {
|
||||||
// set session values
|
// set session values
|
||||||
s.Set(key, value)
|
s.Set(key, value)
|
||||||
|
|
||||||
// test if setted here
|
// test if set here
|
||||||
ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key))
|
ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ func main() {
|
||||||
// set session values
|
// set session values
|
||||||
s.Set(key, value)
|
s.Set(key, value)
|
||||||
valueSet := s.Get(key)
|
valueSet := s.Get(key)
|
||||||
// test if setted here
|
// test if set here
|
||||||
ctx.Writef("All ok session value of the '%s' is: %v", key, valueSet)
|
ctx.Writef("All ok session value of the '%s' is: %v", key, valueSet)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ func main() {
|
||||||
app.Get("/set", func(ctx iris.Context) {
|
app.Get("/set", func(ctx iris.Context) {
|
||||||
s := sess.Start(ctx)
|
s := sess.Start(ctx)
|
||||||
s.SetFlash("name", "iris")
|
s.SetFlash("name", "iris")
|
||||||
ctx.Writef("Message setted, is available for the next request")
|
ctx.Writef("Message set, is available for the next request")
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Get("/get", func(ctx iris.Context) {
|
app.Get("/get", func(ctx iris.Context) {
|
||||||
|
|
|
@ -39,8 +39,8 @@ func newApp() *iris.Application {
|
||||||
s := mySessions.Start(ctx)
|
s := mySessions.Start(ctx)
|
||||||
s.Set("name", "iris")
|
s.Set("name", "iris")
|
||||||
|
|
||||||
//test if setted here
|
//test if set here
|
||||||
ctx.Writef("All ok session setted to: %s", s.GetString("name"))
|
ctx.Writef("All ok session set to: %s", s.GetString("name"))
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Get("/get", func(ctx iris.Context) {
|
app.Get("/get", func(ctx iris.Context) {
|
||||||
|
|
|
@ -14,14 +14,14 @@ func TestSessionsEncodeDecode(t *testing.T) {
|
||||||
es := e.GET("/set").Expect()
|
es := e.GET("/set").Expect()
|
||||||
es.Status(iris.StatusOK)
|
es.Status(iris.StatusOK)
|
||||||
es.Cookies().NotEmpty()
|
es.Cookies().NotEmpty()
|
||||||
es.Body().Equal("All ok session setted to: iris")
|
es.Body().Equal("All ok session set to: iris")
|
||||||
|
|
||||||
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: iris")
|
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: iris")
|
||||||
// delete and re-get
|
// delete and re-get
|
||||||
e.GET("/delete").Expect().Status(iris.StatusOK)
|
e.GET("/delete").Expect().Status(iris.StatusOK)
|
||||||
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ")
|
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ")
|
||||||
// set, clear and re-get
|
// set, clear and re-get
|
||||||
e.GET("/set").Expect().Body().Equal("All ok session setted to: iris")
|
e.GET("/set").Expect().Body().Equal("All ok session set to: iris")
|
||||||
e.GET("/clear").Expect().Status(iris.StatusOK)
|
e.GET("/clear").Expect().Status(iris.StatusOK)
|
||||||
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ")
|
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ")
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ func main() {
|
||||||
s := sess.Start(ctx)
|
s := sess.Start(ctx)
|
||||||
s.Set("name", "iris")
|
s.Set("name", "iris")
|
||||||
|
|
||||||
//test if setted here.
|
//test if set here.
|
||||||
ctx.Writef("All ok session setted to: %s", s.GetString("name"))
|
ctx.Writef("All ok session set to: %s", s.GetString("name"))
|
||||||
|
|
||||||
// Set will set the value as-it-is,
|
// Set will set the value as-it-is,
|
||||||
// if it's a slice or map
|
// if it's a slice or map
|
||||||
|
|
|
@ -29,7 +29,7 @@ func main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Get("/", func(ctx iris.Context) {
|
app.Get("/", func(ctx iris.Context) {
|
||||||
ctx.ViewData("BodyMessage", "a sample text here... setted by the route handler")
|
ctx.ViewData("BodyMessage", "a sample text here... set by the route handler")
|
||||||
if err := ctx.View("index.html"); err != nil {
|
if err := ctx.View("index.html"); err != nil {
|
||||||
ctx.Application().Logger().Infof(err.Error())
|
ctx.Application().Logger().Infof(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func main() {
|
||||||
|
|
||||||
app.Get("/about", func(ctx iris.Context) {
|
app.Get("/about", func(ctx iris.Context) {
|
||||||
ctx.ViewData("Title", "My About Page")
|
ctx.ViewData("Title", "My About Page")
|
||||||
ctx.ViewData("BodyMessage", "about text here... setted by the route handler")
|
ctx.ViewData("BodyMessage", "about text here... set by the route handler")
|
||||||
|
|
||||||
// same file, just to keep things simple.
|
// same file, just to keep things simple.
|
||||||
if err := ctx.View("index.html"); err != nil {
|
if err := ctx.View("index.html"); err != nil {
|
||||||
|
|
4
cache/browser_test.go
vendored
4
cache/browser_test.go
vendored
|
@ -91,13 +91,13 @@ func TestETag(t *testing.T) {
|
||||||
e := httptest.New(t, app)
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
r := e.GET("/").Expect().Status(httptest.StatusOK)
|
r := e.GET("/").Expect().Status(httptest.StatusOK)
|
||||||
r.Header("ETag").Equal("/") // test if header setted.
|
r.Header("ETag").Equal("/") // test if header set.
|
||||||
r.Body().Equal("_")
|
r.Body().Equal("_")
|
||||||
|
|
||||||
e.GET("/").WithHeader("ETag", "/").WithHeader("If-None-Match", "/").Expect().
|
e.GET("/").WithHeader("ETag", "/").WithHeader("If-None-Match", "/").Expect().
|
||||||
Status(httptest.StatusNotModified).Body().Equal("") // browser is responsible, no the test engine.
|
Status(httptest.StatusNotModified).Body().Equal("") // browser is responsible, no the test engine.
|
||||||
|
|
||||||
r = e.GET("/").Expect().Status(httptest.StatusOK)
|
r = e.GET("/").Expect().Status(httptest.StatusOK)
|
||||||
r.Header("ETag").Equal("/") // test if header setted.
|
r.Header("ETag").Equal("/") // test if header set.
|
||||||
r.Body().Equal("__")
|
r.Body().Equal("__")
|
||||||
}
|
}
|
||||||
|
|
2
cache/cfg/cfg.go
vendored
2
cache/cfg/cfg.go
vendored
|
@ -16,7 +16,7 @@ var (
|
||||||
RequestCacheTimeout = 5 * time.Second
|
RequestCacheTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// NoCacheHeader is the static header key which is setted to the response when NoCache is called,
|
// NoCacheHeader is the static header key which is set to the response when NoCache is called,
|
||||||
// used inside nethttp and fhttp Skippers.
|
// used inside nethttp and fhttp Skippers.
|
||||||
var NoCacheHeader = "X-No-Cache"
|
var NoCacheHeader = "X-No-Cache"
|
||||||
|
|
||||||
|
|
2
cache/entry/response.go
vendored
2
cache/entry/response.go
vendored
|
@ -3,7 +3,7 @@ package entry
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
// Response is the cached response will be send to the clients
|
// Response is the cached response will be send to the clients
|
||||||
// its fields setted at runtime on each of the non-cached executions
|
// its fields set at runtime on each of the non-cached executions
|
||||||
// non-cached executions = first execution, and each time after
|
// non-cached executions = first execution, and each time after
|
||||||
// cache expiration datetime passed.
|
// cache expiration datetime passed.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
|
2
cache/uri/uribuilder.go
vendored
2
cache/uri/uribuilder.go
vendored
|
@ -62,7 +62,7 @@ func (r *URIBuilder) ContentType(s string) *URIBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the full url which should be passed to get a cache entry response back
|
// String returns the full url which should be passed to get a cache entry response back
|
||||||
// (it could be setted by server too but we need some client-freedom on the requested key)
|
// (it could be set by server too but we need some client-freedom on the requested key)
|
||||||
// in order to be sure that the registered cache entries are unique among different clients with the same key
|
// in order to be sure that the registered cache entries are unique among different clients with the same key
|
||||||
// note1: we do it manually*,
|
// note1: we do it manually*,
|
||||||
// note2: on fasthttp that is not required because the query args added as expected but we will use it there too to be align with net/http
|
// note2: on fasthttp that is not required because the query args added as expected but we will use it there too to be align with net/http
|
||||||
|
|
|
@ -588,7 +588,7 @@ func (tc TunnelingConfiguration) createTunnel(tunnelAPIRequest ngrokTunnel, publ
|
||||||
// these can be passed via options also, look at the top of this file(configuration.go).
|
// these can be passed via options also, look at the top of this file(configuration.go).
|
||||||
// Configuration is a valid OptionSetter.
|
// Configuration is a valid OptionSetter.
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
// vhost is private and setted only with .Run method, it cannot be changed after the first set.
|
// vhost is private and set only with .Run method, it cannot be changed after the first set.
|
||||||
// It can be retrieved by the context if needed (i.e router for subdomains)
|
// It can be retrieved by the context if needed (i.e router for subdomains)
|
||||||
vhost string
|
vhost string
|
||||||
|
|
||||||
|
@ -609,11 +609,11 @@ type Configuration struct {
|
||||||
// Defaults to an empty slice.
|
// Defaults to an empty slice.
|
||||||
IgnoreServerErrors []string `json:"ignoreServerErrors,omitempty" yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`
|
IgnoreServerErrors []string `json:"ignoreServerErrors,omitempty" yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`
|
||||||
|
|
||||||
// DisableStartupLog if setted to true then it turns off the write banner on server startup.
|
// DisableStartupLog if set to true then it turns off the write banner on server startup.
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
DisableStartupLog bool `json:"disableStartupLog,omitempty" yaml:"DisableStartupLog" toml:"DisableStartupLog"`
|
DisableStartupLog bool `json:"disableStartupLog,omitempty" yaml:"DisableStartupLog" toml:"DisableStartupLog"`
|
||||||
// DisableInterruptHandler if setted to true then it disables the automatic graceful server shutdown
|
// DisableInterruptHandler if set to true then it disables the automatic graceful server shutdown
|
||||||
// when control/cmd+C pressed.
|
// when control/cmd+C pressed.
|
||||||
// Turn this to true if you're planning to handle this by your own via a custom host.Task.
|
// Turn this to true if you're planning to handle this by your own via a custom host.Task.
|
||||||
//
|
//
|
||||||
|
@ -662,11 +662,11 @@ type Configuration struct {
|
||||||
FireMethodNotAllowed bool `json:"fireMethodNotAllowed,omitempty" yaml:"FireMethodNotAllowed" toml:"FireMethodNotAllowed"`
|
FireMethodNotAllowed bool `json:"fireMethodNotAllowed,omitempty" yaml:"FireMethodNotAllowed" toml:"FireMethodNotAllowed"`
|
||||||
|
|
||||||
// DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
|
// DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
|
||||||
// If setted to true then it
|
// If set to true then it
|
||||||
// disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
|
// disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
|
||||||
//
|
//
|
||||||
// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
|
// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
|
||||||
// if this field setted to true then a new buffer will be created to read from and the request body.
|
// if this field set to true then a new buffer will be created to read from and the request body.
|
||||||
// The body will not be changed and existing data before the
|
// The body will not be changed and existing data before the
|
||||||
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
||||||
DisableBodyConsumptionOnUnmarshal bool `json:"disableBodyConsumptionOnUnmarshal,omitempty" yaml:"DisableBodyConsumptionOnUnmarshal" toml:"DisableBodyConsumptionOnUnmarshal"`
|
DisableBodyConsumptionOnUnmarshal bool `json:"disableBodyConsumptionOnUnmarshal,omitempty" yaml:"DisableBodyConsumptionOnUnmarshal" toml:"DisableBodyConsumptionOnUnmarshal"`
|
||||||
|
@ -678,7 +678,7 @@ type Configuration struct {
|
||||||
// By-default a custom http error handler will be fired when "context.StatusCode(code)" called,
|
// By-default a custom http error handler will be fired when "context.StatusCode(code)" called,
|
||||||
// code should be equal with the result of the the `context.StatusCodeNotSuccessful` in order to be received as an "http error handler".
|
// code should be equal with the result of the the `context.StatusCodeNotSuccessful` in order to be received as an "http error handler".
|
||||||
//
|
//
|
||||||
// Developer may want this option to setted as true in order to manually call the
|
// Developer may want this option to set as true in order to manually call the
|
||||||
// error handlers when needed via "context#FireStatusCode(< 200 || >= 400)".
|
// error handlers when needed via "context#FireStatusCode(< 200 || >= 400)".
|
||||||
// HTTP Custom error handlers are being registered via app.OnErrorCode(code, handler)".
|
// HTTP Custom error handlers are being registered via app.OnErrorCode(code, handler)".
|
||||||
//
|
//
|
||||||
|
@ -807,7 +807,7 @@ func (c Configuration) GetFireMethodNotAllowed() bool {
|
||||||
// is disabled.
|
// is disabled.
|
||||||
//
|
//
|
||||||
// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
|
// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
|
||||||
// if this field setted to true then a new buffer will be created to read from and the request body.
|
// if this field set to true then a new buffer will be created to read from and the request body.
|
||||||
// The body will not be changed and existing data before the
|
// The body will not be changed and existing data before the
|
||||||
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
||||||
func (c Configuration) GetDisableBodyConsumptionOnUnmarshal() bool {
|
func (c Configuration) GetDisableBodyConsumptionOnUnmarshal() bool {
|
||||||
|
|
|
@ -61,7 +61,7 @@ func TestConfigurationOptions(t *testing.T) {
|
||||||
t.Fatalf("Expected configuration DisableStartupLog to be: %#v but got: %#v", disableBanner, got)
|
t.Fatalf("Expected configuration DisableStartupLog to be: %#v but got: %#v", disableBanner, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check if other default values are setted (should be setted automatically)
|
// now check if other default values are set (should be set automatically)
|
||||||
|
|
||||||
expected := DefaultConfiguration()
|
expected := DefaultConfiguration()
|
||||||
expected.Charset = charset
|
expected.Charset = charset
|
||||||
|
|
|
@ -41,7 +41,7 @@ type ConfigurationReadOnly interface {
|
||||||
// is disabled.
|
// is disabled.
|
||||||
//
|
//
|
||||||
// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
|
// By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
|
||||||
// if this field setted to true then a new buffer will be created to read from and the request body.
|
// if this field set to true then a new buffer will be created to read from and the request body.
|
||||||
// The body will not be changed and existing data before the
|
// The body will not be changed and existing data before the
|
||||||
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
// context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
|
||||||
GetDisableBodyConsumptionOnUnmarshal() bool
|
GetDisableBodyConsumptionOnUnmarshal() bool
|
||||||
|
|
|
@ -369,7 +369,7 @@ type Context interface {
|
||||||
// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
|
// ContentType sets the response writer's header key "Content-Type" to the 'cType'.
|
||||||
ContentType(cType string)
|
ContentType(cType string)
|
||||||
// GetContentType returns the response writer's header value of "Content-Type"
|
// GetContentType returns the response writer's header value of "Content-Type"
|
||||||
// which may, setted before with the 'ContentType'.
|
// which may, set before with the 'ContentType'.
|
||||||
GetContentType() string
|
GetContentType() string
|
||||||
// GetContentType returns the request's header value of "Content-Type".
|
// GetContentType returns the request's header value of "Content-Type".
|
||||||
GetContentTypeRequested() string
|
GetContentTypeRequested() string
|
||||||
|
@ -669,7 +669,7 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// This function may be used in the following cases:
|
// This function may be used in the following cases:
|
||||||
//
|
//
|
||||||
// * if response body is too big (more than iris.LimitRequestBodySize(if setted)).
|
// * if response body is too big (more than iris.LimitRequestBodySize(if set)).
|
||||||
// * if response body is streamed from slow external sources.
|
// * if response body is streamed from slow external sources.
|
||||||
// * if response body must be streamed to the client in chunks.
|
// * if response body must be streamed to the client in chunks.
|
||||||
// (aka `http server push`).
|
// (aka `http server push`).
|
||||||
|
@ -709,7 +709,7 @@ type Context interface {
|
||||||
// is being called afterwards, in the same request.
|
// is being called afterwards, in the same request.
|
||||||
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
|
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
|
||||||
//
|
//
|
||||||
// Note that the 'layoutTmplFile' argument can be setted to iris.NoLayout || view.NoLayout
|
// Note that the 'layoutTmplFile' argument can be set to iris.NoLayout || view.NoLayout
|
||||||
// to disable the layout for a specific view render action,
|
// to disable the layout for a specific view render action,
|
||||||
// it disables the engine's configuration's layout property.
|
// it disables the engine's configuration's layout property.
|
||||||
//
|
//
|
||||||
|
@ -1762,7 +1762,7 @@ func (ctx *context) ContentType(cType string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContentType returns the response writer's header value of "Content-Type"
|
// GetContentType returns the response writer's header value of "Content-Type"
|
||||||
// which may, setted before with the 'ContentType'.
|
// which may, set before with the 'ContentType'.
|
||||||
func (ctx *context) GetContentType() string {
|
func (ctx *context) GetContentType() string {
|
||||||
return ctx.writer.Header().Get(ContentTypeHeaderKey)
|
return ctx.writer.Header().Get(ContentTypeHeaderKey)
|
||||||
}
|
}
|
||||||
|
@ -2597,7 +2597,7 @@ func (ctx *context) WriteWithExpiration(body []byte, modtime time.Time) (int, er
|
||||||
//
|
//
|
||||||
// This function may be used in the following cases:
|
// This function may be used in the following cases:
|
||||||
//
|
//
|
||||||
// * if response body is too big (more than iris.LimitRequestBodySize(if setted)).
|
// * if response body is too big (more than iris.LimitRequestBodySize(if set)).
|
||||||
// * if response body is streamed from slow external sources.
|
// * if response body is streamed from slow external sources.
|
||||||
// * if response body must be streamed to the client in chunks.
|
// * if response body must be streamed to the client in chunks.
|
||||||
// (aka `http server push`).
|
// (aka `http server push`).
|
||||||
|
@ -2714,7 +2714,7 @@ const (
|
||||||
// is being called afterwards, in the same request.
|
// is being called afterwards, in the same request.
|
||||||
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
|
// Useful when need to set or/and change a layout based on the previous handlers in the chain.
|
||||||
//
|
//
|
||||||
// Note that the 'layoutTmplFile' argument can be setted to iris.NoLayout || view.NoLayout || context.NoLayout
|
// Note that the 'layoutTmplFile' argument can be set to iris.NoLayout || view.NoLayout || context.NoLayout
|
||||||
// to disable the layout for a specific view render action,
|
// to disable the layout for a specific view render action,
|
||||||
// it disables the engine's configuration's layout property.
|
// it disables the engine's configuration's layout property.
|
||||||
//
|
//
|
||||||
|
|
|
@ -18,7 +18,7 @@ type compressionPool struct {
|
||||||
// |GZIP raw io.writer, our gzip response writer will use that. |
|
// |GZIP raw io.writer, our gzip response writer will use that. |
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
|
||||||
// default writer pool with Compressor's level setted to -1
|
// default writer pool with Compressor's level set to -1
|
||||||
var gzipPool = &compressionPool{Level: -1}
|
var gzipPool = &compressionPool{Level: -1}
|
||||||
|
|
||||||
// acquireGzipWriter prepares a gzip writer and returns it.
|
// acquireGzipWriter prepares a gzip writer and returns it.
|
||||||
|
|
|
@ -70,7 +70,7 @@ type ResponseWriter interface {
|
||||||
|
|
||||||
// SetBeforeFlush registers the unique callback which called exactly before the response is flushed to the client.
|
// SetBeforeFlush registers the unique callback which called exactly before the response is flushed to the client.
|
||||||
SetBeforeFlush(cb func())
|
SetBeforeFlush(cb func())
|
||||||
// GetBeforeFlush returns (not execute) the before flush callback, or nil if not setted by SetBeforeFlush.
|
// GetBeforeFlush returns (not execute) the before flush callback, or nil if not set by SetBeforeFlush.
|
||||||
GetBeforeFlush() func()
|
GetBeforeFlush() func()
|
||||||
// FlushResponse should be called only once before EndResponse.
|
// FlushResponse should be called only once before EndResponse.
|
||||||
// it tries to send the status code if not sent already
|
// it tries to send the status code if not sent already
|
||||||
|
|
|
@ -155,7 +155,7 @@ var RequestTransactionScope = TransactionScopeFunc(func(maybeErr TransactionErrR
|
||||||
|
|
||||||
// we need to register a beforeResponseFlush event here in order
|
// we need to register a beforeResponseFlush event here in order
|
||||||
// to execute last the FireStatusCode
|
// to execute last the FireStatusCode
|
||||||
// (which will reset the whole response's body, status code and headers setted from normal flow or other transactions too)
|
// (which will reset the whole response's body, status code and headers set from normal flow or other transactions too)
|
||||||
ctx.ResponseWriter().SetBeforeFlush(func() {
|
ctx.ResponseWriter().SetBeforeFlush(func() {
|
||||||
// we need to re-take the context's response writer
|
// we need to re-take the context's response writer
|
||||||
// because inside here the response writer is changed to the original's
|
// because inside here the response writer is changed to the original's
|
||||||
|
|
|
@ -582,7 +582,7 @@ func (e Entry) BoolDefault(def bool) (bool, error) {
|
||||||
// respects the immutable.
|
// respects the immutable.
|
||||||
func (e Entry) Value() interface{} {
|
func (e Entry) Value() interface{} {
|
||||||
if e.immutable {
|
if e.immutable {
|
||||||
// take its value, no pointer even if setted with a reference.
|
// take its value, no pointer even if set with a reference.
|
||||||
vv := reflect.Indirect(reflect.ValueOf(e.ValueRaw))
|
vv := reflect.Indirect(reflect.ValueOf(e.ValueRaw))
|
||||||
|
|
||||||
// return copy of that slice
|
// return copy of that slice
|
||||||
|
|
|
@ -127,7 +127,7 @@ func ResolveAddr(addr string) string {
|
||||||
if a[portIdx:] == ":https" {
|
if a[portIdx:] == ":https" {
|
||||||
a = defaultServerHostname + ":443"
|
a = defaultServerHostname + ":443"
|
||||||
} else {
|
} else {
|
||||||
// if contains only :port ,then the : is the first letter, so we dont have setted a hostname, lets set it
|
// if contains only :port ,then the : is the first letter, so we dont have set a hostname, lets set it
|
||||||
a = defaultServerHostname + a
|
a = defaultServerHostname + a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (ch *ErrorCodeHandler) Fire(ctx context.Context) {
|
||||||
// if we can reset the body
|
// if we can reset the body
|
||||||
if w, ok := ctx.IsRecording(); ok {
|
if w, ok := ctx.IsRecording(); ok {
|
||||||
if statusCodeSuccessful(w.StatusCode()) { // if not an error status code
|
if statusCodeSuccessful(w.StatusCode()) { // if not an error status code
|
||||||
w.WriteHeader(ch.StatusCode) // then set it manually here, otherwise it should be setted via ctx.StatusCode(...)
|
w.WriteHeader(ch.StatusCode) // then set it manually here, otherwise it should be set via ctx.StatusCode(...)
|
||||||
}
|
}
|
||||||
// reset if previous content and it's recorder, keep the status code.
|
// reset if previous content and it's recorder, keep the status code.
|
||||||
w.ClearHeaders()
|
w.ClearHeaders()
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (c Configuration) Set(main *Configuration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// URL if setted then it sets the httptest's BaseURL.
|
// URL if set then it sets the httptest's BaseURL.
|
||||||
// Defaults to empty string "".
|
// Defaults to empty string "".
|
||||||
URL = func(schemeAndHost string) OptionSet {
|
URL = func(schemeAndHost string) OptionSet {
|
||||||
return func(c *Configuration) {
|
return func(c *Configuration) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ func (p *ParamParser) appendErr(format string, a ...interface{}) {
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultParamErrorCode is the default http error code, 404 not found,
|
// DefaultParamErrorCode is the default http error code, 404 not found,
|
||||||
// per-parameter. An error code can be setted via
|
// per-parameter. An error code can be set via
|
||||||
// the "else" keyword inside a route's path.
|
// the "else" keyword inside a route's path.
|
||||||
DefaultParamErrorCode = 404
|
DefaultParamErrorCode = 404
|
||||||
)
|
)
|
||||||
|
|
|
@ -102,7 +102,7 @@ func New(c Config) context.Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if not default language setted then set to the first of the i.config.Languages
|
// if not default language set then set to the first of the i.config.Languages
|
||||||
if c.Default == "" {
|
if c.Default == "" {
|
||||||
c.Default = firstlanguage
|
c.Default = firstlanguage
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ type Config struct {
|
||||||
// the contents with `ctx.Values().Get(MessageContextKey)`
|
// the contents with `ctx.Values().Get(MessageContextKey)`
|
||||||
// and if available then these contents will be
|
// and if available then these contents will be
|
||||||
// appended as part of the logs (with `%v`, in order to be able to set a struct too),
|
// appended as part of the logs (with `%v`, in order to be able to set a struct too),
|
||||||
// if Columns field was setted to true then
|
// if Columns field was set to true then
|
||||||
// a new column will be added named 'Message'.
|
// a new column will be added named 'Message'.
|
||||||
//
|
//
|
||||||
// Defaults to empty.
|
// Defaults to empty.
|
||||||
|
@ -59,7 +59,7 @@ type Config struct {
|
||||||
// the contents with `ctx.Values().Get(MessageHeaderKey)`
|
// the contents with `ctx.Values().Get(MessageHeaderKey)`
|
||||||
// and if available then these contents will be
|
// and if available then these contents will be
|
||||||
// appended as part of the logs (with `%v`, in order to be able to set a struct too),
|
// appended as part of the logs (with `%v`, in order to be able to set a struct too),
|
||||||
// if Columns field was setted to true then
|
// if Columns field was set to true then
|
||||||
// a new column will be added named 'HeaderMessage'.
|
// a new column will be added named 'HeaderMessage'.
|
||||||
//
|
//
|
||||||
// Defaults to empty.
|
// Defaults to empty.
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Encoding interface {
|
||||||
// Encode the cookie value if not nil.
|
// Encode the cookie value if not nil.
|
||||||
// Should accept as first argument the cookie name (config.Name)
|
// Should accept as first argument the cookie name (config.Name)
|
||||||
// as second argument the server's generated session id.
|
// as second argument the server's generated session id.
|
||||||
// Should return the new session id, if error the session id setted to empty which is invalid.
|
// Should return the new session id, if error the session id set to empty which is invalid.
|
||||||
//
|
//
|
||||||
// Note: Errors are not printed, so you have to know what you're doing,
|
// Note: Errors are not printed, so you have to know what you're doing,
|
||||||
// and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
|
// and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
|
||||||
|
@ -49,10 +49,10 @@ type (
|
||||||
Cookie string
|
Cookie string
|
||||||
|
|
||||||
// CookieSecureTLS set to true if server is running over TLS
|
// CookieSecureTLS set to true if server is running over TLS
|
||||||
// and you need the session's cookie "Secure" field to be setted true.
|
// and you need the session's cookie "Secure" field to be set true.
|
||||||
//
|
//
|
||||||
// Note: The user should fill the Decode configuration field in order for this to work.
|
// Note: The user should fill the Decode configuation field in order for this to work.
|
||||||
// Recommendation: You don't need this to be setted to true, just fill the Encode and Decode fields
|
// Recommendation: You don't need this to be set to true, just fill the Encode and Decode fields
|
||||||
// with a third-party library like secure cookie, example is provided at the _examples folder.
|
// with a third-party library like secure cookie, example is provided at the _examples folder.
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
|
@ -69,7 +69,7 @@ type (
|
||||||
// Encode the cookie value if not nil.
|
// Encode the cookie value if not nil.
|
||||||
// Should accept as first argument the cookie name (config.Cookie)
|
// Should accept as first argument the cookie name (config.Cookie)
|
||||||
// as second argument the server's generated session id.
|
// as second argument the server's generated session id.
|
||||||
// Should return the new session id, if error the session id setted to empty which is invalid.
|
// Should return the new session id, if error the session id set to empty which is invalid.
|
||||||
//
|
//
|
||||||
// Note: Errors are not printed, so you have to know what you're doing,
|
// Note: Errors are not printed, so you have to know what you're doing,
|
||||||
// and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
|
// and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
|
||||||
|
|
331
sessions/sessiondb/redis/service/service.go
Normal file
331
sessions/sessiondb/redis/service/service.go
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gomodule/redigo/redis"
|
||||||
|
"github.com/kataras/iris/core/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrRedisClosed an error with message 'Redis is already closed'
|
||||||
|
ErrRedisClosed = errors.New("Redis is already closed")
|
||||||
|
// ErrKeyNotFound an error with message 'Key $thekey doesn't found'
|
||||||
|
ErrKeyNotFound = errors.New("Key '%s' doesn't found")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service the Redis service, contains the config and the redis pool
|
||||||
|
type Service struct {
|
||||||
|
// Connected is true when the Service has already connected
|
||||||
|
Connected bool
|
||||||
|
// Config the redis config for this redis
|
||||||
|
Config *Config
|
||||||
|
pool *redis.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingPong sends a ping and receives a pong, if no pong received then returns false and filled error
|
||||||
|
func (r *Service) PingPong() (bool, error) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
msg, err := c.Do("PING")
|
||||||
|
if err != nil || msg == nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return (msg == "PONG"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseConnection closes the redis connection
|
||||||
|
func (r *Service) CloseConnection() error {
|
||||||
|
if r.pool != nil {
|
||||||
|
return r.pool.Close()
|
||||||
|
}
|
||||||
|
return ErrRedisClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets a key-value to the redis store.
|
||||||
|
// The expiration is set by the MaxAgeSeconds.
|
||||||
|
func (r *Service) Set(key string, value interface{}, secondsLifetime int64) (err error) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
if c.Err() != nil {
|
||||||
|
return c.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// if has expiration, then use the "EX" to delete the key automatically.
|
||||||
|
if secondsLifetime > 0 {
|
||||||
|
_, err = c.Do("SETEX", r.Config.Prefix+key, secondsLifetime, value)
|
||||||
|
} else {
|
||||||
|
_, err = c.Do("SET", r.Config.Prefix+key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns value, err by its key
|
||||||
|
//returns nil and a filled error if something bad happened.
|
||||||
|
func (r *Service) Get(key string) (interface{}, error) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
if err := c.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
redisVal, err := c.Do("GET", r.Config.Prefix+key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if redisVal == nil {
|
||||||
|
return nil, ErrKeyNotFound.Format(key)
|
||||||
|
}
|
||||||
|
return redisVal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TTL returns the seconds to expire, if the key has expiration and error if action failed.
|
||||||
|
// Read more at: https://redis.io/commands/ttl
|
||||||
|
func (r *Service) TTL(key string) (seconds int64, hasExpiration bool, found bool) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
redisVal, err := c.Do("TTL", r.Config.Prefix+key)
|
||||||
|
if err != nil {
|
||||||
|
return -2, false, false
|
||||||
|
}
|
||||||
|
seconds = redisVal.(int64)
|
||||||
|
// if -1 means the key has unlimited life time.
|
||||||
|
hasExpiration = seconds > -1
|
||||||
|
// if -2 means key does not exist.
|
||||||
|
found = !(c.Err() != nil || seconds == -2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Service) updateTTLConn(c redis.Conn, key string, newSecondsLifeTime int64) error {
|
||||||
|
reply, err := c.Do("EXPIRE", r.Config.Prefix+key, newSecondsLifeTime)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://redis.io/commands/expire#return-value
|
||||||
|
//
|
||||||
|
// 1 if the timeout was set.
|
||||||
|
// 0 if key does not exist.
|
||||||
|
if hadTTLOrExists, ok := reply.(int); ok {
|
||||||
|
if hadTTLOrExists == 1 {
|
||||||
|
return nil
|
||||||
|
} else if hadTTLOrExists == 0 {
|
||||||
|
return fmt.Errorf("unable to update expiration, the key '%s' was stored without ttl", key)
|
||||||
|
} // do not check for -1.
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTTL will update the ttl of a key.
|
||||||
|
// Using the "EXPIRE" command.
|
||||||
|
// Read more at: https://redis.io/commands/expire#refreshing-expires
|
||||||
|
func (r *Service) UpdateTTL(key string, newSecondsLifeTime int64) error {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
err := c.Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.updateTTLConn(c, key, newSecondsLifeTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTTLMany like `UpdateTTL` but for all keys starting with that "prefix",
|
||||||
|
// it is a bit faster operation if you need to update all sessions keys (although it can be even faster if we used hash but this will limit other features),
|
||||||
|
// look the `sessions/Database#OnUpdateExpiration` for example.
|
||||||
|
func (r *Service) UpdateTTLMany(prefix string, newSecondsLifeTime int64) error {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
if err := c.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
keys, err := r.getKeysConn(c, prefix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if err = r.updateTTLConn(c, key, newSecondsLifeTime); err != nil { // fail on first error.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll returns all redis entries using the "SCAN" command (2.8+).
|
||||||
|
func (r *Service) GetAll() (interface{}, error) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
if err := c.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
redisVal, err := c.Do("SCAN", 0) // 0 -> cursor
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if redisVal == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return redisVal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Service) getKeysConn(c redis.Conn, prefix string) ([]string, error) {
|
||||||
|
if err := c.Send("SCAN", 0, "MATCH", r.Config.Prefix+prefix+"*", "COUNT", 9999999999); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := c.Receive()
|
||||||
|
if err != nil || reply == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// it returns []interface, with two entries, the first one is "0" and the second one is a slice of the keys as []interface{uint8....}.
|
||||||
|
|
||||||
|
if keysInterface, ok := reply.([]interface{}); ok {
|
||||||
|
if len(keysInterface) == 2 {
|
||||||
|
// take the second, it must contain the slice of keys.
|
||||||
|
if keysSliceAsBytes, ok := keysInterface[1].([]interface{}); ok {
|
||||||
|
keys := make([]string, len(keysSliceAsBytes), len(keysSliceAsBytes))
|
||||||
|
for i, k := range keysSliceAsBytes {
|
||||||
|
keys[i] = fmt.Sprintf("%s", k)[len(r.Config.Prefix):]
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeys returns all redis keys using the "SCAN" with MATCH command.
|
||||||
|
// Read more at: https://redis.io/commands/scan#the-match-option.
|
||||||
|
func (r *Service) GetKeys(prefix string) ([]string, error) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
if err := c.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.getKeysConn(c, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes returns value, err by its key
|
||||||
|
// you can use utils.Deserialize((.GetBytes("yourkey"),&theobject{})
|
||||||
|
//returns nil and a filled error if something wrong happens
|
||||||
|
func (r *Service) GetBytes(key string) ([]byte, error) {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
if err := c.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
redisVal, err := c.Do("GET", r.Config.Prefix+key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if redisVal == nil {
|
||||||
|
return nil, ErrKeyNotFound.Format(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return redis.Bytes(redisVal, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes redis entry by specific key
|
||||||
|
func (r *Service) Delete(key string) error {
|
||||||
|
c := r.pool.Get()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
_, err := c.Do("DEL", r.Config.Prefix+key)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func dial(network string, addr string, pass string) (redis.Conn, error) {
|
||||||
|
if network == "" {
|
||||||
|
network = DefaultRedisNetwork
|
||||||
|
}
|
||||||
|
if addr == "" {
|
||||||
|
addr = DefaultRedisAddr
|
||||||
|
}
|
||||||
|
c, err := redis.Dial(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pass != "" {
|
||||||
|
if _, err = c.Do("AUTH", pass); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect connects to the redis, called only once
|
||||||
|
func (r *Service) Connect() {
|
||||||
|
c := r.Config
|
||||||
|
|
||||||
|
if c.IdleTimeout <= 0 {
|
||||||
|
c.IdleTimeout = DefaultRedisIdleTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Network == "" {
|
||||||
|
c.Network = DefaultRedisNetwork
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Addr == "" {
|
||||||
|
c.Addr = DefaultRedisAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
pool := &redis.Pool{IdleTimeout: c.IdleTimeout, MaxIdle: c.MaxIdle, MaxActive: c.MaxActive}
|
||||||
|
pool.TestOnBorrow = func(c redis.Conn, t time.Time) error {
|
||||||
|
_, err := c.Do("PING")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Database != "" {
|
||||||
|
pool.Dial = func() (redis.Conn, error) {
|
||||||
|
red, err := dial(c.Network, c.Addr, c.Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err = red.Do("SELECT", c.Database); err != nil {
|
||||||
|
red.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return red, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pool.Dial = func() (redis.Conn, error) {
|
||||||
|
return dial(c.Network, c.Addr, c.Password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Connected = true
|
||||||
|
r.pool = pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a Redis service filled by the passed config
|
||||||
|
// to connect call the .Connect().
|
||||||
|
func New(cfg ...Config) *Service {
|
||||||
|
c := DefaultConfig()
|
||||||
|
if len(cfg) > 0 {
|
||||||
|
c = cfg[0]
|
||||||
|
}
|
||||||
|
r := &Service{pool: &redis.Pool{}, Config: &c}
|
||||||
|
return r
|
||||||
|
}
|
|
@ -91,7 +91,7 @@ func testSessions(t *testing.T, sess *sessions.Sessions, app *iris.Application)
|
||||||
d := e.GET("/destroy").Expect().Status(iris.StatusOK)
|
d := e.GET("/destroy").Expect().Status(iris.StatusOK)
|
||||||
d.JSON().Object().Empty()
|
d.JSON().Object().Empty()
|
||||||
// This removed: d.Cookies().Empty(). Reason:
|
// This removed: d.Cookies().Empty(). Reason:
|
||||||
// httpexpect counts the cookies setted or deleted at the response time, but cookie is not removed, to be really removed needs to SetExpire(now-1second) so,
|
// httpexpect counts the cookies set or deleted at the response time, but cookie is not removed, to be really removed needs to SetExpire(now-1second) so,
|
||||||
// test if the cookies removed on the next request, like the browser's behavior.
|
// test if the cookies removed on the next request, like the browser's behavior.
|
||||||
e.GET("/after_destroy").Expect().Status(iris.StatusOK).Cookies().Empty()
|
e.GET("/after_destroy").Expect().Status(iris.StatusOK).Cookies().Empty()
|
||||||
// set and clear again
|
// set and clear again
|
||||||
|
|
|
@ -78,7 +78,7 @@ type (
|
||||||
// 2. Dir: string, Dir set the root, where to search for typescript files/project. Default "./"
|
// 2. Dir: string, Dir set the root, where to search for typescript files/project. Default "./"
|
||||||
// 3. Ignore: string, comma separated ignore typescript files/project from these directories. Default "" (node_modules are always ignored)
|
// 3. Ignore: string, comma separated ignore typescript files/project from these directories. Default "" (node_modules are always ignored)
|
||||||
// 4. Tsconfig: &typescript.Tsconfig{}, here you can set all compilerOptions if no tsconfig.json exists inside the 'Dir'
|
// 4. Tsconfig: &typescript.Tsconfig{}, here you can set all compilerOptions if no tsconfig.json exists inside the 'Dir'
|
||||||
// 5. Editor: typescript.Editor("username","password"), if setted then alm-tools browser-based typescript IDE will be available. Defailt is nil
|
// 5. Editor: typescript.Editor("username","password"), if set then alm-tools browser-based typescript IDE will be available. Defailt is nil
|
||||||
Config struct {
|
Config struct {
|
||||||
// Bin the path of the tsc binary file
|
// Bin the path of the tsc binary file
|
||||||
// if empty then the plugin tries to find it
|
// if empty then the plugin tries to find it
|
||||||
|
|
|
@ -128,7 +128,7 @@ func hi(ctx iris.Context) {
|
||||||
|
|
||||||
View engine supports bundled(https://github.com/shuLhan/go-bindata) template files too.
|
View engine supports bundled(https://github.com/shuLhan/go-bindata) template files too.
|
||||||
`go-bindata` gives you two functions, `Assset` and `AssetNames`,
|
`go-bindata` gives you two functions, `Assset` and `AssetNames`,
|
||||||
these can be setted to each of the template engines using the `.Binary` function.
|
these can be set to each of the template engines using the `.Binary` function.
|
||||||
|
|
||||||
Example code:
|
Example code:
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ func (s *AmberEngine) Binary(assetFn func(name string) ([]byte, error), namesFn
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload if setted to true the templates are reloading on each render,
|
// Reload if set to true the templates are reloading on each render,
|
||||||
// use it when you're in development and you're boring of restarting
|
// use it when you're in development and you're boring of restarting
|
||||||
// the whole app when you edit a template file.
|
// the whole app when you edit a template file.
|
||||||
//
|
//
|
||||||
|
@ -91,7 +91,7 @@ func (s *AmberEngine) Load() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// change the directory field configuration, load happens after directory has been setted, so we will not have any problems here.
|
// change the directory field configuration, load happens after directory has been set, so we will not have any problems here.
|
||||||
s.directory = dir
|
s.directory = dir
|
||||||
return s.loadDirectory()
|
return s.loadDirectory()
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ func (s *DjangoEngine) Binary(assetFn func(name string) ([]byte, error), namesFn
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload if setted to true the templates are reloading on each render,
|
// Reload if set to true the templates are reloading on each render,
|
||||||
// use it when you're in development and you're boring of restarting
|
// use it when you're in development and you're boring of restarting
|
||||||
// the whole app when you edit a template file.
|
// the whole app when you edit a template file.
|
||||||
//
|
//
|
||||||
|
@ -210,7 +210,7 @@ func (s *DjangoEngine) Load() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// change the directory field configuration, load happens after directory has been setted, so we will not have any problems here.
|
// change the directory field configuration, load happens after directory has been set, so we will not have any problems here.
|
||||||
s.directory = dir
|
s.directory = dir
|
||||||
return s.loadDirectory()
|
return s.loadDirectory()
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (s *HandlebarsEngine) Binary(assetFn func(name string) ([]byte, error), nam
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload if setted to true the templates are reloading on each render,
|
// Reload if set to true the templates are reloading on each render,
|
||||||
// use it when you're in development and you're boring of restarting
|
// use it when you're in development and you're boring of restarting
|
||||||
// the whole app when you edit a template file.
|
// the whole app when you edit a template file.
|
||||||
//
|
//
|
||||||
|
@ -111,7 +111,7 @@ func (s *HandlebarsEngine) Load() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// change the directory field configuration, load happens after directory has been setted, so we will not have any problems here.
|
// change the directory field configuration, load happens after directory has been set, so we will not have any problems here.
|
||||||
s.directory = dir
|
s.directory = dir
|
||||||
return s.loadDirectory()
|
return s.loadDirectory()
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (s *HTMLEngine) Binary(assetFn func(name string) ([]byte, error), namesFn f
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload if setted to true the templates are reloading on each render,
|
// Reload if set to true the templates are reloading on each render,
|
||||||
// use it when you're in development and you're boring of restarting
|
// use it when you're in development and you're boring of restarting
|
||||||
// the whole app when you edit a template file.
|
// the whole app when you edit a template file.
|
||||||
//
|
//
|
||||||
|
@ -226,7 +226,7 @@ func (s *HTMLEngine) Load() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// change the directory field configuration, load happens after directory has been setted, so we will not have any problems here.
|
// change the directory field configuration, load happens after directory has been set, so we will not have any problems here.
|
||||||
s.directory = dir
|
s.directory = dir
|
||||||
return s.loadDirectory()
|
return s.loadDirectory()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user