Update to version 8.5.5 | Read HISTORY.md

Former-commit-id: dced7d472edabbab4f80c76051f13261928a8dea
This commit is contained in:
kataras 2017-11-02 05:54:33 +02:00
parent 666bcacf20
commit 15feaf0237
100 changed files with 13338 additions and 13155 deletions

View File

@ -10,7 +10,7 @@ go:
# - tip # - tip
go_import_path: github.com/kataras/iris go_import_path: github.com/kataras/iris
install: install:
- go get ./... # for iris-contrib/httpexpect, kataras/golog, boltdb/bolt(sessiondb, optional) - go get ./... # for iris-contrib/httpexpect, kataras/golog, kataras/signal
script: script:
- go test -v -cover ./... - go test -v -cover ./...
after_script: after_script:

View File

@ -17,6 +17,19 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you. **How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you.
# Tu, 02 November 2017 | v8.5.5
- fix [audio/mpeg3 does not appear to be a valid registered mime type#798](https://github.com/kataras/iris/issues/798]) reported by @kryptodev,
- improve the updater's performance and moved that into the framework itself,
- ask for authentication only when a new version is released.
- sessiondb's `.Async` functions do nothing now, all session databases(back-end persistence storage) should run in-sync, @speedwheel helped to find a misbehavior because of that setting,
- we are on [opencollective](http://opencollective.com/iris) and sponsored by [codesponsor](https://codesponsor.io/) now.
_TODO;_
- give the ability to customize the mvc path-method-and path parameters mapping,
- make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here.
# Th, 26 October 2017 | v8.5.4 # Th, 26 October 2017 | v8.5.4
This version is part of the [releases](https://github.com/kataras/iris/releases). This version is part of the [releases](https://github.com/kataras/iris/releases).

View File

@ -1,5 +1,9 @@
# ![Logo created by @santoshanand](logo_white_35_24.png) Iris [![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris)[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)[![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)[![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples)[![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris)[![CLA assistant](https://cla-assistant.io/readme/badge/kataras/iris?style=flat-square)](https://cla-assistant.io/kataras/iris) # ![Logo created by @santoshanand](logo_white_35_24.png) Iris [![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)[![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris)[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)[![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)[![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples)[![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris)[![CLA assistant](https://cla-assistant.io/readme/badge/kataras/iris?style=flat-square)](https://cla-assistant.io/kataras/iris)
<a target='_blank' rel='nofollow' href='https://app.codesponsor.io/link/Qw6E1MTHvUJW6BtwUUf9qwsy/kataras/iris'>
<img alt='Sponsor' width='888' height='68' src='https://app.codesponsor.io/embed/Qw6E1MTHvUJW6BtwUUf9qwsy/kataras/iris.svg' />
</a>
Iris is a fast, simple and efficient web framework for Go. Iris is a fast, simple and efficient web framework for Go.
Iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app. Iris provides a beautifully expressive and easy to use foundation for your next website, API, or distributed app.
@ -16,6 +20,8 @@ Learn what [others say about Iris](https://www.youtube.com/watch?v=jGx0LkuUs4A)
_Updated at: [Friday, 29 September 2017](_benchmarks)_ _Updated at: [Friday, 29 September 2017](_benchmarks)_
</details> </details>
## Built with ♥️
We have no doubt you will able to find other web frameworks written in Go We have no doubt you will able to find other web frameworks written in Go
and even put up a real fight to learn and use them for quite some time but and even put up a real fight to learn and use them for quite some time but
make no mistake, sooner or later you will be using Iris, not because of the ergonomic, high-performant solution that it provides but its well-documented unique features, as these will transform you to a real rockstar geek. make no mistake, sooner or later you will be using Iris, not because of the ergonomic, high-performant solution that it provides but its well-documented unique features, as these will transform you to a real rockstar geek.
@ -27,24 +33,16 @@ you can find online.
Iris may have reached version 8, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris. Iris may have reached version 8, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris.
## Built with ♥️
<a target='_blank' rel='nofollow' href='https://app.codesponsor.io/link/Qw6E1MTHvUJW6BtwUUf9qwsy/kataras/iris'>
<img alt='Sponsor' width='700' height='60' src='https://app.codesponsor.io/embed/Qw6E1MTHvUJW6BtwUUf9qwsy/kataras/iris.svg' />
</a>
Accelerated by [KeyCDN](https://www.keycdn.com/), a simple, fast and reliable CDN. Accelerated by [KeyCDN](https://www.keycdn.com/), a simple, fast and reliable CDN.
We are developing this project using the best code editor for Golang; [Visual Studio Code](https://code.visualstudio.com/) supported by [Microsoft](https://www.microsoft.com). We are developing this project using the best code editor for Golang; [Visual Studio Code](https://code.visualstudio.com/) supported by [Microsoft](https://www.microsoft.com).
Iris was built on top of the the [net/http](https://golang.org/pkg/net/http/) package, we own many thanks to [Brad Fitzpatrick](https://github.com/bradfitz) for that.
If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs](https://github.com/expressjs/express) equivalent for Gophers. If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs](https://github.com/expressjs/express) equivalent for Gophers.
## Table Of Content ## Table Of Content
* [Installation](#installation) * [Installation](#installation)
* [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#th-26-october-2017--v854) * [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855)
* [Getting started](#getting-started) * [Getting started](#getting-started)
* [Learn](_examples/) * [Learn](_examples/)
* [MVC (Model View Controller)](_examples/#mvc) **NEW** * [MVC (Model View Controller)](_examples/#mvc) **NEW**
@ -80,7 +78,7 @@ If you're coming from [nodejs](https://nodejs.org) world, Iris is the [expressjs
## Installation ## Installation
The only requirement is the [Go Programming Language](https://golang.org/dl/), at least version 1.9 The only requirement is the [Go Programming Language](https://golang.org/dl/)
```sh ```sh
$ go get -u github.com/kataras/iris $ go get -u github.com/kataras/iris

View File

@ -1 +1 @@
8.5.4:https://github.com/kataras/iris/blob/master/HISTORY.md#th-26-october-2017--v854 8.5.5:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855

View File

@ -137,6 +137,9 @@ var WithoutInterruptHandler = func(app *Application) {
} }
// WithoutVersionChecker will disable the version checker and updater. // WithoutVersionChecker will disable the version checker and updater.
// The Iris server will be not
// receive automatic updates if you pass this
// to the `Run` function. Use it only while you're ready for Production environment.
var WithoutVersionChecker = func(app *Application) { var WithoutVersionChecker = func(app *Application) {
app.config.DisableVersionChecker = true app.config.DisableVersionChecker = true
} }
@ -268,23 +271,23 @@ type Configuration struct {
// Example: https://github.com/kataras/iris/tree/master/_examples/http-listening/listen-addr/omit-server-errors // Example: https://github.com/kataras/iris/tree/master/_examples/http-listening/listen-addr/omit-server-errors
// //
// Defaults to an empty slice. // Defaults to an empty slice.
IgnoreServerErrors []string `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 setted to true then it turns off the write banner on server startup.
// //
// Defaults to false. // Defaults to false.
DisableStartupLog bool `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 setted 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.
// //
// Defaults to false. // Defaults to false.
DisableInterruptHandler bool `yaml:"DisableInterruptHandler" toml:"DisableInterruptHandler"` DisableInterruptHandler bool `json:"disableInterruptHandler,omitempty" yaml:"DisableInterruptHandler" toml:"DisableInterruptHandler"`
// DisableVersionChecker if true then process will be not be notified for any available updates. // DisableVersionChecker if true then process will be not be notified for any available updates.
// //
// Defaults to false. // Defaults to false.
DisableVersionChecker bool `yaml:"DisableVersionChecker" toml:"DisableVersionChecker"` DisableVersionChecker bool `json:"disableVersionChecker,omitempty" yaml:"DisableVersionChecker" toml:"DisableVersionChecker"`
// DisablePathCorrection corrects and redirects the requested path to the registered path // DisablePathCorrection corrects and redirects the requested path to the registered path
// for example, if /home/ path is requested but no handler for this Route found, // for example, if /home/ path is requested but no handler for this Route found,
@ -292,7 +295,7 @@ type Configuration struct {
// (permant)redirects the client to the correct path /home // (permant)redirects the client to the correct path /home
// //
// Defaults to false. // Defaults to false.
DisablePathCorrection bool `yaml:"DisablePathCorrection" toml:"DisablePathCorrection"` DisablePathCorrection bool `json:"disablePathCorrection,omitempty" yaml:"DisablePathCorrection" toml:"DisablePathCorrection"`
// EnablePathEscape when is true then its escapes the path, the named parameters (if any). // EnablePathEscape when is true then its escapes the path, the named parameters (if any).
// Change to false it if you want something like this https://github.com/kataras/iris/issues/135 to work // Change to false it if you want something like this https://github.com/kataras/iris/issues/135 to work
@ -305,17 +308,17 @@ type Configuration struct {
// projectName, _ := url.QueryUnescape(c.Param("project"). // projectName, _ := url.QueryUnescape(c.Param("project").
// //
// Defaults to false. // Defaults to false.
EnablePathEscape bool `yaml:"EnablePathEscape" toml:"EnablePathEscape"` EnablePathEscape bool `json:"enablePathEscape,omitempty" yaml:"EnablePathEscape" toml:"EnablePathEscape"`
// EnableOptimization when this field is true // EnableOptimization when this field is true
// then the application tries to optimize for the best performance where is possible. // then the application tries to optimize for the best performance where is possible.
// //
// Defaults to false. // Defaults to false.
EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"` EnableOptimizations bool `json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
// FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and // FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and
// fires the 405 error instead of 404 // fires the 405 error instead of 404
// Defaults to false. // Defaults to false.
FireMethodNotAllowed bool `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 setted to true then it
@ -325,7 +328,7 @@ type Configuration struct {
// if this field setted to true then a new buffer will be created to read from and the request body. // if this field setted 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 `yaml:"DisableBodyConsumptionOnUnmarshal" toml:"DisableBodyConsumptionOnUnmarshal"` DisableBodyConsumptionOnUnmarshal bool `json:"disableBodyConsumptionOnUnmarshal,omitempty" yaml:"DisableBodyConsumptionOnUnmarshal" toml:"DisableBodyConsumptionOnUnmarshal"`
// DisableAutoFireStatusCode if true then it turns off the http error status code handler automatic execution // DisableAutoFireStatusCode if true then it turns off the http error status code handler automatic execution
// from "context.StatusCode(>=400)" and instead app should manually call the "context.FireStatusCode(>=400)". // from "context.StatusCode(>=400)" and instead app should manually call the "context.FireStatusCode(>=400)".
@ -338,16 +341,16 @@ type Configuration struct {
// HTTP Custom error handlers are being registered via app.OnErrorCode(code, handler)". // HTTP Custom error handlers are being registered via app.OnErrorCode(code, handler)".
// //
// Defaults to false. // Defaults to false.
DisableAutoFireStatusCode bool `yaml:"DisableAutoFireStatusCode" toml:"DisableAutoFireStatusCode"` DisableAutoFireStatusCode bool `json:"disableAutoFireStatusCode,omitempty" yaml:"DisableAutoFireStatusCode" toml:"DisableAutoFireStatusCode"`
// TimeFormat time format for any kind of datetime parsing // TimeFormat time format for any kind of datetime parsing
// Defaults to "Mon, 02 Jan 2006 15:04:05 GMT". // Defaults to "Mon, 02 Jan 2006 15:04:05 GMT".
TimeFormat string `yaml:"TimeFormat" toml:"TimeFormat"` TimeFormat string `json:"timeFormat,omitempty" yaml:"TimeFormat" toml:"TimeFormat"`
// Charset character encoding for various rendering // Charset character encoding for various rendering
// used for templates and the rest of the responses // used for templates and the rest of the responses
// Defaults to "UTF-8". // Defaults to "UTF-8".
Charset string `yaml:"Charset" toml:"Charset"` Charset string `json:"charset,omitempty" yaml:"Charset" toml:"Charset"`
// +----------------------------------------------------+ // +----------------------------------------------------+
// | Context's keys for values used on various featuers | // | Context's keys for values used on various featuers |
@ -359,11 +362,11 @@ type Configuration struct {
// currently we have only one: https://github.com/kataras/iris/tree/master/middleware/i18n. // currently we have only one: https://github.com/kataras/iris/tree/master/middleware/i18n.
// //
// Defaults to "iris.translate" and "iris.language" // Defaults to "iris.translate" and "iris.language"
TranslateFunctionContextKey string `yaml:"TranslateFunctionContextKey" toml:"TranslateFunctionContextKey"` TranslateFunctionContextKey string `json:"translateFunctionContextKey,omitempty" yaml:"TranslateFunctionContextKey" toml:"TranslateFunctionContextKey"`
// TranslateLanguageContextKey used for i18n. // TranslateLanguageContextKey used for i18n.
// //
// Defaults to "iris.language" // Defaults to "iris.language"
TranslateLanguageContextKey string `yaml:"TranslateLanguageContextKey" toml:"TranslateLanguageContextKey"` TranslateLanguageContextKey string `json:"translateLanguageContextKey,omitempty" yaml:"TranslateLanguageContextKey" toml:"TranslateLanguageContextKey"`
// GetViewLayoutContextKey is the key of the context's user values' key // GetViewLayoutContextKey is the key of the context's user values' key
// which is being used to set the template // which is being used to set the template
@ -371,13 +374,13 @@ type Configuration struct {
// Overrides the parent's or the configuration's. // Overrides the parent's or the configuration's.
// //
// Defaults to "iris.ViewLayout" // Defaults to "iris.ViewLayout"
ViewLayoutContextKey string `yaml:"ViewLayoutContextKey" toml:"ViewLayoutContextKey"` ViewLayoutContextKey string `json:"viewLayoutContextKey,omitempty" yaml:"ViewLayoutContextKey" toml:"ViewLayoutContextKey"`
// GetViewDataContextKey is the key of the context's user values' key // GetViewDataContextKey is the key of the context's user values' key
// which is being used to set the template // which is being used to set the template
// binding data from a middleware or the main handler. // binding data from a middleware or the main handler.
// //
// Defaults to "iris.viewData" // Defaults to "iris.viewData"
ViewDataContextKey string `yaml:"ViewDataContextKey" toml:"ViewDataContextKey"` ViewDataContextKey string `json:"viewDataContextKey,omitempty" yaml:"ViewDataContextKey" toml:"ViewDataContextKey"`
// RemoteAddrHeaders returns the allowed request headers names // RemoteAddrHeaders returns the allowed request headers names
// that can be valid to parse the client's IP based on. // that can be valid to parse the client's IP based on.
// //
@ -387,13 +390,13 @@ type Configuration struct {
// "CF-Connecting-IP": false // "CF-Connecting-IP": false
// //
// Look `context.RemoteAddr()` for more. // Look `context.RemoteAddr()` for more.
RemoteAddrHeaders map[string]bool `yaml:"RemoteAddrHeaders" toml:"RemoteAddrHeaders"` RemoteAddrHeaders map[string]bool `json:"remoteAddrHeaders,omitempty" yaml:"RemoteAddrHeaders" toml:"RemoteAddrHeaders"`
// Other are the custom, dynamic options, can be empty. // Other are the custom, dynamic options, can be empty.
// This field used only by you to set any app's options you want // This field used only by you to set any app's options you want
// or by custom adaptors, it's a way to simple communicate between your adaptors (if any) // or by custom adaptors, it's a way to simple communicate between your adaptors (if any)
// Defaults to a non-nil empty map. // Defaults to a non-nil empty map.
Other map[string]interface{} `yaml:"Other" toml:"Other"` Other map[string]interface{} `json:"other,omitempty" yaml:"Other" toml:"Other"`
} }
var _ context.ConfigurationReadOnly = &Configuration{} var _ context.ConfigurationReadOnly = &Configuration{}

View File

@ -125,7 +125,7 @@ func (r RequestParams) GetInt64(key string) (int64, error) {
// GetFloat64 returns a path parameter's value based as float64 on its route's dynamic path key. // GetFloat64 returns a path parameter's value based as float64 on its route's dynamic path key.
func (r RequestParams) GetFloat64(key string) (float64, error) { func (r RequestParams) GetFloat64(key string) (float64, error) {
return strconv.ParseFloat(r.Get(key), 64) return r.store.GetFloat64(key)
} }
// GetBool returns the path parameter's value as bool, based on its key. // GetBool returns the path parameter's value as bool, based on its key.

76
core/host/interrupt.go Normal file
View File

@ -0,0 +1,76 @@
package host
import (
"os"
"os/signal"
"sync"
"syscall"
)
// RegisterOnInterrupt registers a global function to call when CTRL+C/CMD+C pressed or a unix kill command received.
func RegisterOnInterrupt(cb func()) {
Interrupt.Register(cb)
}
// Interrupt watches the os.Signals for interruption signals
// and fires the callbacks when those happens.
// A call of its `FireNow` manually will fire and reset the registered interrupt handlers.
var Interrupt = new(interruptListener)
type interruptListener struct {
mu sync.Mutex
once sync.Once
// onInterrupt contains a list of the functions that should be called when CTRL+C/CMD+C or
// a unix kill command received.
onInterrupt []func()
}
// Register registers a global function to call when CTRL+C/CMD+C pressed or a unix kill command received.
func (i *interruptListener) Register(cb func()) {
if cb == nil {
return
}
i.listenOnce()
i.mu.Lock()
i.onInterrupt = append(i.onInterrupt, cb)
i.mu.Unlock()
}
// FireNow can be called more than one times from a Consumer in order to
// execute all interrupt handlers manually.
func (i *interruptListener) FireNow() {
i.mu.Lock()
for _, f := range i.onInterrupt {
f()
}
i.onInterrupt = i.onInterrupt[0:0]
i.mu.Unlock()
}
// listenOnce fires a goroutine which calls the interrupt handlers when CTRL+C/CMD+C and e.t.c.
// If `FireNow` called before then it does nothing when interrupt signal received,
// so it's safe to be used side by side with `FireNow`.
//
// Btw this `listenOnce` is called automatically on first register, it's useless for outsiders.
func (i *interruptListener) listenOnce() {
i.once.Do(func() { go i.notifyAndFire() })
}
func (i *interruptListener) notifyAndFire() {
ch := make(chan os.Signal, 1)
signal.Notify(ch,
// kill -SIGINT XXXX or Ctrl+c
os.Interrupt,
syscall.SIGINT, // register that too, it should be ok
// os.Kill is equivalent with the syscall.SIGKILL
os.Kill,
syscall.SIGKILL, // register that too, it should be ok
// kill -SIGTERM XXXX
syscall.SIGTERM,
)
select {
case <-ch:
i.FireNow()
}
}

View File

@ -190,8 +190,6 @@ func (su *Supervisor) supervise(blockFunc func() error) error {
su.notifyServe(host) su.notifyServe(host)
tryStartInterruptNotifier()
err := blockFunc() err := blockFunc()
su.notifyErr(err) su.notifyErr(err)

View File

@ -1,61 +0,0 @@
package host
import (
"os"
"os/signal"
"sync"
"syscall"
)
// package-level interrupt notifier and event firing.
type world struct {
mu sync.Mutex
// onInterrupt contains a list of the functions that should be called when CTRL+C/CMD+C or
// a unix kill command received.
onInterrupt []func()
}
var w = &world{}
// RegisterOnInterrupt registers a global function to call when CTRL+C/CMD+C pressed or a unix kill command received.
func RegisterOnInterrupt(cb func()) {
w.mu.Lock()
w.onInterrupt = append(w.onInterrupt, cb)
w.mu.Unlock()
}
func notifyInterrupt() {
w.mu.Lock()
for _, f := range w.onInterrupt {
f()
}
w.mu.Unlock()
}
func tryStartInterruptNotifier() {
w.mu.Lock()
defer w.mu.Unlock()
if len(w.onInterrupt) > 0 {
// this can't be moved to the task interrupt's `Run` function
// because it will not catch more than one ctrl/cmd+c, so
// we do it here. These tasks are canceled already too.
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch,
// kill -SIGINT XXXX or Ctrl+c
os.Interrupt,
syscall.SIGINT, // register that too, it should be ok
// os.Kill is equivalent with the syscall.SIGKILL
os.Kill,
syscall.SIGKILL, // register that too, it should be ok
// kill -SIGTERM XXXX
syscall.SIGTERM,
)
select {
case <-ch:
notifyInterrupt()
}
}()
}
}

View File

@ -0,0 +1,93 @@
package maintenance
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/url"
"github.com/kataras/iris/core/maintenance/client"
"github.com/kataras/iris/core/maintenance/encoding"
"github.com/kataras/survey"
)
// question describes the question which will be used
// for the survey in order to authenticate the local iris.
type question struct {
Message string `json:"message"`
}
func hasInternetConnection() (bool, bool) {
r, err := client.PostForm("", nil)
if err != nil {
// no internet connection
return false, false
}
defer r.Body.Close()
return true, r.StatusCode == 204
}
func ask() bool {
qs := fetchQuestions()
var lastResponseUnsed string
for _, q := range qs {
survey.AskOne(&survey.Input{Message: q.Message}, &lastResponseUnsed, validate(q))
}
return lastResponseUnsed != ""
}
// fetchQuestions returns a list of questions
// fetched by the authority server.
func fetchQuestions() (qs []question) {
r, err := client.PostForm("/survey/ask", nil)
if err != nil {
return
}
defer r.Body.Close()
if err := encoding.UnmarshalBody(r.Body, &qs, json.Unmarshal); err != nil {
return
}
return
}
func validate(q question) survey.Validator {
return func(answer interface{}) error {
if err := survey.Required(answer); err != nil {
return err
}
ans, ok := answer.(string)
if !ok {
return fmt.Errorf("bug: expected string but got %v", answer)
}
data := url.Values{
"q": []string{q.Message},
"ans": []string{ans},
"current_version": []string{Version},
}
r, err := client.PostForm("/survey/submit", data)
if err != nil {
// error from server-side, allow.
return nil
}
defer r.Body.Close()
if r.StatusCode == 200 {
// read the whole thing, it has nothing.
io.Copy(ioutil.Discard, r.Body)
return nil // pass, no any errors.
}
// now, if invalid;
got, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil
}
errMsg := string(got)
return fmt.Errorf(errMsg)
}
}

View File

@ -0,0 +1,41 @@
package client
import (
"bytes"
"net"
"net/http"
"net/url"
"time"
"github.com/kataras/iris/core/netutil"
)
const host = "http://live.iris-go.com"
// PostForm performs the PostForm with a secure client.
func PostForm(p string, data url.Values) (*http.Response, error) {
client := netutil.Client(25 * time.Second)
if len(data) == 0 {
data = make(url.Values, 1)
}
data.Set("X-Auth", a)
u := host + p
r, err := client.PostForm(u, data)
return r, err
}
var a string
func init() {
interfaces, err := net.Interfaces()
if err == nil {
for _, f := range interfaces {
if f.Flags&net.FlagUp != 0 && bytes.Compare(f.HardwareAddr, nil) != 0 {
a = f.HardwareAddr.String()
break
}
}
}
}

View File

@ -0,0 +1,33 @@
package encoding
import (
"errors"
"io"
"io/ioutil"
"reflect"
)
// UnmarshalerFunc is the Unmarshaler compatible type.
//
// See 'unmarshalBody' for more.
type UnmarshalerFunc func(data []byte, v interface{}) error
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type.
func UnmarshalBody(body io.Reader, v interface{}, unmarshaler UnmarshalerFunc) error {
if body == nil {
return errors.New("unmarshal: empty body")
}
rawData, err := ioutil.ReadAll(body)
if err != nil {
return err
}
// check if v is already a pointer, if yes then pass as it's
if reflect.TypeOf(v).Kind() == reflect.Ptr {
return unmarshaler(rawData, v)
}
// finally, if the v doesn't contains a self-body decoder and it's not a pointer
// use the custom unmarshaler to bind the body
return unmarshaler(rawData, &v)
}

View File

@ -0,0 +1,6 @@
package maintenance
// Start starts the maintenance process.
func Start() {
CheckForUpdates()
}

View File

@ -0,0 +1,83 @@
package maintenance
import (
"fmt"
"os"
"os/exec"
"github.com/kataras/iris/core/maintenance/version"
"github.com/kataras/golog"
"github.com/kataras/survey"
)
const (
// Version is the string representation of the current local Iris Web Framework version.
Version = "8.5.5"
)
// CheckForUpdates checks for any available updates
// and asks for the user if want to update now or not.
func CheckForUpdates() {
v := version.Acquire()
updateAvailale := v.Compare(Version) == version.Smaller
if updateAvailale {
has, ft := hasInternetConnection()
canUpdate := (has && ft && ask()) || !has || !ft
if canUpdate {
installVersion(v)
}
}
}
func installVersion(v version.Version) {
// on help? when asking for installing the new update
// and when answering "No".
ignoreUpdatesMsg := "Would you like to ignore future updates? Disable the version checker via:\napp.Run(..., iris.WithoutVersionChecker)"
// if update available ask for update action.
shouldUpdateNowMsg :=
fmt.Sprintf("A new version is available online[%s < %s].\nRelease notes: %s.\nUpdate now?",
Version, v.String(),
v.ChangelogURL)
var confirmUpdate bool
survey.AskOne(&survey.Confirm{
Message: shouldUpdateNowMsg,
Help: ignoreUpdatesMsg,
}, &confirmUpdate, nil)
// run the updater last, so the user can star the repo and at the same time
// the app will update her/his local iris.
if confirmUpdate { // it's true only when update was available and user typed "yes".
repo := "github.com/kataras/iris/..."
cmd := exec.Command("go", "get", "-u", "-v", repo)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
if err := cmd.Run(); err != nil {
golog.Warnf("unexpected message while trying to go get,\nif you edited the original source code then you've to remove the whole $GOPATH/src/github.com/kataras folder and execute `go get -u github.com/kataras/iris/...` manually\n%v", err)
return
}
golog.Infof("Update process finished.\nManual rebuild and restart is required to apply the changes...\n")
return
}
// if update was available but chosen not to update then just continue...
}
/* Author's note:
We could use github webhooks to automatic notify for updates
when a new update is pushed to the repository
even when server is already started and running but this would expose
a route which dev may don't know about, so let it for now but if
they ask it then I should add an optional configuration field
to "live/realtime update" and implement the idea (which is already implemented in the iris-go server).
*/
/* Author's note:
The old remote endpoint for version checker is still available on the server for backwards
compatibility with older clients, it will stay there for a long period of time.
*/

View File

@ -0,0 +1,59 @@
package version
import (
"io/ioutil"
"strings"
"time"
"github.com/hashicorp/go-version"
"github.com/kataras/golog"
"github.com/kataras/iris/core/netutil"
)
const (
versionURL = "https://raw.githubusercontent.com/kataras/iris/master/VERSION"
)
func fetch() (*version.Version, string) {
client := netutil.Client(time.Duration(30 * time.Second))
r, err := client.Get(versionURL)
if err != nil {
golog.Debugf("err: %v\n", err)
return nil, ""
}
defer r.Body.Close()
if r.StatusCode >= 400 {
golog.Debugf("Internet connection is missing, updater is unable to fetch the latest Iris version\n", err)
return nil, ""
}
b, err := ioutil.ReadAll(r.Body)
if len(b) == 0 || err != nil {
golog.Debugf("err: %v\n", err)
return nil, ""
}
var (
fetchedVersion = string(b)
changelogURL string
)
// Example output:
// Version(8.5.5)
// 8.5.5:https://github.com/kataras/iris/blob/master/HISTORY.md#tu-02-november-2017--v855
if idx := strings.IndexByte(fetchedVersion, ':'); idx > 0 {
changelogURL = fetchedVersion[idx+1:]
fetchedVersion = fetchedVersion[0:idx]
}
latestVersion, err := version.NewVersion(fetchedVersion)
if err != nil {
golog.Debugf("while fetching and parsing latest version from github: %v\n", err)
return nil, ""
}
return latestVersion, changelogURL
}

View File

@ -0,0 +1,64 @@
package version
import (
"time"
"github.com/hashicorp/go-version"
)
// Version is a version wrapper which
// contains some additional customized properties.
type Version struct {
version.Version
WrittenAt time.Time
ChangelogURL string
}
// Result is the compare result type.
// Available types are Invalid, Smaller, Equal or Larger.
type Result int32
const (
// Smaller when the compared version is smaller than the latest one.
Smaller Result = -1
// Equal when the compared version is equal with the latest one.
Equal Result = 0
// Larger when the compared version is larger than the latest one.
Larger Result = 1
// Invalid means that an error occurred when comparing the versions.
Invalid Result = -2
)
// Compare compares the "versionStr" with the latest Iris version,
// opossite to the version package
// it returns the result of the "versionStr" not the "v" itself.
func (v *Version) Compare(versionStr string) Result {
if len(v.Version.String()) == 0 {
// if version not refreshed, by an internet connection lose,
// then return Invalid.
return Invalid
}
other, err := version.NewVersion(versionStr)
if err != nil {
return Invalid
}
return Result(other.Compare(&v.Version))
}
// Acquire returns the latest version info wrapper.
// It calls the fetch.
func Acquire() (v Version) {
newVersion, changelogURL := fetch()
if newVersion == nil { // if github was down then don't panic, just set it as the smallest version.
newVersion, _ = version.NewVersion("0.0.1")
}
v = Version{
Version: *newVersion,
WrittenAt: time.Now(),
ChangelogURL: changelogURL,
}
return
}

View File

@ -2,6 +2,7 @@ package ast
import ( import (
"fmt" "fmt"
"reflect"
"strconv" "strconv"
) )
@ -50,6 +51,40 @@ const (
ParamTypePath ParamTypePath
) )
// Not because for a single reason
// a string may be a
// ParamTypeString or a ParamTypeFile
// or a ParamTypePath or ParamTypeAlphabetical.
//
// func ParamTypeFromStd(k reflect.Kind) ParamType {
// Kind returns the std kind of this param type.
func (pt ParamType) Kind() reflect.Kind {
switch pt {
case ParamTypeAlphabetical:
fallthrough
case ParamTypeFile:
fallthrough
case ParamTypePath:
fallthrough
case ParamTypeString:
return reflect.String
case ParamTypeInt:
return reflect.Int
case ParamTypeLong:
return reflect.Int64
case ParamTypeBoolean:
return reflect.Bool
}
return reflect.Invalid // 0
}
// Assignable returns true if the "k" standard type
// is assignabled to this ParamType.
func (pt ParamType) Assignable(k reflect.Kind) bool {
return pt.Kind() == k
}
var paramTypes = map[string]ParamType{ var paramTypes = map[string]ParamType{
"string": ParamTypeString, "string": ParamTypeString,
"int": ParamTypeInt, "int": ParamTypeInt,

View File

@ -235,7 +235,7 @@ var types = map[string]string{
".mov": "video/quicktime", ".mov": "video/quicktime",
".movie": "video/x-sgi-movie", ".movie": "video/x-sgi-movie",
".mp2": "audio/mpeg", ".mp2": "audio/mpeg",
".mp3": "audio/mpeg3", ".mp3": "audio/mpeg",
".mp4": "video/mp4", ".mp4": "video/mp4",
".mpa": "audio/mpeg", ".mpa": "audio/mpeg",
".mpc": "application/x-project", ".mpc": "application/x-project",

View File

@ -102,7 +102,7 @@ func (nodes *Nodes) add(routeName, path string, paramNames []string, handlers co
// set the wildcard param name to the root and its children. // set the wildcard param name to the root and its children.
wildcardIdx := strings.IndexByte(path, '*') wildcardIdx := strings.IndexByte(path, '*')
wildcardParamName := "" wildcardParamName := ""
if wildcardIdx > 0 && len(paramNames) == 0 { if wildcardIdx > 0 && len(paramNames) == 0 { // 27 Oct comment: && len(paramNames) == 0 {
wildcardParamName = path[wildcardIdx+1:] wildcardParamName = path[wildcardIdx+1:]
path = path[0:wildcardIdx-1] + "/" // replace *paramName with single slash path = path[0:wildcardIdx-1] + "/" // replace *paramName with single slash
@ -217,8 +217,10 @@ loop:
*nodes = append(*nodes, n) *nodes = append(*nodes, n)
return return
} }
// println("4. nodes.Add path: " + path[len(n.s):])
err = n.childrenNodes.add(routeName, path[len(n.s):], paramNames, handlers, false) pathToAdd := path[len(n.s):]
// println("4. nodes.Add path: " + pathToAdd)
err = n.childrenNodes.add(routeName, pathToAdd, paramNames, handlers, false)
return err return err
} }
@ -231,10 +233,19 @@ loop:
} }
n.paramNames = paramNames n.paramNames = paramNames
n.handlers = handlers n.handlers = handlers
return return
} }
// START
// Author's note:
// 27 Oct 2017; fixes s|i|l+static+p
// without breaking the current tests.
if wildcardIdx > 0 {
wildcardParamName = path[wildcardIdx+1:]
path = path[0:wildcardIdx-1] + "/"
}
// END
n := &node{ n := &node{
s: path, s: path,
routeName: routeName, routeName: routeName,

6
doc.go
View File

@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
Current Version Current Version
8.5.4 8.5.5
Installation Installation
@ -333,7 +333,7 @@ Example Code:
h := app.NewHost(&http.Server{Addr:":8080"}) h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){ h.RegisterOnShutdown(func(){
println("server was closed!") println("terminate")
}) })
app.Run(iris.Raw(h.ListenAndServe)) app.Run(iris.Raw(h.ListenAndServe))
@ -398,7 +398,7 @@ Example Code:
// //
// we register a shutdown "event" callback // we register a shutdown "event" callback
su.RegisterOnShutdown(func() { su.RegisterOnShutdown(func() {
println("server is closed") println("terminate")
}) })
// su.RegisterOnError // su.RegisterOnError
// su.RegisterOnServe // su.RegisterOnServe

81
faq.md
View File

@ -1,81 +0,0 @@
# FAQ
## How to upgrade
```sh
go get -u github.com/kataras/iris
```
## Learning
More than 50 practical examples, tutorials and articles at:
- https://github.com/kataras/iris/tree/master/_examples
- https://github.com/iris-contrib/examples
- https://iris-go.com/v8/recipe
- https://docs.iris-go.com (in-progress)
- https://godoc.org/github.com/kataras/iris
> [Stay tuned](https://github.com/kataras/iris/stargazers), community prepares even more tutorials.
Want to help and join to the greatest community? Describe your skills and push your own sections at: https://github.com/kataras/build-a-better-web-together/issues/new
### common errors that new gophers may meet
#### type aliases
| build error | reason | solution |
| -----------|--------|--------|
| `undefined iris.Context` | caused of using the **optional type alias** `iris.Context` instead of the `context.Context` when building with Go 1.8 | import the original package `github.com/kataras/iris/context` and declare as `func(context.Context){})` **or** download and install the [latest go version](https://golang.org/dl) _recommended_ |
Type alias is a new feature, introduced at Go version 1.9, so if you want to use Iris' type aliases you have to build using the latest Go version. Nothing really changes for your application if you use type alias or not, Iris' type aliases helps you to omit import statements -- to reduce lines of code, nothing more.
**Details...**
Go version 1.9 introduced the [type alias](https://golang.org/doc/go1.9#language) feature.
Iris uses the `type alias` feature to help you writing less code by omitting some package imports. The examples and documentation are written using Go 1.9 as well.
If you build your Go app with Go 1.9 you can, optionally, use all Iris web framework's features by importing one single package, the `github.com/kataras/iris`.
Available type aliases;
| Go 1.8 | Go 1.8 usage | Go 1.9 usage (optionally) |
| -----------|--------|--------|
| `import "github.com/kataras/iris/context"` | `func(context.Context) {}`, `context.Handler`, `context.Map` | `func(iris.Context) {}`, `iris.Handler`, `iris.Map` |
| `import "github.com/kataras/iris/mvc"` | `type MyController struct { mvc.Controller }` , `mvc.SessionController` | `type MyController struct { iris.Controller }`, `iris.SessionController` |
| `import "github.com/kataras/iris/core/router"` | `app.PartyFunc("/users", func(p router.Party) {})` | `app.PartyFunc("/users", func(p iris.Party) {})` |
| `import "github.com/kataras/iris/core/host"` | `app.ConfigureHost(func(s *host.Supervisor) {})` | `app.ConfigureHost(func(s *iris.Supervisor) {})` |
You can find all type aliases and their original package import statements at the [./context.go file](context.go).
> Remember; this doesn't mean that you have to use those type aliases, you can still import the original packages as you did with Go version 1.8, it's up to you.
## Active development mode
Iris may have reached version 8, but we're not stopping there. We have many feature ideas on our board that we're anxious to add and other innovative web development solutions that we're planning to build into Iris.
## Can I find a job if I learn how to use Iris?
Yes, not only because you will learn Golang in the same time, but there are some positions
open for Iris-specific developers the time we speak.
- https://glints.id/opportunities/jobs/5553
## Can Iris be used in production after Dubai purchase?
Yes, now more than ever.
https://github.com/kataras/iris/issues/711
## Do we have a community Chat?
Yes, https://kataras.rocket.chat/channel/iris.
https://github.com/kataras/iris/issues/646
## How this open-source project still active and shine?
By normal people like you, who help us by donating small or larger amounts of money.
Help this project to continue deliver awesome and unique features with the higher code quality as possible by donating any amount via [PayPal](https://www.paypal.me/kataras)!

View File

@ -84,7 +84,8 @@ func New(t *testing.T, app *iris.Application, setters ...OptionSetter) *httpexpe
setter.Set(conf) setter.Set(conf)
} }
// disable the logger // set the logger or disable it (default) and disable the updater (for any case).
app.Configure(iris.WithoutVersionChecker)
app.Logger().SetLevel(conf.LogLevel) app.Logger().SetLevel(conf.LogLevel)
app.Build() app.Build()

14
iris.go
View File

@ -17,6 +17,7 @@ import (
// core packages, needed to build the application // core packages, needed to build the application
"github.com/kataras/iris/core/errors" "github.com/kataras/iris/core/errors"
"github.com/kataras/iris/core/host" "github.com/kataras/iris/core/host"
"github.com/kataras/iris/core/maintenance"
"github.com/kataras/iris/core/netutil" "github.com/kataras/iris/core/netutil"
"github.com/kataras/iris/core/router" "github.com/kataras/iris/core/router"
// handlerconv conversions // handlerconv conversions
@ -26,13 +27,14 @@ import (
// view // view
"github.com/kataras/iris/view" "github.com/kataras/iris/view"
// middleware used in Default method // middleware used in Default method
requestLogger "github.com/kataras/iris/middleware/logger" requestLogger "github.com/kataras/iris/middleware/logger"
"github.com/kataras/iris/middleware/recover" "github.com/kataras/iris/middleware/recover"
) )
const ( var (
// Version is the current version number of the Iris Web Framework. // Version is the current version number of the Iris Web Framework.
Version = "8.5.4" Version = maintenance.Version
) )
// HTTP status codes as registered with IANA. // HTTP status codes as registered with IANA.
@ -663,9 +665,7 @@ var ErrServerClosed = http.ErrServerClosed
// then create a new host and run it manually by `go NewHost(*http.Server).Serve/ListenAndServe` etc... // then create a new host and run it manually by `go NewHost(*http.Server).Serve/ListenAndServe` etc...
// or use an already created host: // or use an already created host:
// h := NewHost(*http.Server) // h := NewHost(*http.Server)
// Run(Raw(h.ListenAndServe), WithCharset("UTF-8"), // Run(Raw(h.ListenAndServe), WithCharset("UTF-8"), WithRemoteAddrHeader("CF-Connecting-IP"))
// WithRemoteAddrHeader("CF-Connecting-IP"),
// WithoutServerError(iris.ErrServerClosed))
// //
// The Application can go online with any type of server or iris's host with the help of // The Application can go online with any type of server or iris's host with the help of
// the following runners: // the following runners:
@ -680,8 +680,8 @@ func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error {
app.Configure(withOrWithout...) app.Configure(withOrWithout...)
app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1) app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1)
if !app.config.DisableVersionChecker && app.logger.Level != golog.DisableLevel { if !app.config.DisableVersionChecker {
go CheckVersion() go maintenance.Start()
} }
// this will block until an error(unless supervisor's DeferFlow called from a Task). // this will block until an error(unless supervisor's DeferFlow called from a Task).

View File

@ -14,7 +14,7 @@ import (
// DefaultFileMode used as the default database's "fileMode" // DefaultFileMode used as the default database's "fileMode"
// for creating the sessions directory path, opening and write the session file. // for creating the sessions directory path, opening and write the session file.
var ( var (
DefaultFileMode = 0666 DefaultFileMode = 0755
) )
// Database the badger(key-value file-based) session storage. // Database the badger(key-value file-based) session storage.
@ -23,7 +23,6 @@ type Database struct {
// it's initialized at `New` or `NewFromDB`. // it's initialized at `New` or `NewFromDB`.
// Can be used to get stats. // Can be used to get stats.
Service *badger.DB Service *badger.DB
async bool
} }
// New creates and returns a new badger(key-value file-based) storage // New creates and returns a new badger(key-value file-based) storage
@ -109,10 +108,9 @@ func (db *Database) Cleanup() (err error) {
return rep.Return() return rep.Return()
} }
// Async if true passed then it will use different // Async is DEPRECATED
// go routines to update the badger(key-value file-based) storage. // if it was true then it could use different to update the back-end storage, now it does nothing.
func (db *Database) Async(useGoRoutines bool) *Database { func (db *Database) Async(useGoRoutines bool) *Database {
db.async = useGoRoutines
return db return db
} }
@ -146,11 +144,7 @@ func (db *Database) Load(sid string) (storeDB sessions.RemoteStore) {
// Sync syncs the database with the session's (memory) store. // Sync syncs the database with the session's (memory) store.
func (db *Database) Sync(p sessions.SyncPayload) { func (db *Database) Sync(p sessions.SyncPayload) {
if db.async {
go db.sync(p)
} else {
db.sync(p) db.sync(p)
}
} }
func (db *Database) sync(p sessions.SyncPayload) { func (db *Database) sync(p sessions.SyncPayload) {

View File

@ -17,7 +17,7 @@ import (
// for creating the sessions directory path, opening and write // for creating the sessions directory path, opening and write
// the session boltdb(file-based) storage. // the session boltdb(file-based) storage.
var ( var (
DefaultFileMode = 0666 DefaultFileMode = 0755
) )
// Database the BoltDB(file-based) session storage. // Database the BoltDB(file-based) session storage.
@ -27,7 +27,6 @@ type Database struct {
// it's initialized at `New` or `NewFromDB`. // it's initialized at `New` or `NewFromDB`.
// Can be used to get stats. // Can be used to get stats.
Service *bolt.DB Service *bolt.DB
async bool
} }
var ( var (
@ -115,10 +114,9 @@ func (db *Database) Cleanup() error {
return err return err
} }
// Async if true passed then it will use different // Async is DEPRECATED
// go routines to update the BoltDB(file-based) storage. // if it was true then it could use different to update the back-end storage, now it does nothing.
func (db *Database) Async(useGoRoutines bool) *Database { func (db *Database) Async(useGoRoutines bool) *Database {
db.async = useGoRoutines
return db return db
} }
@ -151,11 +149,7 @@ func (db *Database) Load(sid string) (storeDB sessions.RemoteStore) {
// Sync syncs the database with the session's (memory) store. // Sync syncs the database with the session's (memory) store.
func (db *Database) Sync(p sessions.SyncPayload) { func (db *Database) Sync(p sessions.SyncPayload) {
if db.async {
go db.sync(p)
} else {
db.sync(p) db.sync(p)
}
} }
func (db *Database) sync(p sessions.SyncPayload) { func (db *Database) sync(p sessions.SyncPayload) {

View File

@ -13,7 +13,7 @@ import (
// DefaultFileMode used as the default database's "fileMode" // DefaultFileMode used as the default database's "fileMode"
// for creating the sessions directory path, opening and write the session file. // for creating the sessions directory path, opening and write the session file.
var ( var (
DefaultFileMode = 0666 DefaultFileMode = 0755
) )
// Database is the basic file-storage session database. // Database is the basic file-storage session database.
@ -28,12 +28,7 @@ var (
// Remember: sessions are not a storage for large data, everywhere: on any platform on any programming language. // Remember: sessions are not a storage for large data, everywhere: on any platform on any programming language.
type Database struct { type Database struct {
dir string dir string
fileMode os.FileMode // defaults to 0666 if missing. fileMode os.FileMode // defaults to DefaultFileMode if missing.
// if true then it will use go routines to:
// append or re-write a file
// create a file
// remove a file
async bool
} }
// New creates and returns a new file-storage database instance based on the "directoryPath". // New creates and returns a new file-storage database instance based on the "directoryPath".
@ -77,20 +72,15 @@ func (db *Database) Cleanup() error {
// FileMode for creating the sessions directory path, opening and write the session file. // FileMode for creating the sessions directory path, opening and write the session file.
// //
// Defaults to 0666. // Defaults to 0755.
func (db *Database) FileMode(fileMode uint32) *Database { func (db *Database) FileMode(fileMode uint32) *Database {
db.fileMode = os.FileMode(fileMode) db.fileMode = os.FileMode(fileMode)
return db return db
} }
// Async if true passed then it will use go routines to: // Async is DEPRECATED
// append or re-write a file // if it was true then it could use different to update the back-end storage, now it does nothing.
// create a file
// remove a file.
//
// Defaults to false.
func (db *Database) Async(useGoRoutines bool) *Database { func (db *Database) Async(useGoRoutines bool) *Database {
db.async = useGoRoutines
return db return db
} }
@ -137,11 +127,7 @@ func (db *Database) load(fileName string) (storeDB sessions.RemoteStore, loadErr
// Sync syncs the database. // Sync syncs the database.
func (db *Database) Sync(p sessions.SyncPayload) { func (db *Database) Sync(p sessions.SyncPayload) {
if db.async {
go db.sync(p)
} else {
db.sync(p) db.sync(p)
}
} }
func (db *Database) sync(p sessions.SyncPayload) { func (db *Database) sync(p sessions.SyncPayload) {

View File

@ -27,7 +27,6 @@ type Database struct {
// it's initialized at `New` or `NewFromDB`. // it's initialized at `New` or `NewFromDB`.
// Can be used to get stats. // Can be used to get stats.
Service *leveldb.DB Service *leveldb.DB
async bool
} }
// New creates and returns a new LevelDB(file-based) storage // New creates and returns a new LevelDB(file-based) storage
@ -98,10 +97,9 @@ func (db *Database) Cleanup() error {
return iter.Error() return iter.Error()
} }
// Async if true passed then it will use different // Async is DEPRECATED
// go routines to update the LevelDB(file-based) storage. // if it was true then it could use different to update the back-end storage, now it does nothing.
func (db *Database) Async(useGoRoutines bool) *Database { func (db *Database) Async(useGoRoutines bool) *Database {
db.async = useGoRoutines
return db return db
} }
@ -140,11 +138,7 @@ func (db *Database) Load(sid string) (storeDB sessions.RemoteStore) {
// Sync syncs the database with the session's (memory) store. // Sync syncs the database with the session's (memory) store.
func (db *Database) Sync(p sessions.SyncPayload) { func (db *Database) Sync(p sessions.SyncPayload) {
if db.async {
go db.sync(p)
} else {
db.sync(p) db.sync(p)
}
} }
func (db *Database) sync(p sessions.SyncPayload) { func (db *Database) sync(p sessions.SyncPayload) {

View File

@ -12,7 +12,6 @@ import (
// Database the redis back-end session database for the sessions. // Database the redis back-end session database for the sessions.
type Database struct { type Database struct {
redis *service.Service redis *service.Service
async bool
} }
// New returns a new redis database. // New returns a new redis database.
@ -27,10 +26,9 @@ func (db *Database) Config() *service.Config {
return db.redis.Config return db.redis.Config
} }
// Async if true passed then it will use different // Async is DEPRECATED
// go routines to update the redis storage. // if it was true then it could use different to update the back-end storage, now it does nothing.
func (db *Database) Async(useGoRoutines bool) *Database { func (db *Database) Async(useGoRoutines bool) *Database {
db.async = useGoRoutines
return db return db
} }
@ -70,11 +68,7 @@ func (db *Database) Load(sid string) (storeDB sessions.RemoteStore) {
// Sync syncs the database. // Sync syncs the database.
func (db *Database) Sync(p sessions.SyncPayload) { func (db *Database) Sync(p sessions.SyncPayload) {
if db.async {
go db.sync(p)
} else {
db.sync(p) db.sync(p)
}
} }
func (db *Database) sync(p sessions.SyncPayload) { func (db *Database) sync(p sessions.SyncPayload) {

View File

@ -1,151 +0,0 @@
package iris
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"os"
"os/exec"
"sync"
"time"
"github.com/kataras/golog"
"github.com/kataras/iris/core/netutil"
"github.com/kataras/survey"
"github.com/skratchdot/open-golang/open"
)
var checkVersionOnce = sync.Once{}
// CheckVersion checks for any available updates.
func CheckVersion() {
checkVersionOnce.Do(func() {
checkVersion()
})
}
type versionInfo struct {
Version string `json:"version"`
ChangelogURL string `json:"changelog_url"`
UpdateAvailable bool `json:"update_available"`
FirstTime bool `json:"first_time"`
}
func checkVersion() {
client := netutil.Client(25 * time.Second)
r, err := client.PostForm("https://iris-go.com/version", url.Values{"current_version": {Version}})
if err != nil {
golog.Debugf("%v", err)
return
}
defer r.Body.Close()
if r.StatusCode >= 400 {
return
}
b, err := ioutil.ReadAll(r.Body)
if len(b) == 0 || err != nil {
golog.Debugf("%v", err)
return
}
v := new(versionInfo)
if err := json.Unmarshal(b, v); err != nil {
golog.Debugf("error while unmarshal the response body: %v", err)
return
}
var qs []*survey.Question
// on help? when asking for installing the new update
// and when answering "No".
ignoreUpdatesMsg := "Would you like to ignore future updates? Disable the version checker via:\napp.Run(..., iris.WithoutVersionChecker)"
if v.UpdateAvailable {
// if update available ask for update action.
shouldUpdateNowMsg :=
fmt.Sprintf("A new version is available online[%s > %s].\nRelease notes: %s.\nUpdate now?",
v.Version, Version,
v.ChangelogURL)
qs = append(qs, &survey.Question{
Name: "shouldUpdateNow",
Prompt: &survey.Confirm{
Message: shouldUpdateNowMsg,
Help: ignoreUpdatesMsg,
},
Validate: survey.Required,
})
}
// firs time and update available is not relative because if no update often server will decide when to ask this,
// so separate the actions and if statements here.
if v.FirstTime {
// if first time that this server was updated then ask if enjoying the framework.
qs = append(qs, &survey.Question{
Name: "enjoyingIris",
Prompt: &survey.Confirm{
Message: "Enjoying Iris Framework?",
Help: "yes or no",
},
Validate: survey.Required,
})
}
// Ask if should update(if available) and enjoying iris(if first time) in the same survey.
ans := struct {
ShouldUpdateNow bool `survey:"shouldUpdateNow"`
EnjoyingIris bool `survey:"enjoyingIris"`
}{}
survey.Ask(qs, &ans)
if ans.EnjoyingIris {
// if the answer to the previous survey about enjoying the framework
// was positive then do the survey (currently only one question and its action).
qs2 := []*survey.Question{
{
Name: "starNow",
Prompt: &survey.Confirm{
Message: "Would you mind giving us a star on GitHub? It really helps us out! Thanks for your support:)",
Help: "Its free so let's do that, type 'y'",
},
Validate: survey.Required,
},
/* any future questions should be here, at this second survey. */
}
ans2 := struct {
StarNow bool `survey:"starNow"`
}{}
survey.Ask(qs2, &ans2)
if ans2.StarNow {
starRepo := "https://github.com/kataras/iris/stargazers"
if err := open.Run(starRepo); err != nil {
golog.Warnf("tried to open the browser for you but failed, please give us a star at: %s\n", starRepo)
}
}
}
// run the updater last, so the user can star the repo and at the same time
// the app will update her/his local iris.
if ans.ShouldUpdateNow { // it's true only when update was available and user typed "yes".
repo := "github.com/kataras/iris/..."
cmd := exec.Command("go", "get", "-u", "-v", repo)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
if err := cmd.Run(); err != nil {
golog.Warnf("unexpected message while trying to go get,\nif you edited the original source code then you've to remove the whole $GOPATH/src/github.com/kataras folder and execute `go get -u github.com/kataras/iris/...` manually\n%v", err)
return
}
golog.Infof("Update process finished.\nManual rebuild and restart is required to apply the changes...\n")
} else if v.UpdateAvailable { // if update was available but choosen not to update.
golog.Infof(ignoreUpdatesMsg)
}
}