mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
add viper configuration example and minor improvements - read HISTORY.md
This commit is contained in:
parent
f9e048e56b
commit
373b8993ad
|
@ -612,6 +612,7 @@ New Package-level Variables:
|
|||
|
||||
New Context Methods:
|
||||
|
||||
- `Context.TextYAML(interface{}) error` same as `Context.YAML` but with set the Content-Type to `text/yaml` instead (Google Chrome renders it as text).
|
||||
- `Context.IsDebug() bool` reports whether the application is running under debug/development mode. It is a shortcut of Application.Logger().Level >= golog.DebugLevel.
|
||||
- `Context.IsRecovered() bool` reports whether the current request was recovered from the [recover middleware](https://github.com/kataras/iris/tree/master/middleware/recover). Also the `iris.IsErrPrivate` function and `iris.ErrPrivate` interface have been introduced.
|
||||
- `Context.RecordBody()` same as the Application's `DisableBodyConsumptionOnUnmarshal` configuration field but registers per chain of handlers. It makes the request body readable more than once.
|
||||
|
@ -657,6 +658,8 @@ New Context Methods:
|
|||
|
||||
Breaking Changes:
|
||||
|
||||
- The `Context.ContentType` does not accept filenames to resolve the mime type anymore (caused issues with vendor-specific(vnd) MIME types).
|
||||
- The `Configuration.RemoteAddrPrivateSubnets.IPRange.Start and End` are now type of `string` instead of `net.IP`. The `WithRemoteAddrPrivateSubnet` option remains as it is, already accepts `string`s.
|
||||
- The `i18n#LoaderConfig.FuncMap template.FuncMap` field was replaced with `Funcs func(iris.Locale) template.FuncMap` in order to give current locale access to the template functions. A new `app.I18n.Loader` was introduced too, in order to make it easier for end-developers to customize the translation key values.
|
||||
- Request Logger's `Columns bool` field has been removed. Use the new [accesslog](https://github.com/kataras/iris/tree/master/_examples/logging/request-logger/accesslog/main.go) middleware instead.
|
||||
- The `.Binary` method of all view engines was removed: pass the go-bindata's latest version `AssetFile()` exported function as the first argument instead of string. All examples updated.
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
* Configuration
|
||||
* [Functional](configuration/functional/main.go)
|
||||
* [Configuration Struct](configuration/from-configuration-structure/main.go)
|
||||
* [Using Viper](configuration/viper)
|
||||
* [Import from YAML](configuration/from-yaml-file/main.go)
|
||||
* [Share Configuration across instances](configuration/from-yaml-file/shared-configuration/main.go)
|
||||
* [Import from TOML](configuration/from-toml-file/main.go)
|
||||
|
|
|
@ -4,5 +4,5 @@ go 1.15
|
|||
|
||||
require (
|
||||
github.com/betacraft/yaag v1.0.1-0.20200719063524-47d781406108
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
github.com/kataras/iris/v12 master
|
||||
)
|
||||
|
|
50
_examples/configuration/viper/config.yml
Normal file
50
_examples/configuration/viper/config.yml
Normal file
|
@ -0,0 +1,50 @@
|
|||
Addr:
|
||||
Internal:
|
||||
IP: 127.0.0.1
|
||||
Plain: 8080
|
||||
Secure: 443
|
||||
Locale:
|
||||
Pattern: "./locales/*/*.ini"
|
||||
Default: "en-US"
|
||||
Supported:
|
||||
- "en-US"
|
||||
- "el-GR"
|
||||
Iris:
|
||||
LogLevel: debug
|
||||
SocketSharding: true
|
||||
EnableOptimizations: true
|
||||
DisableStartupLog: false
|
||||
FireMethodNotAllowed: true
|
||||
ForceLowercaseRouting: true
|
||||
EnablePathIntelligence: true
|
||||
Charset: "utf-8"
|
||||
TimeFormat: "2006-01-02 15:04:05"
|
||||
DisableBodyConsumptionOnUnmarshal: true
|
||||
FireEmptyFormError: true
|
||||
PostMaxMemory: 67108864
|
||||
RemoteAddrHeaders:
|
||||
- "X-Real-Ip"
|
||||
- "X-Forwarded-For"
|
||||
- "CF-Connecting-IP"
|
||||
- "True-Client-Ip"
|
||||
IgnoreServerErrors:
|
||||
- "http: Server closed"
|
||||
# Tunneling:
|
||||
# WebInterface: "http://127.0.0.1:4040"
|
||||
# AuthToken: "<secret>"
|
||||
# Tunnels:
|
||||
# - Name: "My awesome App"
|
||||
# Addr: "localhost:8080"
|
||||
# - Name: "My Second awesome App"
|
||||
# Addr: "localhost:9090"
|
||||
RemoteAddrPrivateSubnets:
|
||||
- Start: "192.168.0.0"
|
||||
End: "192.168.255.255"
|
||||
- Start: "198.18.0.0"
|
||||
End: "198.19.255.255"
|
||||
SSLProxyHeaders:
|
||||
X-Forwarded-Proto: "https"
|
||||
HostProxyHeaders:
|
||||
X-Host: true
|
||||
Other:
|
||||
ServerName: "My awesome Iris web server"
|
54
_examples/configuration/viper/config/config.go
Normal file
54
_examples/configuration/viper/config/config.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
// Viper is a third-party package:
|
||||
// go get github.com/spf13/viper
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
loadConfiguration()
|
||||
}
|
||||
|
||||
// C is the configuration of the app.
|
||||
var C = struct {
|
||||
Iris iris.Configuration
|
||||
Addr struct {
|
||||
Internal struct {
|
||||
IP string
|
||||
Plain int
|
||||
Secure int
|
||||
}
|
||||
}
|
||||
Locale struct {
|
||||
Pattern string
|
||||
Default string
|
||||
Supported []string
|
||||
}
|
||||
}{
|
||||
Iris: iris.DefaultConfiguration(),
|
||||
// other default values...
|
||||
}
|
||||
|
||||
func loadConfiguration() {
|
||||
viper.SetConfigName("config") // name of config file (without extension)
|
||||
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
|
||||
viper.AddConfigPath("/etc/app/") // path to look for the config file in
|
||||
viper.AddConfigPath("$HOME/.app") // call multiple times to add many search paths
|
||||
viper.AddConfigPath(".") // optionally look for config in the working directory
|
||||
err := viper.ReadInConfig() // Find and read the config file
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
} else {
|
||||
panic(fmt.Errorf("load configuration: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
err = viper.Unmarshal(&C)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("load configuration: unmarshal: %w", err))
|
||||
}
|
||||
}
|
8
_examples/configuration/viper/go.mod
Normal file
8
_examples/configuration/viper/go.mod
Normal file
|
@ -0,0 +1,8 @@
|
|||
module app
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/kataras/iris/v12 master
|
||||
github.com/spf13/viper v1.3.2
|
||||
)
|
19
_examples/configuration/viper/main.go
Normal file
19
_examples/configuration/viper/main.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"app/config"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.TextYAML(config.C)
|
||||
})
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", config.C.Addr.Internal.IP, config.C.Addr.Internal.Plain)
|
||||
app.Listen(addr, iris.WithConfiguration(config.C.Iris))
|
||||
}
|
|
@ -4,6 +4,6 @@ go 1.15
|
|||
|
||||
require (
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
github.com/kataras/iris/v12 master
|
||||
go.mongodb.org/mongo-driver v1.3.4
|
||||
)
|
||||
|
|
|
@ -4,6 +4,6 @@ go 1.15
|
|||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
github.com/kataras/iris/v12 master
|
||||
github.com/mailgun/groupcache/v2 v2.1.0
|
||||
)
|
||||
|
|
|
@ -4,5 +4,5 @@ go 1.15
|
|||
|
||||
require (
|
||||
github.com/Shopify/sarama v1.26.4
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
github.com/kataras/iris/v12 master
|
||||
)
|
||||
|
|
|
@ -3,6 +3,6 @@ module github.com/kataras/iris/examples/logging/rollbar
|
|||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
github.com/kataras/iris/v12 master
|
||||
github.com/rollbar/rollbar-go v1.2.0
|
||||
)
|
||||
|
|
|
@ -2,4 +2,4 @@ module app
|
|||
|
||||
go 1.15
|
||||
|
||||
require github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
require github.com/kataras/iris/v12 master
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/kataras/iris/_examples/mvc/vuejs-todo-mvc/src
|
|||
|
||||
go 1.15
|
||||
|
||||
require github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
require github.com/kataras/iris/v12 master
|
||||
|
|
|
@ -2,6 +2,4 @@ module github.com/kataras/iris/_examples/routing/subdomains/redirect/multi-insta
|
|||
|
||||
go 1.15
|
||||
|
||||
require github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
|
||||
replace github.com/kataras/iris/v12 => ../../../../../
|
||||
require github.com/kataras/iris/v12 master
|
|
@ -2,5 +2,5 @@ module app
|
|||
|
||||
go 1.15
|
||||
|
||||
require github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
require github.com/kataras/iris/v12 master
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ go 1.15
|
|||
|
||||
require (
|
||||
github.com/iris-contrib/middleware/jwt v0.0.0-20200710202437-92b01b85baaf
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha // indirect
|
||||
github.com/kataras/iris/v12 master
|
||||
)
|
||||
|
|
|
@ -4,5 +4,5 @@ go 1.15
|
|||
|
||||
require (
|
||||
github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0
|
||||
github.com/kataras/iris/v12 v12.2.0-alpha
|
||||
github.com/kataras/iris/v12 master
|
||||
)
|
||||
|
|
|
@ -3,7 +3,6 @@ package iris
|
|||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
@ -391,8 +390,8 @@ func WithoutRemoteAddrHeader(headerName string) Configurator {
|
|||
func WithRemoteAddrPrivateSubnet(startIP, endIP string) Configurator {
|
||||
return func(app *Application) {
|
||||
app.config.RemoteAddrPrivateSubnets = append(app.config.RemoteAddrPrivateSubnets, netutil.IPRange{
|
||||
Start: net.ParseIP(startIP),
|
||||
End: net.ParseIP(endIP),
|
||||
Start: startIP,
|
||||
End: endIP,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -825,28 +824,28 @@ type Configuration struct {
|
|||
// For details please navigate through: https://github.com/kataras/iris/issues/1453
|
||||
// Defaults to:
|
||||
// {
|
||||
// Start: net.ParseIP("10.0.0.0"),
|
||||
// End: net.ParseIP("10.255.255.255"),
|
||||
// Start: "10.0.0.0",
|
||||
// End: "10.255.255.255",
|
||||
// },
|
||||
// {
|
||||
// Start: net.ParseIP("100.64.0.0"),
|
||||
// End: net.ParseIP("100.127.255.255"),
|
||||
// Start: "100.64.0.0",
|
||||
// End: "100.127.255.255",
|
||||
// },
|
||||
// {
|
||||
// Start: net.ParseIP("172.16.0.0"),
|
||||
// End: net.ParseIP("172.31.255.255"),
|
||||
// Start: "172.16.0.0",
|
||||
// End: "172.31.255.255",
|
||||
// },
|
||||
// {
|
||||
// Start: net.ParseIP("192.0.0.0"),
|
||||
// End: net.ParseIP("192.0.0.255"),
|
||||
// Start: "192.0.0.0",
|
||||
// End: "192.0.0.255",
|
||||
// },
|
||||
// {
|
||||
// Start: net.ParseIP("192.168.0.0"),
|
||||
// End: net.ParseIP("192.168.255.255"),
|
||||
// Start: "192.168.0.0",
|
||||
// End: "192.168.255.255",
|
||||
// },
|
||||
// {
|
||||
// Start: net.ParseIP("198.18.0.0"),
|
||||
// End: net.ParseIP("198.19.255.255"),
|
||||
// Start: "198.18.0.0",
|
||||
// End: "198.19.255.255",
|
||||
// }
|
||||
//
|
||||
// Look `Context.RemoteAddr()` for more.
|
||||
|
@ -1218,28 +1217,28 @@ func DefaultConfiguration() Configuration {
|
|||
RemoteAddrHeadersForce: false,
|
||||
RemoteAddrPrivateSubnets: []netutil.IPRange{
|
||||
{
|
||||
Start: net.ParseIP("10.0.0.0"),
|
||||
End: net.ParseIP("10.255.255.255"),
|
||||
Start: "10.0.0.0",
|
||||
End: "10.255.255.255",
|
||||
},
|
||||
{
|
||||
Start: net.ParseIP("100.64.0.0"),
|
||||
End: net.ParseIP("100.127.255.255"),
|
||||
Start: "100.64.0.0",
|
||||
End: "100.127.255.255",
|
||||
},
|
||||
{
|
||||
Start: net.ParseIP("172.16.0.0"),
|
||||
End: net.ParseIP("172.31.255.255"),
|
||||
Start: "172.16.0.0",
|
||||
End: "172.31.255.255",
|
||||
},
|
||||
{
|
||||
Start: net.ParseIP("192.0.0.0"),
|
||||
End: net.ParseIP("192.0.0.255"),
|
||||
Start: "192.0.0.0",
|
||||
End: "192.0.0.255",
|
||||
},
|
||||
{
|
||||
Start: net.ParseIP("192.168.0.0"),
|
||||
End: net.ParseIP("192.168.255.255"),
|
||||
Start: "192.168.0.0",
|
||||
End: "192.168.255.255",
|
||||
},
|
||||
{
|
||||
Start: net.ParseIP("198.18.0.0"),
|
||||
End: net.ParseIP("198.19.255.255"),
|
||||
Start: "198.18.0.0",
|
||||
End: "198.19.255.255",
|
||||
},
|
||||
},
|
||||
SSLProxyHeaders: make(map[string]string),
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -1323,14 +1322,15 @@ func (ctx *Context) ContentType(cType string) {
|
|||
}
|
||||
|
||||
// 1. if it's path or a filename or an extension,
|
||||
// then take the content type from that
|
||||
if strings.Contains(cType, ".") {
|
||||
ext := filepath.Ext(cType)
|
||||
cType = mime.TypeByExtension(ext)
|
||||
}
|
||||
// then take the content type from that,
|
||||
// ^ No, it's not always a file,e .g. vnd.$type
|
||||
// if strings.Contains(cType, ".") {
|
||||
// ext := filepath.Ext(cType)
|
||||
// cType = mime.TypeByExtension(ext)
|
||||
// }
|
||||
// if doesn't contain a charset already then append it
|
||||
if !strings.Contains(cType, "charset") {
|
||||
if shouldAppendCharset(cType) {
|
||||
if shouldAppendCharset(cType) {
|
||||
if !strings.Contains(cType, "charset") {
|
||||
cType += "; charset=" + ctx.app.ConfigurationReadOnly().GetCharset()
|
||||
}
|
||||
}
|
||||
|
@ -2431,7 +2431,7 @@ func (ctx *Context) ReadBody(ptr interface{}) error {
|
|||
case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
|
||||
return ctx.ReadXML(ptr)
|
||||
// "%v reflect.Indirect(reflect.ValueOf(ptr)).Interface())
|
||||
case ContentYAMLHeaderValue:
|
||||
case ContentYAMLHeaderValue, ContentYAMLTextHeaderValue:
|
||||
return ctx.ReadYAML(ptr)
|
||||
case ContentFormHeaderValue, ContentFormMultipartHeaderValue:
|
||||
return ctx.ReadForm(ptr)
|
||||
|
@ -3009,6 +3009,8 @@ const (
|
|||
ContentMarkdownHeaderValue = "text/markdown"
|
||||
// ContentYAMLHeaderValue header value for YAML data.
|
||||
ContentYAMLHeaderValue = "application/x-yaml"
|
||||
// ContentYAMLTextHeaderValue header value for YAML plain text.
|
||||
ContentYAMLTextHeaderValue = "text/yaml"
|
||||
// ContentProtobufHeaderValue header value for Protobuf messages data.
|
||||
ContentProtobufHeaderValue = "application/x-protobuf"
|
||||
// ContentMsgPackHeaderValue header value for MsgPack data.
|
||||
|
@ -3484,7 +3486,8 @@ func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (int, error) {
|
|||
return n, err
|
||||
}
|
||||
|
||||
// YAML marshals the "v" using the yaml marshaler and renders its result to the client.
|
||||
// YAML marshals the "v" using the yaml marshaler
|
||||
// and sends the result to the client.
|
||||
func (ctx *Context) YAML(v interface{}) (int, error) {
|
||||
out, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
|
@ -3497,6 +3500,13 @@ func (ctx *Context) YAML(v interface{}) (int, error) {
|
|||
return ctx.Write(out)
|
||||
}
|
||||
|
||||
// TextYAML marshals the "v" using the yaml marshaler
|
||||
// and renders to the client.
|
||||
func (ctx *Context) TextYAML(v interface{}) (int, error) {
|
||||
ctx.contentTypeOnce(ContentYAMLTextHeaderValue, "")
|
||||
return ctx.YAML(v)
|
||||
}
|
||||
|
||||
// Protobuf parses the "v" of proto Message and renders its result to the client.
|
||||
func (ctx *Context) Protobuf(v proto.Message) (int, error) {
|
||||
out, err := proto.Marshal(v)
|
||||
|
@ -3735,6 +3745,8 @@ func (ctx *Context) Negotiate(v interface{}) (int, error) {
|
|||
return ctx.XML(v)
|
||||
case ContentYAMLHeaderValue:
|
||||
return ctx.YAML(v)
|
||||
case ContentYAMLTextHeaderValue:
|
||||
return ctx.TextYAML(v)
|
||||
case ContentProtobufHeaderValue:
|
||||
msg, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
|
@ -3918,6 +3930,19 @@ func (n *NegotiationBuilder) YAML(v ...interface{}) *NegotiationBuilder {
|
|||
return n.MIME(ContentYAMLHeaderValue, content)
|
||||
}
|
||||
|
||||
// TextYAML registers the "text/yaml" content type and, optionally,
|
||||
// a value that `Context.Negotiate` will render
|
||||
// when a client accepts the "application/x-yaml" content type.
|
||||
//
|
||||
// Returns itself for recursive calls.
|
||||
func (n *NegotiationBuilder) TextYAML(v ...interface{}) *NegotiationBuilder {
|
||||
var content interface{}
|
||||
if len(v) > 0 {
|
||||
content = v[0]
|
||||
}
|
||||
return n.MIME(ContentYAMLTextHeaderValue, content)
|
||||
}
|
||||
|
||||
// Protobuf registers the "application/x-protobuf" content type and, optionally,
|
||||
// a value that `Context.Negotiate` will render
|
||||
// when a client accepts the "application/x-protobuf" content type.
|
||||
|
@ -4131,6 +4156,12 @@ func (n *NegotiationAcceptBuilder) YAML() *NegotiationAcceptBuilder {
|
|||
return n.MIME(ContentYAMLHeaderValue)
|
||||
}
|
||||
|
||||
// TextYAML adds the "text/yaml" as accepted client content type.
|
||||
// Returns itself.
|
||||
func (n *NegotiationAcceptBuilder) TextYAML() *NegotiationAcceptBuilder {
|
||||
return n.MIME(ContentYAMLTextHeaderValue)
|
||||
}
|
||||
|
||||
// Protobuf adds the "application/x-protobuf" as accepted client content type.
|
||||
// Returns itself.
|
||||
func (n *NegotiationAcceptBuilder) Protobuf() *NegotiationAcceptBuilder {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"net"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/* Based on:
|
||||
|
@ -13,13 +14,18 @@ https://github.com/kataras/iris/issues/1453
|
|||
|
||||
// IPRange is a structure that holds the start and end of a range of IP Addresses.
|
||||
type IPRange struct {
|
||||
Start net.IP `ini:"start" json:"start" yaml:"Start" toml:"Start"`
|
||||
End net.IP `ini:"end" json:"end" yaml:"End" toml:"End"`
|
||||
Start string `ini:"start" json:"start" yaml:"Start" toml:"Start"`
|
||||
End string `ini:"end" json:"end" yaml:"End" toml:"End"`
|
||||
}
|
||||
|
||||
func unsafeCompare(a []byte, b string) int {
|
||||
bb := *(*[]byte)(unsafe.Pointer(&b))
|
||||
return bytes.Compare(a, bb)
|
||||
}
|
||||
|
||||
// IPInRange reports whether a given IP Address is within a range given.
|
||||
func IPInRange(r IPRange, ipAddress net.IP) bool {
|
||||
return bytes.Compare(ipAddress, r.Start) >= 0 && bytes.Compare(ipAddress, r.End) < 0
|
||||
return unsafeCompare(ipAddress, r.Start) >= 0 && unsafeCompare(ipAddress, r.End) < 0
|
||||
}
|
||||
|
||||
// IPIsPrivateSubnet reports whether this "ipAddress" is in a private subnet.
|
||||
|
|
Loading…
Reference in New Issue
Block a user