forked from orijtech/otils
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Group by functions responsibility.
- Loading branch information
Showing
7 changed files
with
563 additions
and
540 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package otils | ||
|
||
import ( | ||
"net/http" | ||
) | ||
|
||
type CORS struct { | ||
Origins []string | ||
Methods []string | ||
Headers []string | ||
|
||
// AllowCredentials when set signifies that the header | ||
// "Access-Control-Allow-Credentials" which will allow | ||
// the possibility of the frontend XHR's withCredentials=true | ||
// to be set. | ||
AllowCredentials bool | ||
|
||
next http.Handler | ||
} | ||
|
||
func CORSMiddleware(c *CORS, next http.Handler) http.Handler { | ||
if c == nil { | ||
return next | ||
} | ||
copy := new(CORS) | ||
*copy = *c | ||
copy.next = next | ||
return copy | ||
} | ||
|
||
var allInclusiveCORS = &CORS{ | ||
Origins: []string{"*"}, | ||
Methods: []string{"*"}, | ||
Headers: []string{"*"}, | ||
|
||
AllowCredentials: true, | ||
} | ||
|
||
// CORSMiddlewareAllInclusive is a convenience helper that uses the | ||
// all inclusive CORS: | ||
// Access-Control-Allow-Origin: * | ||
// Access-Control-Allow-Methods: * | ||
// Access-Control-Allow-Headers: * | ||
// Access-Control-Allow-Credentials: * | ||
// thus enabling all origins, all methods and all headers. | ||
func CORSMiddlewareAllInclusive(next http.Handler) http.Handler { | ||
return CORSMiddleware(allInclusiveCORS, next) | ||
} | ||
|
||
var _ http.Handler = (*CORS)(nil) | ||
|
||
func (c *CORS) ServeHTTP(rw http.ResponseWriter, req *http.Request) { | ||
c.setCORSForResponseWriter(rw) | ||
if c.next != nil { | ||
c.next.ServeHTTP(rw, req) | ||
} | ||
} | ||
|
||
func (c *CORS) setCORSForResponseWriter(rw http.ResponseWriter) { | ||
for _, origin := range c.Origins { | ||
rw.Header().Add("Access-Control-Allow-Origin", origin) | ||
} | ||
for _, mtd := range c.Methods { | ||
rw.Header().Add("Access-Control-Allow-Methods", mtd) | ||
} | ||
for _, hdr := range c.Headers { | ||
rw.Header().Add("Access-Control-Allow-Headers", hdr) | ||
} | ||
if c.AllowCredentials { | ||
rw.Header().Add("Access-Control-Allow-Credentials", "true") | ||
} | ||
} | ||
|
||
func unexportedField(name string) bool { | ||
return len(name) > 0 && name[0] >= 'a' && name[0] <= 'z' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package otils | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
) | ||
|
||
func EnvOrAlternates(envVar string, alternates ...string) string { | ||
if retr := strings.TrimSpace(os.Getenv(envVar)); retr != "" { | ||
return retr | ||
} | ||
for _, alt := range alternates { | ||
alt = strings.TrimSpace(alt) | ||
if alt != "" { | ||
return alt | ||
} | ||
} | ||
return "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package otils | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
) | ||
|
||
// RedirectAllTrafficTo creates a handler that can be attached | ||
// to an HTTP traffic multiplexer to perform a 301 Permanent Redirect | ||
// to the specified host for any path, anytime that the handler | ||
// receives a request. | ||
// Sample usage is: | ||
// | ||
// httpsRedirectHandler := RedirectAllTrafficTo("https://orijtech.com") | ||
// if err := http.ListenAndServe(":80", httpsRedirectHandler); err != nil { | ||
// log.Fatal(err) | ||
// } | ||
// | ||
// which is used in production at orijtech.com to redirect any non-https | ||
// traffic from http://orijtech.com/* to https://orijtech.com/* | ||
func RedirectAllTrafficTo(host string) http.Handler { | ||
fn := func(rw http.ResponseWriter, req *http.Request) { | ||
finalURL := fmt.Sprintf("%s%s", host, req.URL.Path) | ||
rw.Header().Set("Location", finalURL) | ||
rw.WriteHeader(301) | ||
} | ||
|
||
return http.HandlerFunc(fn) | ||
} | ||
|
||
// StatusOK returns true if a status code is a 2XX code | ||
func StatusOK(code int) bool { return code >= 200 && code <= 299 } | ||
|
||
type CodedError struct { | ||
code int | ||
msg string | ||
} | ||
|
||
func (cerr *CodedError) Error() string { | ||
if cerr == nil { | ||
return "" | ||
} | ||
return cerr.msg | ||
} | ||
|
||
func (cerr *CodedError) Code() int { | ||
if cerr == nil { | ||
return http.StatusOK | ||
} | ||
return cerr.code | ||
} | ||
|
||
func MakeCodedError(msg string, code int) *CodedError { | ||
return &CodedError{ | ||
msg: msg, | ||
code: code, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package otils | ||
|
||
import ( | ||
"encoding/json" | ||
"strconv" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// NullableString represents a string that is sent | ||
// back by some APIs as null, in JSON unquoted which | ||
// makes them un-unmarshalable in Go. | ||
// NullableString interprets null as "". | ||
type NullableString string | ||
|
||
var _ json.Unmarshaler = (*NullableString)(nil) | ||
|
||
func (ns *NullableString) UnmarshalJSON(b []byte) error { | ||
str := string(b) | ||
// Special case when we encounter `null`, modify it to the empty string | ||
if str == "null" || str == "" { | ||
str = "" | ||
} else { | ||
unquoted, err := strconv.Unquote(str) | ||
if err != nil { | ||
return err | ||
} | ||
*ns = NullableString(unquoted) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type NullableFloat64 float64 | ||
|
||
var _ json.Unmarshaler = (*NullableFloat64)(nil) | ||
|
||
func (nf64 *NullableFloat64) UnmarshalJSON(b []byte) error { | ||
str := string(b) | ||
if strings.HasPrefix(str, "\"") { | ||
unquoted, err := strconv.Unquote(str) | ||
if err == nil { | ||
str = unquoted | ||
} | ||
} | ||
|
||
f64, err := strconv.ParseFloat(str, 64) | ||
if err == nil { | ||
*nf64 = NullableFloat64(f64) | ||
return nil | ||
} | ||
|
||
// Otherwise trying checking if it was null | ||
var ns NullableString | ||
if err := json.Unmarshal(b, &ns); err != nil { | ||
return err | ||
} | ||
|
||
if ns == "" { | ||
*nf64 = 0.0 | ||
return nil | ||
} | ||
|
||
f64, err = strconv.ParseFloat(str, 64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
*nf64 = NullableFloat64(f64) | ||
return nil | ||
} | ||
|
||
type NumericBool bool | ||
|
||
func (nb *NumericBool) UnmarshalJSON(blob []byte) error { | ||
if len(blob) < 1 { | ||
*nb = false | ||
return nil | ||
} | ||
|
||
s := string(blob) | ||
// Try first parsing an integer. | ||
pBool, err := strconv.ParseBool(s) | ||
if err == nil { | ||
*nb = NumericBool(pBool) | ||
return nil | ||
} | ||
|
||
pInt, err := strconv.ParseInt(s, 10, 32) | ||
if err != nil { | ||
*nb = pInt != 0 | ||
return nil | ||
} | ||
|
||
return err | ||
} | ||
|
||
type NullableTime time.Time | ||
|
||
var _ json.Unmarshaler = (*NullableTime)(nil) | ||
|
||
func (nt *NullableTime) UnmarshalJSON(b []byte) error { | ||
var ns NullableString | ||
if err := json.Unmarshal(b, &ns); err != nil { | ||
return err | ||
} | ||
if ns == "" { | ||
nt = nil | ||
return nil | ||
} | ||
|
||
// To parse the time, we need to quote the value | ||
quotedStr := strconv.Quote(string(ns)) | ||
t := new(time.Time) | ||
if err := json.Unmarshal([]byte(quotedStr), t); err != nil { | ||
return err | ||
} | ||
|
||
*nt = NullableTime(*t) | ||
return nil | ||
} |
Oops, something went wrong.