├── .gitignore
├── vendor
└── github.com
│ ├── zabawaba99
│ └── firego
│ │ ├── sync
│ │ ├── fixtures
│ │ │ ├── scalars
│ │ │ │ ├── decimal.json
│ │ │ │ ├── number.json
│ │ │ │ ├── boolean.json
│ │ │ │ └── string.json
│ │ │ ├── objects
│ │ │ │ ├── simple.json
│ │ │ │ ├── complex.json
│ │ │ │ ├── with_arrays.json
│ │ │ │ └── nested.json
│ │ │ └── arrays
│ │ │ │ ├── booleans.json
│ │ │ │ ├── numbers.json
│ │ │ │ ├── strings.json
│ │ │ │ └── decimals.json
│ │ ├── node_bench_test.go
│ │ ├── database_test.go
│ │ ├── database.go
│ │ ├── node.go
│ │ └── node_test.go
│ │ ├── .gitignore
│ │ ├── internal
│ │ └── firetest
│ │ │ ├── exmaple_test.go
│ │ │ ├── README.md
│ │ │ ├── notify_db_test.go
│ │ │ ├── direct.go
│ │ │ ├── direct_test.go
│ │ │ ├── notify_db.go
│ │ │ └── server.go
│ │ ├── LICENSE
│ │ ├── snapshot.go
│ │ ├── snapshot_test.go
│ │ ├── .travis.yml
│ │ ├── transaction_test.go
│ │ ├── transaction.go
│ │ ├── example_test.go
│ │ ├── README.md
│ │ ├── firebase_test.go
│ │ ├── watch.go
│ │ ├── watch_test.go
│ │ ├── query_test.go
│ │ ├── query.go
│ │ ├── event_callback.go
│ │ └── firebase.go
│ ├── gorilla
│ ├── context
│ │ ├── README.md
│ │ ├── .travis.yml
│ │ ├── LICENSE
│ │ ├── doc.go
│ │ ├── context_test.go
│ │ └── context.go
│ └── mux
│ │ ├── .travis.yml
│ │ ├── context_native.go
│ │ ├── context_gorilla.go
│ │ ├── context_native_test.go
│ │ ├── context_gorilla_test.go
│ │ ├── LICENSE
│ │ ├── bench_test.go
│ │ └── doc.go
│ └── urfave
│ └── negroni
│ ├── recovery_test.go
│ ├── logger_test.go
│ ├── doc.go
│ ├── logger.go
│ ├── CHANGELOG.md
│ ├── recovery.go
│ ├── LICENSE
│ ├── static.go
│ ├── negroni_test.go
│ ├── static_test.go
│ ├── response_writer.go
│ ├── response_writer_test.go
│ ├── negroni.go
│ └── translations
│ ├── README_zh_tw.md
│ ├── README_zh_cn.md
│ ├── README_pt_br.md
│ └── README_de_de.md
├── helm
├── seanmeme
│ ├── Chart.yaml
│ ├── .helmignore
│ ├── templates
│ │ ├── _helpers.tpl
│ │ ├── service.yaml
│ │ ├── ingress.yaml
│ │ ├── deployment.yaml
│ │ └── NOTES.txt
│ └── values.yaml
└── helm-init.sh
├── Dockerfile
├── Makefile
├── Gopkg.toml
├── Gopkg.lock
├── main.go
├── Jenkinsfile
└── static
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | gin-bin
2 | static/memes
3 | /seanmeme
4 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/scalars/decimal.json:
--------------------------------------------------------------------------------
1 | 2.2
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/scalars/number.json:
--------------------------------------------------------------------------------
1 | 2
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/scalars/boolean.json:
--------------------------------------------------------------------------------
1 | false
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/scalars/string.json:
--------------------------------------------------------------------------------
1 | "foo"
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/objects/simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "foo": "bar"
3 | }
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/arrays/booleans.json:
--------------------------------------------------------------------------------
1 | [
2 | true,
3 | false
4 | ]
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/arrays/numbers.json:
--------------------------------------------------------------------------------
1 | [
2 | 1,
3 | 2,
4 | 3
5 | ]
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/arrays/strings.json:
--------------------------------------------------------------------------------
1 | [
2 | "foo",
3 | "bar"
4 | ]
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/arrays/decimals.json:
--------------------------------------------------------------------------------
1 | [
2 | 1.1,
3 | 2.2,
4 | 3.3
5 | ]
--------------------------------------------------------------------------------
/helm/seanmeme/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | description: A Helm chart for Kubernetes
3 | name: seanmeme
4 | version: 0.1.0
5 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/objects/complex.json:
--------------------------------------------------------------------------------
1 | {
2 | "foo": "bar",
3 | "foo1": 2,
4 | "foo2": true,
5 | "foo3": 3.42
6 | }
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine
2 |
3 | RUN apk add -U ca-certificates
4 |
5 | COPY static/ /static/
6 | COPY seanmeme /
7 |
8 | ENV PORT 8080
9 |
10 | CMD ["/seanmeme"]
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | build:
2 | docker run --rm -v "${PWD}":/go/src/seanmeme -w /go/src/seanmeme -e CGO_ENABLED=0 golang:1.8 go build
3 |
4 | docker-image: build
5 | docker build -t prydonius/seanmeme .
6 |
--------------------------------------------------------------------------------
/helm/helm-init.sh:
--------------------------------------------------------------------------------
1 | HELM_URL=https://storage.googleapis.com/kubernetes-helm
2 | HELM_TARBALL=helm-v2.4.1-linux-amd64.tar.gz
3 | curl -O $HELM_URL/$HELM_TARBALL
4 | tar xzfv $HELM_TARBALL -C /home/jenkins && rm $HELM_TARBALL
5 | export PATH=/home/jenkins/linux-amd64/:$PATH
6 | helm init --client-only
7 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/objects/with_arrays.json:
--------------------------------------------------------------------------------
1 | {
2 | "regular": "item",
3 | "booleans": [
4 | false,
5 | true
6 | ],
7 | "numbers": [
8 | 1,
9 | 2
10 | ],
11 | "decimals": [
12 | 1.1,
13 | 2.2
14 | ],
15 | "strings": [
16 | "foo",
17 | "bar"
18 | ]
19 | }
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/context/README.md:
--------------------------------------------------------------------------------
1 | context
2 | =======
3 | [](https://travis-ci.org/gorilla/context)
4 |
5 | gorilla/context is a general purpose registry for global request variables.
6 |
7 | Read the full documentation here: http://www.gorillatoolkit.org/pkg/context
8 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/context/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | sudo: false
3 |
4 | matrix:
5 | include:
6 | - go: 1.3
7 | - go: 1.4
8 | - go: 1.5
9 | - go: 1.6
10 | - go: tip
11 |
12 | install:
13 | - go get golang.org/x/tools/cmd/vet
14 |
15 | script:
16 | - go get -t -v ./...
17 | - diff -u <(echo -n) <(gofmt -d .)
18 | - go tool vet .
19 | - go test -v -race ./...
20 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 |
10 | # Architecture specific extensions/prefixes
11 | *.[568vq]
12 | [568vq].out
13 |
14 | *.cgo1.go
15 | *.cgo2.c
16 | _cgo_defun.c
17 | _cgo_gotypes.go
18 | _cgo_export.*
19 |
20 | _testmain.go
21 |
22 | *.exe
23 | *.test
24 | *.prof
25 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | sudo: false
3 |
4 | matrix:
5 | include:
6 | - go: 1.2
7 | - go: 1.3
8 | - go: 1.4
9 | - go: 1.5
10 | - go: 1.6
11 | - go: 1.7
12 | - go: 1.8
13 | - go: tip
14 |
15 | install:
16 | - # Skip
17 |
18 | script:
19 | - go get -t -v ./...
20 | - diff -u <(echo -n) <(gofmt -d .)
21 | - go tool vet .
22 | - go test -v -race ./...
23 |
--------------------------------------------------------------------------------
/helm/seanmeme/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *~
18 | # Various IDEs
19 | .project
20 | .idea/
21 | *.tmproj
22 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/context_native.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package mux
4 |
5 | import (
6 | "context"
7 | "net/http"
8 | )
9 |
10 | func contextGet(r *http.Request, key interface{}) interface{} {
11 | return r.Context().Value(key)
12 | }
13 |
14 | func contextSet(r *http.Request, key, val interface{}) *http.Request {
15 | if val == nil {
16 | return r
17 | }
18 |
19 | return r.WithContext(context.WithValue(r.Context(), key, val))
20 | }
21 |
22 | func contextClear(r *http.Request) {
23 | return
24 | }
25 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/context_gorilla.go:
--------------------------------------------------------------------------------
1 | // +build !go1.7
2 |
3 | package mux
4 |
5 | import (
6 | "net/http"
7 |
8 | "github.com/gorilla/context"
9 | )
10 |
11 | func contextGet(r *http.Request, key interface{}) interface{} {
12 | return context.Get(r, key)
13 | }
14 |
15 | func contextSet(r *http.Request, key, val interface{}) *http.Request {
16 | if val == nil {
17 | return r
18 | }
19 |
20 | context.Set(r, key, val)
21 | return r
22 | }
23 |
24 | func contextClear(r *http.Request) {
25 | context.Clear(r)
26 | }
27 |
--------------------------------------------------------------------------------
/helm/seanmeme/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "name" -}}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7 | {{- end -}}
8 |
9 | {{/*
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12 | */}}
13 | {{- define "fullname" -}}
14 | {{- $name := default .Chart.Name .Values.nameOverride -}}
15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
16 | {{- end -}}
17 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/fixtures/objects/nested.json:
--------------------------------------------------------------------------------
1 | {
2 | "dinosaurs": {
3 | "bruhathkayosaurus": {
4 | "appeared": -70000000,
5 | "height": 25,
6 | "length": 44,
7 | "order": "saurischia",
8 | "vanished": -70000000,
9 | "weight": 135000
10 | },
11 | "lambeosaurus": {
12 | "appeared": -76000000,
13 | "height": 2.1,
14 | "length": 12.5,
15 | "order": "ornithischia",
16 | "vanished": -75000000,
17 | "weight": 5000
18 | }
19 | },
20 | "scores": {
21 | "bruhathkayosaurus": 55,
22 | "lambeosaurus": 21
23 | }
24 | }
--------------------------------------------------------------------------------
/helm/seanmeme/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ template "fullname" . }}
5 | labels:
6 | app: {{ template "name" . }}
7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
8 | release: {{ .Release.Name }}
9 | heritage: {{ .Release.Service }}
10 | spec:
11 | type: {{ .Values.service.type }}
12 | ports:
13 | - port: {{ .Values.service.externalPort }}
14 | targetPort: {{ .Values.service.internalPort }}
15 | protocol: TCP
16 | name: {{ .Values.service.name }}
17 | selector:
18 | app: {{ template "name" . }}
19 | release: {{ .Release.Name }}
20 |
--------------------------------------------------------------------------------
/Gopkg.toml:
--------------------------------------------------------------------------------
1 |
2 | # Gopkg.toml example
3 | #
4 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
5 | # for detailed Gopkg.toml documentation.
6 | #
7 | # required = ["github.com/user/thing/cmd/thing"]
8 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
9 | #
10 | # [[constraint]]
11 | # name = "github.com/user/project"
12 | # version = "1.0.0"
13 | #
14 | # [[constraint]]
15 | # name = "github.com/user/project2"
16 | # branch = "dev"
17 | # source = "github.com/myfork/project2"
18 | #
19 | # [[override]]
20 | # name = "github.com/x/y"
21 | # version = "2.4.0"
22 |
23 |
24 | [[constraint]]
25 | name = "github.com/urfave/negroni"
26 | version = "0.2.0"
27 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/exmaple_test.go:
--------------------------------------------------------------------------------
1 | package firetest_test
2 |
3 | import (
4 | "io/ioutil"
5 | "log"
6 | "net/http"
7 | "strings"
8 |
9 | "github.com/zabawaba99/firego/internal/firetest"
10 | )
11 |
12 | func Example() {
13 | ft := firetest.New()
14 | defer ft.Close()
15 |
16 | ft.Start()
17 |
18 | resp, err := http.Post(ft.URL+"/foo.json", "application/json", strings.NewReader(`{"bar":true}`))
19 | if err != nil {
20 | log.Fatal(err)
21 | }
22 | defer resp.Body.Close()
23 |
24 | b, err := ioutil.ReadAll(resp.Body)
25 | if err != nil {
26 | log.Fatal(err)
27 | }
28 |
29 | log.Printf("Post Resp: %s\n", string(b))
30 |
31 | v := ft.Get("foo/bar")
32 | log.Printf("Value: %v", v)
33 | }
34 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/recovery_test.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "bytes"
5 | "log"
6 | "net/http"
7 | "net/http/httptest"
8 | "testing"
9 | )
10 |
11 | func TestRecovery(t *testing.T) {
12 | buff := bytes.NewBufferString("")
13 | recorder := httptest.NewRecorder()
14 |
15 | rec := NewRecovery()
16 | rec.Logger = log.New(buff, "[negroni] ", 0)
17 |
18 | n := New()
19 | // replace log for testing
20 | n.Use(rec)
21 | n.UseHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
22 | panic("here is a panic!")
23 | }))
24 | n.ServeHTTP(recorder, (*http.Request)(nil))
25 | expect(t, recorder.Code, http.StatusInternalServerError)
26 | refute(t, recorder.Body.Len(), 0)
27 | refute(t, len(buff.String()), 0)
28 | }
29 |
--------------------------------------------------------------------------------
/helm/seanmeme/templates/ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: extensions/v1beta1
2 | kind: Ingress
3 | metadata:
4 | name: {{ template "fullname" . }}
5 | annotations:
6 | kubernetes.io/ingress.class: nginx
7 | {{- if .Values.ingress.tls }}
8 | kubernetes.io/tls-acme: 'true'
9 | {{- end }}
10 | labels:
11 | chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
12 | spec:
13 | rules:
14 | - http:
15 | paths:
16 | - backend:
17 | serviceName: {{ template "fullname" . }}
18 | servicePort: {{ .Values.service.externalPort }}
19 | path: /
20 | host: {{ .Values.ingress.host | quote }}
21 | {{- if .Values.ingress.tls }}
22 | tls:
23 | - secretName: {{ .Values.ingress.host }}-tls
24 | hosts:
25 | - {{ .Values.ingress.host | quote }}
26 | {{- end -}}
27 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/logger_test.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "bytes"
5 | "log"
6 | "net/http"
7 | "net/http/httptest"
8 | "testing"
9 | )
10 |
11 | func Test_Logger(t *testing.T) {
12 | buff := bytes.NewBufferString("")
13 | recorder := httptest.NewRecorder()
14 |
15 | l := NewLogger()
16 | l.Logger = log.New(buff, "[negroni] ", 0)
17 |
18 | n := New()
19 | // replace log for testing
20 | n.Use(l)
21 | n.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
22 | rw.WriteHeader(http.StatusNotFound)
23 | }))
24 |
25 | req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil)
26 | if err != nil {
27 | t.Error(err)
28 | }
29 |
30 | n.ServeHTTP(recorder, req)
31 | expect(t, recorder.Code, http.StatusNotFound)
32 | refute(t, len(buff.String()), 0)
33 | }
34 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/doc.go:
--------------------------------------------------------------------------------
1 | // Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers.
2 | //
3 | // If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
4 | //
5 | // For a full guide visit http://github.com/codegangsta/negroni
6 | //
7 | // package main
8 | //
9 | // import (
10 | // "github.com/codegangsta/negroni"
11 | // "net/http"
12 | // "fmt"
13 | // )
14 | //
15 | // func main() {
16 | // mux := http.NewServeMux()
17 | // mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
18 | // fmt.Fprintf(w, "Welcome to the home page!")
19 | // })
20 | //
21 | // n := negroni.Classic()
22 | // n.UseHandler(mux)
23 | // n.Run(":3000")
24 | // }
25 | package negroni
26 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/context_native_test.go:
--------------------------------------------------------------------------------
1 | // +build go1.7
2 |
3 | package mux
4 |
5 | import (
6 | "context"
7 | "net/http"
8 | "testing"
9 | "time"
10 | )
11 |
12 | func TestNativeContextMiddleware(t *testing.T) {
13 | withTimeout := func(h http.Handler) http.Handler {
14 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15 | ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
16 | defer cancel()
17 | h.ServeHTTP(w, r.WithContext(ctx))
18 | })
19 | }
20 |
21 | r := NewRouter()
22 | r.Handle("/path/{foo}", withTimeout(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
23 | vars := Vars(r)
24 | if vars["foo"] != "bar" {
25 | t.Fatal("Expected foo var to be set")
26 | }
27 | })))
28 |
29 | rec := NewRecorder()
30 | req := newRequest("GET", "/path/bar")
31 | r.ServeHTTP(rec, req)
32 | }
33 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/logger.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "os"
7 | "time"
8 | )
9 |
10 | // Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
11 | type Logger struct {
12 | // Logger inherits from log.Logger used to log messages with the Logger middleware
13 | *log.Logger
14 | }
15 |
16 | // NewLogger returns a new Logger instance
17 | func NewLogger() *Logger {
18 | return &Logger{log.New(os.Stdout, "[negroni] ", 0)}
19 | }
20 |
21 | func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
22 | start := time.Now()
23 | l.Printf("Started %s %s", r.Method, r.URL.Path)
24 |
25 | next(rw, r)
26 |
27 | res := rw.(ResponseWriter)
28 | l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start))
29 | }
30 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | **ATTN**: This project uses [semantic versioning](http://semver.org/).
4 |
5 | ## [Unreleased]
6 |
7 | ## [0.2.0] - 2016-05-10
8 | ### Added
9 | - Support for variadic handlers in `New()`
10 | - Added `Negroni.Handlers()` to fetch all of the handlers for a given chain
11 | - Allowed size in `Recovery` handler was bumped to 8k
12 | - `Negroni.UseFunc` to push another handler onto the chain
13 |
14 | ### Changed
15 | - Set the status before calling `beforeFuncs` so the information is available to them
16 | - Set default status to `200` in the case that no handler writes status -- was previously `0`
17 | - Panic if `nil` handler is given to `negroni.Use`
18 |
19 | ## 0.1.0 - 2013-07-22
20 | ### Added
21 | - Initial implementation.
22 |
23 | [Unreleased]: https://github.com/codegangsta/negroni/compare/v0.2.0...HEAD
24 | [0.2.0]: https://github.com/codegangsta/negroni/compare/v0.1.0...v0.2.0
25 |
--------------------------------------------------------------------------------
/helm/seanmeme/values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for seanmeme.
2 | # This is a YAML-formatted file.
3 | # Declare variables to be passed into your templates.
4 | replicaCount: 1
5 | image:
6 | repository: prydonius/seanmeme
7 | tag: latest
8 | pullPolicy: IfNotPresent
9 | service:
10 | name: http
11 | type: ClusterIP
12 | externalPort: 80
13 | internalPort: 8080
14 | ingress:
15 | host: seanmeme.local
16 | # Enable automatic TLS with Let's Encrypt
17 | tls: true
18 | resources: {}
19 | # We usually recommend not to specify default resources and to leave this as a conscious
20 | # choice for the user. This also increases chances charts run on environments with little
21 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
22 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
23 | # limits:
24 | # cpu: 100m
25 | # memory: 128Mi
26 | #requests:
27 | # cpu: 100m
28 | # memory: 128Mi
29 |
--------------------------------------------------------------------------------
/Gopkg.lock:
--------------------------------------------------------------------------------
1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
2 |
3 |
4 | [[projects]]
5 | name = "github.com/gorilla/context"
6 | packages = ["."]
7 | revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
8 | version = "v1.1"
9 |
10 | [[projects]]
11 | name = "github.com/gorilla/mux"
12 | packages = ["."]
13 | revision = "bcd8bc72b08df0f70df986b97f95590779502d31"
14 | version = "v1.4.0"
15 |
16 | [[projects]]
17 | name = "github.com/urfave/negroni"
18 | packages = ["."]
19 | revision = "fde5e16d32adc7ad637e9cd9ad21d4ebc6192535"
20 | version = "v0.2.0"
21 |
22 | [[projects]]
23 | branch = "v1"
24 | name = "github.com/zabawaba99/firego"
25 | packages = [".","sync"]
26 | revision = "4d07741c1dde0b0d76218e8365baea10c33cf968"
27 |
28 | [solve-meta]
29 | analyzer-name = "dep"
30 | analyzer-version = 1
31 | inputs-digest = "6898dfc6d22ee826a60f29484f714d2e61de34a26550d2d8f1b3c8899dbf0f3d"
32 | solver-name = "gps-cdcl"
33 | solver-version = 1
34 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/context_gorilla_test.go:
--------------------------------------------------------------------------------
1 | // +build !go1.7
2 |
3 | package mux
4 |
5 | import (
6 | "net/http"
7 | "testing"
8 |
9 | "github.com/gorilla/context"
10 | )
11 |
12 | // Tests that the context is cleared or not cleared properly depending on
13 | // the configuration of the router
14 | func TestKeepContext(t *testing.T) {
15 | func1 := func(w http.ResponseWriter, r *http.Request) {}
16 |
17 | r := NewRouter()
18 | r.HandleFunc("/", func1).Name("func1")
19 |
20 | req, _ := http.NewRequest("GET", "http://localhost/", nil)
21 | context.Set(req, "t", 1)
22 |
23 | res := new(http.ResponseWriter)
24 | r.ServeHTTP(*res, req)
25 |
26 | if _, ok := context.GetOk(req, "t"); ok {
27 | t.Error("Context should have been cleared at end of request")
28 | }
29 |
30 | r.KeepContext = true
31 |
32 | req, _ = http.NewRequest("GET", "http://localhost/", nil)
33 | context.Set(req, "t", 1)
34 |
35 | r.ServeHTTP(*res, req)
36 | if _, ok := context.GetOk(req, "t"); !ok {
37 | t.Error("Context should NOT have been cleared at end of request")
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/recovery.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "os"
8 | "runtime"
9 | )
10 |
11 | // Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
12 | type Recovery struct {
13 | Logger *log.Logger
14 | PrintStack bool
15 | StackAll bool
16 | StackSize int
17 | }
18 |
19 | // NewRecovery returns a new instance of Recovery
20 | func NewRecovery() *Recovery {
21 | return &Recovery{
22 | Logger: log.New(os.Stdout, "[negroni] ", 0),
23 | PrintStack: true,
24 | StackAll: false,
25 | StackSize: 1024 * 8,
26 | }
27 | }
28 |
29 | func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
30 | defer func() {
31 | if err := recover(); err != nil {
32 | rw.WriteHeader(http.StatusInternalServerError)
33 | stack := make([]byte, rec.StackSize)
34 | stack = stack[:runtime.Stack(stack, rec.StackAll)]
35 |
36 | f := "PANIC: %s\n%s"
37 | rec.Logger.Printf(f, err, stack)
38 |
39 | if rec.PrintStack {
40 | fmt.Fprintf(rw, f, err, stack)
41 | }
42 | }
43 | }()
44 |
45 | next(rw, r)
46 | }
47 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Steven Berlanga, Google Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/README.md:
--------------------------------------------------------------------------------
1 | # firetest
2 |
3 | Firebase test server meant for use in unit tests
4 |
5 | ### Implemented
6 |
7 | * [Basic API Usage](https://www.firebase.com/docs/rest/api/#section-api-usage)
8 | * POST
9 | * GET
10 | * PUT
11 | * PATCH
12 | * DELETE
13 | * [Query parameters](https://www.firebase.com/docs/rest/api/#section-query-parameters):
14 | * auth
15 | * [Streaming](https://www.firebase.com/docs/rest/api/#section-streaming)
16 |
17 | ### Not Supported
18 |
19 | * [Query parameters](https://www.firebase.com/docs/rest/api/#section-query-parameters):
20 | * shallow
21 | * print
22 | * format
23 | * download
24 | * [Priorities](https://www.firebase.com/docs/rest/api/#section-priorities)
25 | * [Server Values](https://www.firebase.com/docs/rest/api/#section-server-values)
26 | * [Security Rules](https://www.firebase.com/docs/rest/api/#section-security-rules)
27 | * [Error Conditions](https://www.firebase.com/docs/rest/api/#section-error-conditions)
28 |
29 | ## Contributing
30 |
31 | 1. Fork it
32 | 2. Create your feature branch (`git checkout -b new-feature`)
33 | 3. Commit your changes (`git commit -am 'awesome things with tests'`)
34 | 4. Push to the branch (`git push origin new-feature`)
35 | 5. Create new Pull Request
36 |
--------------------------------------------------------------------------------
/helm/seanmeme/templates/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: extensions/v1beta1
2 | kind: Deployment
3 | metadata:
4 | name: {{ template "fullname" . }}
5 | labels:
6 | app: {{ template "name" . }}
7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
8 | release: {{ .Release.Name }}
9 | heritage: {{ .Release.Service }}
10 | spec:
11 | replicas: {{ .Values.replicaCount }}
12 | template:
13 | metadata:
14 | labels:
15 | app: {{ template "name" . }}
16 | release: {{ .Release.Name }}
17 | spec:
18 | containers:
19 | - name: {{ .Chart.Name }}
20 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
21 | imagePullPolicy: {{ .Values.image.pullPolicy }}
22 | ports:
23 | - containerPort: {{ .Values.service.internalPort }}
24 | livenessProbe:
25 | httpGet:
26 | path: /
27 | port: {{ .Values.service.internalPort }}
28 | readinessProbe:
29 | httpGet:
30 | path: /
31 | port: {{ .Values.service.internalPort }}
32 | resources:
33 | {{ toYaml .Values.resources | indent 12 }}
34 | {{- if .Values.nodeSelector }}
35 | nodeSelector:
36 | {{ toYaml .Values.nodeSelector | indent 8 }}
37 | {{- end }}
38 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/snapshot.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/zabawaba99/firego/sync"
7 | )
8 |
9 | // DataSnapshot instances contains data from a Firebase reference.
10 | type DataSnapshot struct {
11 | // Key retrieves the key for the source location of this snapshot
12 | Key string
13 |
14 | // Value retrieves the data contained in this snapshot.
15 | Value interface{}
16 | }
17 |
18 | func newSnapshot(node *sync.Node) DataSnapshot {
19 | return DataSnapshot{
20 | Key: node.Key,
21 | Value: node.Objectify(),
22 | }
23 | }
24 |
25 | // Child gets a DataSnapshot for the location at the specified relative path.
26 | // The relative path can either be a simple child key (e.g. 'fred') or a deeper
27 | // slash-separated path (e.g. 'fred/name/first').
28 | func (d *DataSnapshot) Child(name string) (DataSnapshot, bool) {
29 | name = strings.Trim(name, "/")
30 | rabbitHole := strings.Split(name, "/")
31 |
32 | current := *d
33 | for _, tkn := range rabbitHole {
34 | children, ok := current.Value.(map[string]interface{})
35 | if !ok {
36 | return current, false
37 | }
38 |
39 | v, ok := children[tkn]
40 | if !ok {
41 | return current, ok
42 | }
43 |
44 | current = DataSnapshot{
45 | Key: tkn,
46 | Value: v,
47 | }
48 | }
49 |
50 | return current, true
51 | }
52 |
--------------------------------------------------------------------------------
/helm/seanmeme/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | 1. Get the application URL by running these commands:
2 | {{- if .Values.ingress.hostname }}
3 | http://{{- .Values.ingress.hostname }}
4 | {{- else if contains "NodePort" .Values.service.type }}
5 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
6 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
7 | echo http://$NODE_IP:$NODE_PORT
8 | {{- else if contains "LoadBalancer" .Values.service.type }}
9 | NOTE: It may take a few minutes for the LoadBalancer IP to be available.
10 | You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}'
11 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
12 | echo http://$SERVICE_IP:{{ .Values.service.externalPort }}
13 | {{- else if contains "ClusterIP" .Values.service.type }}
14 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
15 | echo "Visit http://127.0.0.1:8080 to use your application"
16 | kubectl port-forward $POD_NAME 8080:{{ .Values.service.externalPort }}
17 | {{- end }}
18 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/snapshot_test.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | "github.com/stretchr/testify/require"
8 | "github.com/zabawaba99/firego/sync"
9 | )
10 |
11 | func TestDataSnapshotKey(t *testing.T) {
12 | n := sync.Node{Key: "foo"}
13 | d := newSnapshot(&n)
14 |
15 | assert.Equal(t, n.Key, d.Key)
16 | }
17 |
18 | func TestDataSnapshotValue(t *testing.T) {
19 | n := sync.Node{Value: "foo"}
20 | d := newSnapshot(&n)
21 |
22 | assert.Equal(t, n.Value, d.Value)
23 | }
24 |
25 | func TestDataSnapshotChild(t *testing.T) {
26 | n := sync.NewNode("", map[string]interface{}{
27 | "one": map[string]interface{}{
28 | "two": map[string]interface{}{
29 | "three": true,
30 | },
31 | },
32 | })
33 | d := newSnapshot(n)
34 |
35 | one, ok := d.Child("one")
36 | require.True(t, ok)
37 | assert.Equal(t, one.Key, "one")
38 | assert.Equal(t, one.Value, map[string]interface{}{
39 | "two": map[string]interface{}{
40 | "three": true,
41 | },
42 | })
43 |
44 | two, ok := one.Child("two")
45 | require.True(t, ok)
46 | assert.Equal(t, two.Key, "two")
47 | assert.Equal(t, two.Value, map[string]interface{}{
48 | "three": true,
49 | })
50 |
51 | three, ok := two.Child("three")
52 | require.True(t, ok)
53 | assert.Equal(t, three.Key, "three")
54 | assert.Equal(t, three.Value, true)
55 |
56 | three2, ok := d.Child("one/two/three")
57 | require.True(t, ok)
58 | assert.Equal(t, three, three2)
59 | }
60 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/context/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the name of Google Inc. nor the names of its
14 | contributors may be used to endorse or promote products derived from
15 | this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the name of Google Inc. nor the names of its
14 | contributors may be used to endorse or promote products derived from
15 | this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/bench_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package mux
6 |
7 | import (
8 | "net/http"
9 | "net/http/httptest"
10 | "testing"
11 | )
12 |
13 | func BenchmarkMux(b *testing.B) {
14 | router := new(Router)
15 | handler := func(w http.ResponseWriter, r *http.Request) {}
16 | router.HandleFunc("/v1/{v1}", handler)
17 |
18 | request, _ := http.NewRequest("GET", "/v1/anything", nil)
19 | for i := 0; i < b.N; i++ {
20 | router.ServeHTTP(nil, request)
21 | }
22 | }
23 |
24 | func BenchmarkMuxAlternativeInRegexp(b *testing.B) {
25 | router := new(Router)
26 | handler := func(w http.ResponseWriter, r *http.Request) {}
27 | router.HandleFunc("/v1/{v1:(?:a|b)}", handler)
28 |
29 | requestA, _ := http.NewRequest("GET", "/v1/a", nil)
30 | requestB, _ := http.NewRequest("GET", "/v1/b", nil)
31 | for i := 0; i < b.N; i++ {
32 | router.ServeHTTP(nil, requestA)
33 | router.ServeHTTP(nil, requestB)
34 | }
35 | }
36 |
37 | func BenchmarkManyPathVariables(b *testing.B) {
38 | router := new(Router)
39 | handler := func(w http.ResponseWriter, r *http.Request) {}
40 | router.HandleFunc("/v1/{v1}/{v2}/{v3}/{v4}/{v5}", handler)
41 |
42 | matchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4/5", nil)
43 | notMatchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4", nil)
44 | recorder := httptest.NewRecorder()
45 | for i := 0; i < b.N; i++ {
46 | router.ServeHTTP(nil, matchingRequest)
47 | router.ServeHTTP(recorder, notMatchingRequest)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/base64"
5 | "fmt"
6 | "io/ioutil"
7 | "log"
8 | "net/http"
9 | "os"
10 |
11 | "github.com/gorilla/mux"
12 | "github.com/urfave/negroni"
13 | "github.com/zabawaba99/firego"
14 | )
15 |
16 | func main() {
17 | f := firego.New("https://seanmeme-fdcf7.firebaseio.com/memes", nil)
18 | r := mux.NewRouter()
19 |
20 | r.Methods("POST").Path("/gen/{type}/{text}").HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
21 | vars := mux.Vars(req)
22 | memeType := vars["type"]
23 | text := vars["text"]
24 |
25 | var url string
26 | switch memeType {
27 | case "winter":
28 | // Shamefully using the awesome https://github.com/jacebrowning/memegen
29 | url = "https://memegen.link/winter/brace_yourselves/" + text + ".jpg"
30 | case "mordor":
31 | url = "https://memegen.link/mordor/one_does_not_simply/" + text + ".jpg"
32 | default:
33 | fmt.Fprint(w, "not found")
34 | return
35 | }
36 |
37 | response, err := http.Get(url + "?width=250")
38 | if err != nil {
39 | log.Print(err)
40 | return
41 | }
42 | defer response.Body.Close()
43 |
44 | data, err := ioutil.ReadAll(response.Body)
45 | if err != nil {
46 | log.Print(err)
47 | return
48 | }
49 |
50 | img := base64.StdEncoding.EncodeToString(data)
51 | _, err = f.Push(img)
52 | if err != nil {
53 | log.Print(err)
54 | return
55 | }
56 | })
57 |
58 | r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
59 |
60 | n := negroni.Classic() // Includes some default middlewares
61 | n.UseHandler(r)
62 |
63 | port := os.Getenv("PORT")
64 | addr := ":" + port
65 | http.ListenAndServe(addr, n)
66 | }
67 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.8
5 | - 1.9
6 | - tip
7 |
8 | matrix:
9 | allow_failures:
10 | - go: tip
11 | fast_finish: true
12 |
13 | before_install:
14 | # linting tools
15 | - go get github.com/golang/lint/golint
16 | - go get github.com/fzipp/gocyclo
17 |
18 | # code coverage
19 | - go get github.com/axw/gocov/gocov
20 | - go get github.com/mattn/goveralls
21 | - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
22 |
23 | install:
24 | # make sure stuff actually builds
25 | - go build
26 |
27 | script:
28 | # ensure everything is formatted all pretty like
29 | - if gofmt -l -s . | grep '**.go'; then exit 1; fi
30 | # vet out possible issues
31 | - go vet ./...
32 | # run tests
33 | - go get -t
34 | - go test -a -race -v ./...
35 |
36 | after_success:
37 | - |
38 | echo "mode: count" > profile.cov
39 | for dir in $(find . -maxdepth 10 -not -path 'vendor' -not -path './.git*' -not -path '*/_*' -type d);
40 | do
41 | if ls $dir/*.go &> /dev/null; then
42 | go test -covermode=count -coverprofile=$dir/profile.tmp $dir
43 | if [ -f $dir/profile.tmp ]
44 | then
45 | cat $dir/profile.tmp | tail -n +2 >> profile.cov
46 | rm $dir/profile.tmp
47 | fi
48 | fi
49 | done
50 | go tool cover -func profile.cov
51 | goveralls -coverprofile=profile.cov -service=travis-ci -repotoken=$COVERALLS -v
52 |
53 | after_script:
54 | # check possible styling errors
55 | - golint ./...
56 | # check for potentially complex functions but don't false build
57 | - gocyclo -over 15 . || true
58 | # refresh godocs in case there were api changes
59 | - |
60 | if [[ "$TRAVIS_PULL_REQUEST" == "false" ]] && [[ "$TRAVIS_BRANCH" == "master" ]]; then
61 | go list ./... | xargs -n 1 -I{} curl http://godoc.org/-/refresh -d path={}
62 | fi
63 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/static.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "net/http"
5 | "path"
6 | "strings"
7 | )
8 |
9 | // Static is a middleware handler that serves static files in the given directory/filesystem.
10 | type Static struct {
11 | // Dir is the directory to serve static files from
12 | Dir http.FileSystem
13 | // Prefix is the optional prefix used to serve the static directory content
14 | Prefix string
15 | // IndexFile defines which file to serve as index if it exists.
16 | IndexFile string
17 | }
18 |
19 | // NewStatic returns a new instance of Static
20 | func NewStatic(directory http.FileSystem) *Static {
21 | return &Static{
22 | Dir: directory,
23 | Prefix: "",
24 | IndexFile: "index.html",
25 | }
26 | }
27 |
28 | func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
29 | if r.Method != "GET" && r.Method != "HEAD" {
30 | next(rw, r)
31 | return
32 | }
33 | file := r.URL.Path
34 | // if we have a prefix, filter requests by stripping the prefix
35 | if s.Prefix != "" {
36 | if !strings.HasPrefix(file, s.Prefix) {
37 | next(rw, r)
38 | return
39 | }
40 | file = file[len(s.Prefix):]
41 | if file != "" && file[0] != '/' {
42 | next(rw, r)
43 | return
44 | }
45 | }
46 | f, err := s.Dir.Open(file)
47 | if err != nil {
48 | // discard the error?
49 | next(rw, r)
50 | return
51 | }
52 | defer f.Close()
53 |
54 | fi, err := f.Stat()
55 | if err != nil {
56 | next(rw, r)
57 | return
58 | }
59 |
60 | // try to serve index file
61 | if fi.IsDir() {
62 | // redirect if missing trailing slash
63 | if !strings.HasSuffix(r.URL.Path, "/") {
64 | http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound)
65 | return
66 | }
67 |
68 | file = path.Join(file, s.IndexFile)
69 | f, err = s.Dir.Open(file)
70 | if err != nil {
71 | next(rw, r)
72 | return
73 | }
74 | defer f.Close()
75 |
76 | fi, err = f.Stat()
77 | if err != nil || fi.IsDir() {
78 | next(rw, r)
79 | return
80 | }
81 | }
82 |
83 | http.ServeContent(rw, r, file, fi.ModTime(), f)
84 | }
85 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/transaction_test.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "encoding/base64"
5 | "net/http"
6 | "net/http/httptest"
7 | "strconv"
8 | "sync/atomic"
9 | "testing"
10 |
11 | "github.com/stretchr/testify/assert"
12 | "github.com/stretchr/testify/require"
13 | )
14 |
15 | type aBool struct {
16 | addr *int32
17 | }
18 |
19 | func (a *aBool) set(v bool) {
20 | val := int32(0)
21 | if v {
22 | val = 1
23 | }
24 | atomic.StoreInt32(a.addr, val)
25 | }
26 |
27 | func (a *aBool) val() bool {
28 | v := atomic.LoadInt32(a.addr)
29 | if v == 1 {
30 | return true
31 | }
32 | return false
33 | }
34 |
35 | func newABool() *aBool {
36 | return &aBool{
37 | addr: new(int32),
38 | }
39 | }
40 |
41 | func TestTransaction(t *testing.T) {
42 | storedVal := newABool()
43 | hitConflict := newABool()
44 |
45 | fbCounter := new(int64)
46 | atomic.StoreInt64(fbCounter, 1)
47 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
48 | counter := atomic.LoadInt64(fbCounter)
49 | val := strconv.FormatInt(counter, 10)
50 | valBytes := []byte(val)
51 | etag := base64.StdEncoding.EncodeToString(valBytes)
52 |
53 | if req.Method == http.MethodGet {
54 | w.Header().Set("Etag", etag)
55 | w.Write(valBytes)
56 | return
57 | }
58 |
59 | if req.Header.Get("if-match") != etag {
60 | hitConflict.set(true)
61 | w.Header().Set("Etag", etag)
62 | w.WriteHeader(http.StatusConflict)
63 | w.Write(valBytes)
64 | return
65 | }
66 |
67 | storedVal.set(true)
68 | w.WriteHeader(http.StatusOK)
69 | }))
70 | defer server.Close()
71 |
72 | fb := New(server.URL, nil)
73 | err := fb.Transaction(func(currentSnapshot interface{}) (interface{}, error) {
74 | counter, ok := currentSnapshot.(float64)
75 | require.True(t, ok, "counter is not of type float64")
76 | if !hitConflict.val() {
77 | // set some random value so that we can test out the conflict logic
78 | atomic.StoreInt64(fbCounter, 123)
79 | }
80 | return counter + 1, nil
81 | })
82 | assert.NoError(t, err)
83 | assert.True(t, storedVal.val())
84 | assert.True(t, hitConflict.val())
85 | }
86 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/notify_db_test.go:
--------------------------------------------------------------------------------
1 | package firetest
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 | "time"
7 |
8 | "github.com/stretchr/testify/assert"
9 | "github.com/zabawaba99/firego/sync"
10 | )
11 |
12 | func TestNotifyDBAdd(t *testing.T) {
13 | for _, test := range []struct {
14 | path string
15 | node *sync.Node
16 | }{
17 | {
18 | path: "scalars/string",
19 | node: sync.NewNode("", "foo"),
20 | },
21 | {
22 | path: "s/c/a/l/a/r/s/s/t/r/i/n/g",
23 | node: sync.NewNode("", []interface{}{"foo", "bar"}),
24 | },
25 | } {
26 | db := newNotifyDB()
27 |
28 | // listen for notifications
29 | notifications := db.watch("")
30 | exited := make(chan struct{})
31 | go func() {
32 | n, ok := <-notifications
33 | assert.True(t, ok)
34 | assert.Equal(t, "put", n.Name)
35 | assert.Equal(t, test.path, n.Data.Path, "wat?")
36 | assert.Equal(t, test.node, n.Data.Data)
37 | close(exited)
38 | }()
39 |
40 | db.add(test.path, test.node)
41 |
42 | select {
43 | case <-exited:
44 | case <-time.After(250 * time.Millisecond):
45 | }
46 | db.stopWatching(test.path, notifications)
47 | }
48 | }
49 |
50 | func TestNotifyDBDel(t *testing.T) {
51 | existingNodes := []string{
52 | "root/only/two",
53 | "root/only/three",
54 | "root/only/one/child/here",
55 | }
56 | db := newNotifyDB()
57 | for _, p := range existingNodes {
58 | db.add(p, sync.NewNode("", 1))
59 | }
60 |
61 | // listen for notifications
62 | notifications := db.watch("")
63 | exited := make(chan struct{})
64 | go func() {
65 | regex := regexp.MustCompile("(root/only/one/child|root)")
66 | n, ok := <-notifications
67 | assert.True(t, ok)
68 | assert.Equal(t, "put", n.Name)
69 | assert.Regexp(t, regex, n.Data.Path)
70 |
71 | n, ok = <-notifications
72 | assert.True(t, ok)
73 | assert.Equal(t, "put", n.Name)
74 | assert.Regexp(t, regex, n.Data.Path)
75 | close(exited)
76 | }()
77 |
78 | db.del("root/only/one/child")
79 | db.del("root")
80 |
81 | select {
82 | case <-exited:
83 | case <-time.After(250 * time.Millisecond):
84 | }
85 | db.stopWatching("", notifications)
86 | }
87 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | pipeline {
2 | environment {
3 | IMAGE_NAME = 'prydonius/seanmeme'
4 | }
5 |
6 | agent any
7 |
8 | stages {
9 | stage('Build') {
10 | steps {
11 | checkout scm
12 | sh '''
13 | docker run --rm -v "${PWD}":/go/src/seanmeme -w /go/src/seanmeme -e CGO_ENABLED=0 golang:1.8 go build
14 | docker build -t $IMAGE_NAME:$BUILD_ID .
15 | '''
16 | }
17 | }
18 | stage('Test') {
19 | steps {
20 | echo 'TODO: add tests'
21 | }
22 | }
23 | stage('Image Release') {
24 | when {
25 | expression { env.BRANCH_NAME == 'master' }
26 | }
27 |
28 | steps {
29 | withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'dockerhub',
30 | usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD']]) {
31 | sh '''
32 | docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
33 | docker push $IMAGE_NAME:$BUILD_ID
34 | '''
35 | }
36 | }
37 | }
38 | stage('Staging Deployment') {
39 | when {
40 | expression { env.BRANCH_NAME == 'master' }
41 | }
42 |
43 | environment {
44 | RELEASE_NAME = 'seanmeme-staging'
45 | SERVER_HOST = 'staging.seanmeme.k8s.prydoni.us'
46 | }
47 |
48 | steps {
49 | sh '''
50 | . ./helm/helm-init.sh
51 | helm upgrade --install --namespace staging $RELEASE_NAME ./helm/seanmeme --set image.tag=$BUILD_ID,ingress.host=$SERVER_HOST
52 | '''
53 | }
54 | }
55 | stage('Deploy to Production?') {
56 | when {
57 | expression { env.BRANCH_NAME == 'master' }
58 | }
59 |
60 | steps {
61 | // Prevent any older builds from deploying to production
62 | milestone(1)
63 | input 'Deploy to Production?'
64 | milestone(2)
65 | }
66 | }
67 | stage('Production Deployment') {
68 | when {
69 | expression { env.BRANCH_NAME == 'master' }
70 | }
71 |
72 | environment {
73 | RELEASE_NAME = 'seanmeme-production'
74 | SERVER_HOST = 'seanmeme.k8s.prydoni.us'
75 | }
76 |
77 | steps {
78 | sh '''
79 | . ./helm/helm-init.sh
80 | helm upgrade --install --namespace production $RELEASE_NAME ./helm/seanmeme --set image.tag=$BUILD_ID,ingress.host=$SERVER_HOST
81 | '''
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sean Meme
8 |
9 |
15 |
16 |
17 |
18 |
Sean Meme's photos - bit.ly/seanmeme
19 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
65 |
66 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/negroni_test.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | /* Test Helpers */
11 | func expect(t *testing.T, a interface{}, b interface{}) {
12 | if a != b {
13 | t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
14 | }
15 | }
16 |
17 | func refute(t *testing.T, a interface{}, b interface{}) {
18 | if a == b {
19 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
20 | }
21 | }
22 |
23 | func TestNegroniRun(t *testing.T) {
24 | // just test that Run doesn't bomb
25 | go New().Run(":3000")
26 | }
27 |
28 | func TestNegroniServeHTTP(t *testing.T) {
29 | result := ""
30 | response := httptest.NewRecorder()
31 |
32 | n := New()
33 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
34 | result += "foo"
35 | next(rw, r)
36 | result += "ban"
37 | }))
38 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
39 | result += "bar"
40 | next(rw, r)
41 | result += "baz"
42 | }))
43 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
44 | result += "bat"
45 | rw.WriteHeader(http.StatusBadRequest)
46 | }))
47 |
48 | n.ServeHTTP(response, (*http.Request)(nil))
49 |
50 | expect(t, result, "foobarbatbazban")
51 | expect(t, response.Code, http.StatusBadRequest)
52 | }
53 |
54 | // Ensures that a Negroni middleware chain
55 | // can correctly return all of its handlers.
56 | func TestHandlers(t *testing.T) {
57 | response := httptest.NewRecorder()
58 | n := New()
59 | handlers := n.Handlers()
60 | expect(t, 0, len(handlers))
61 |
62 | n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
63 | rw.WriteHeader(http.StatusOK)
64 | }))
65 |
66 | // Expects the length of handlers to be exactly 1
67 | // after adding exactly one handler to the middleware chain
68 | handlers = n.Handlers()
69 | expect(t, 1, len(handlers))
70 |
71 | // Ensures that the first handler that is in sequence behaves
72 | // exactly the same as the one that was registered earlier
73 | handlers[0].ServeHTTP(response, (*http.Request)(nil), nil)
74 | expect(t, response.Code, http.StatusOK)
75 | }
76 |
77 | func TestNegroni_Use_Nil(t *testing.T) {
78 | defer func() {
79 | err := recover()
80 | if err == nil {
81 | t.Errorf("Expected negroni.Use(nil) to panic, but it did not")
82 | }
83 | }()
84 |
85 | n := New()
86 | n.Use(nil)
87 | }
88 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/node_bench_test.go:
--------------------------------------------------------------------------------
1 | package sync
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func BenchmarkNewNode(b *testing.B) {
8 | nodesToCreate := []interface{}{
9 | // primitives
10 | "somestirng",
11 | 1,
12 | int8(2),
13 | int16(12),
14 | int32(222),
15 | int64(3245),
16 | float32(123123123123234),
17 | float64(7654323456543245654),
18 | true,
19 |
20 | // slice
21 | []interface{}{
22 | "foobar",
23 | 1234,
24 | true,
25 | },
26 |
27 | // simple map
28 | map[string]interface{}{
29 | "hello": "world",
30 | "foo": false,
31 | "number": 222,
32 | },
33 |
34 | // something that is not interface type
35 | map[string]bool{
36 | "1": true,
37 | "2": true,
38 | "3": true,
39 | },
40 |
41 | // nest map
42 | map[string]interface{}{
43 | "aaa": []interface{}{
44 | "ahhhh",
45 | map[string]interface{}{
46 | "wat?": "another map?!",
47 | "yup": true,
48 | },
49 | },
50 | "doras-backpack": map[string]interface{}{
51 | "si se puede": "yes you can!",
52 | "map map map map": 333,
53 | },
54 | "something-simple": 1,
55 | "inception": map[string]interface{}{
56 | "aaa": []interface{}{
57 | "ahhhh",
58 | map[string]interface{}{
59 | "wat?": "another map?!",
60 | "yup": true,
61 | },
62 | },
63 | "doras-backpack": map[string]interface{}{
64 | "si se puede": "yes you can!",
65 | "map map map map": 333,
66 | },
67 | "something-simple": 1,
68 | "inception": map[string]interface{}{
69 | "aaa": []interface{}{
70 | "ahhhh",
71 | map[string]interface{}{
72 | "wat?": "another map?!",
73 | "yup": true,
74 | },
75 | },
76 | "doras-backpack": map[string]interface{}{
77 | "si se puede": "yes you can!",
78 | "map map map map": 333,
79 | },
80 | "something-simple": 1,
81 | "inception": map[string]interface{}{
82 | "aaa": []interface{}{
83 | "ahhhh",
84 | map[string]interface{}{
85 | "wat?": "another map?!",
86 | "yup": true,
87 | },
88 | },
89 | "doras-backpack": map[string]interface{}{
90 | "si se puede": "yes you can!",
91 | "map map map map": 333,
92 | },
93 | "something-simple": 1,
94 | },
95 | },
96 | },
97 | },
98 | }
99 |
100 | b.ResetTimer()
101 | for i := 0; i < b.N; i++ {
102 | for _, node := range nodesToCreate {
103 | _ = NewNode("", node)
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/database_test.go:
--------------------------------------------------------------------------------
1 | package sync
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestAdd(t *testing.T) {
12 | for _, test := range []struct {
13 | path string
14 | node *Node
15 | }{
16 | {
17 | path: "scalars/string",
18 | node: NewNode("", "foo"),
19 | },
20 | {
21 | path: "s/c/a/l/a/r/s/s/t/r/i/n/g",
22 | node: NewNode("", []interface{}{"foo", "bar"}),
23 | },
24 | } {
25 | db := NewDB()
26 |
27 | db.Add(test.path, test.node)
28 |
29 | rabbitHole := strings.Split(test.path, "/")
30 | previous := db.root
31 | for i := 0; i < len(rabbitHole); i++ {
32 | var ok bool
33 | previous, ok = previous.Children[rabbitHole[i]]
34 | assert.True(t, ok, test.path)
35 | }
36 |
37 | assert.NoError(t, equalNodes(test.node, previous), test.path)
38 | }
39 | }
40 |
41 | func TestUpdate(t *testing.T) {
42 | db := NewDB()
43 |
44 | db.Add("", NewNode("", map[string]interface{}{
45 | "hello": map[string]interface{}{
46 | "world": 2,
47 | "world2": 1,
48 | },
49 | }))
50 |
51 | db.Update("hello/world", NewNode("", "hi"))
52 | db.Update("hello/world3", NewNode("", "lol"))
53 |
54 | assert.Equal(t, "hi", db.Get("hello/world").Value)
55 | assert.Equal(t, 1, db.Get("hello/world2").Value)
56 | assert.Equal(t, "lol", db.Get("hello/world3").Value)
57 | }
58 |
59 | func TestGet(t *testing.T) {
60 | for _, test := range []struct {
61 | path string
62 | node *Node
63 | }{
64 | {
65 | path: "scalars/string",
66 | node: NewNode("", "foo"),
67 | },
68 | {
69 | path: "s/c/a/l/a/r/s/s/t/r/i/n/g",
70 | node: NewNode("", []interface{}{"foo", "bar"}),
71 | },
72 | } {
73 | db := NewDB()
74 | db.Add(test.path, test.node)
75 |
76 | assert.NoError(t, equalNodes(test.node, db.Get(test.path)), test.path)
77 | }
78 | }
79 |
80 | func TestDel(t *testing.T) {
81 | existingNodes := []string{
82 | "root/only/two",
83 | "root/only/three",
84 | "root/only/one/child/here",
85 | }
86 | db := NewDB()
87 | for _, p := range existingNodes {
88 | db.Add(p, NewNode("", 1))
89 | }
90 |
91 | db.Del("root/only/one/child")
92 | assert.Nil(t, db.Get("root/only/one/child/here"))
93 | assert.Nil(t, db.Get("root/only/one/child"))
94 | assert.Nil(t, db.Get("root/only/one"))
95 |
96 | n := db.Get("root/only")
97 | require.NotNil(t, n)
98 |
99 | assert.Len(t, n.Children, 2)
100 | _, ok := n.Children["one"]
101 | assert.False(t, ok)
102 |
103 | db.Del("root")
104 | n = db.Get("")
105 | require.NotNil(t, n)
106 | assert.Len(t, n.Children, 0)
107 | }
108 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/transaction.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "net/http"
8 | )
9 |
10 | // TransactionFn is used to run a transaction on a Firebase reference.
11 | // See Firebase.Transaction for more information.
12 | type TransactionFn func(currentSnapshot interface{}) (result interface{}, err error)
13 |
14 | func getTransactionParams(headers http.Header, body []byte) (etag string, snapshot interface{}, err error) {
15 | etag = headers.Get("ETag")
16 | if len(etag) == 0 {
17 | return etag, snapshot, errors.New("no etag returned by Firebase")
18 | }
19 |
20 | if err := json.Unmarshal(body, &snapshot); err != nil {
21 | return etag, snapshot, fmt.Errorf("failed to unmarshal Firebase response. %s", err)
22 | }
23 |
24 | return etag, snapshot, nil
25 | }
26 |
27 | // Transaction runs a transaction on the data at this location. The TransactionFn parameter
28 | // will be called, possibly multiple times, with the current data at this location.
29 | // It is responsible for inspecting that data and specifying either the desired new data
30 | // at the location or that the transaction should be aborted.
31 | //
32 | // Since the provided function may be called repeatedly for the same transaction, be extremely careful of
33 | // any side effects that may be triggered by this method.
34 | //
35 | // Best practices for this method are to rely only on the data that is passed in.
36 | func (fb *Firebase) Transaction(fn TransactionFn) error {
37 | // fetch etag and current value
38 | headers, body, err := fb.doRequest("GET", nil, withHeader("X-Firebase-ETag", "true"))
39 | if err != nil {
40 | return err
41 | }
42 |
43 | etag, snapshot, err := getTransactionParams(headers, body)
44 | if err != nil {
45 | return err
46 | }
47 |
48 | // set the error value to something non-nil so that
49 | // we step into the loop
50 | tErr := errors.New("")
51 | for i := 0; i < 25 && tErr != nil; i++ {
52 | // run transaction
53 | result, err := fn(snapshot)
54 | if err != nil {
55 | return nil
56 | }
57 |
58 | newBody, err := json.Marshal(result)
59 | if err != nil {
60 | return fmt.Errorf("failed to marshal transaction result. %s", err)
61 | }
62 |
63 | // attempt to update it
64 | headers, body, tErr = fb.doRequest("PUT", newBody, withHeader("if-match", etag))
65 | if tErr == nil {
66 | // we're good, break the loop
67 | break
68 | }
69 |
70 | // we failed to update, so grab the new snapshot/etag
71 | e, s, tErr := getTransactionParams(headers, body)
72 | if tErr != nil {
73 | return tErr
74 | }
75 | etag, snapshot = e, s
76 | }
77 |
78 | if tErr != nil {
79 | return fmt.Errorf("failed to run transaction. %s", tErr)
80 | }
81 | return nil
82 | }
83 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/direct.go:
--------------------------------------------------------------------------------
1 | package firetest
2 |
3 | import (
4 | "encoding/base64"
5 | "fmt"
6 | "sync/atomic"
7 | "time"
8 |
9 | "github.com/zabawaba99/firego/sync"
10 | )
11 |
12 | // RequireAuth determines whether or not a Firetest server
13 | // will require that each request be authorized
14 | func (ft *Firetest) RequireAuth(v bool) {
15 | var val int32
16 | if v {
17 | val = 1
18 | }
19 | atomic.StoreInt32(ft.requireAuth, val)
20 | }
21 |
22 | // Create generates a new child under the given location
23 | // using a unique name and returns the name
24 | //
25 | // Reference https://www.firebase.com/docs/rest/api/#section-post
26 | func (ft *Firetest) Create(path string, v interface{}) string {
27 | src := []byte(fmt.Sprint(time.Now().UnixNano()))
28 | name := "~" + base64.StdEncoding.EncodeToString(src)
29 |
30 | path = fmt.Sprintf("%s/%s", sanitizePath(path), name)
31 | // sanitize one more time in case initial path was empty
32 | path = sanitizePath(path)
33 | ft.db.add(path, sync.NewNode("", v))
34 | return name
35 | }
36 |
37 | // Delete removes the data at the requested location.
38 | // Any data at child locations will also be deleted.
39 | //
40 | // Reference https://www.firebase.com/docs/rest/api/#section-delete
41 | func (ft *Firetest) Delete(path string) {
42 | ft.db.del(sanitizePath(path))
43 | }
44 |
45 | // Update writes the enumerated children to this the given location.
46 | // This will overwrite only children enumerated in the "value" parameter
47 | // and will leave others untouched. Note that the update function is equivalent
48 | // to calling Set() on the named children; it does not recursively update children
49 | // if they are objects. Passing null as a value for a child is equivalent to
50 | // calling remove() on that child.
51 | //
52 | // Reference https://www.firebase.com/docs/rest/api/#section-patch
53 | func (ft *Firetest) Update(path string, v interface{}) {
54 | path = sanitizePath(path)
55 | if v == nil {
56 | ft.db.del(path)
57 | } else {
58 | ft.db.update(path, sync.NewNode("", v))
59 | }
60 | }
61 |
62 | // Set writes data to at the given location.
63 | // This will overwrite any data at this location and all child locations.
64 | //
65 | // Reference https://www.firebase.com/docs/rest/api/#section-put
66 | func (ft *Firetest) Set(path string, v interface{}) {
67 | ft.db.add(sanitizePath(path), sync.NewNode("", v))
68 | }
69 |
70 | // Get retrieves the data and all its children at the
71 | // requested location
72 | //
73 | // Reference https://www.firebase.com/docs/rest/api/#section-get
74 | func (ft *Firetest) Get(path string) (v interface{}) {
75 | n := ft.db.intDB.Get(sanitizePath(path))
76 | if n != nil {
77 | v = n.Objectify()
78 | }
79 | return v
80 | }
81 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/direct_test.go:
--------------------------------------------------------------------------------
1 | package firetest
2 |
3 | import (
4 | "strings"
5 | "sync/atomic"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/assert"
9 | "github.com/zabawaba99/firego/sync"
10 | )
11 |
12 | func TestRequireAuth(t *testing.T) {
13 | for _, require := range []bool{true, false} {
14 | ft := New()
15 | ft.RequireAuth(require)
16 | var expected int32
17 | if require {
18 | expected = 1
19 | }
20 | assert.Equal(t, expected, atomic.LoadInt32(ft.requireAuth))
21 | }
22 | }
23 |
24 | func TestCreate(t *testing.T) {
25 | var (
26 | ft = New()
27 | v = true
28 | )
29 |
30 | for _, p := range []string{"path/hi", ""} {
31 | name := ft.Create(p, v)
32 | assert.True(t, strings.HasPrefix(name, "~"), "name is missing `~` prefix")
33 |
34 | n := ft.db.get(sanitizePath(p + "/" + name))
35 | assert.Equal(t, v, n.Value)
36 | }
37 | }
38 |
39 | func TestDelete(t *testing.T) {
40 | var (
41 | ft = New()
42 | path = "foo/bar"
43 | v = true
44 | )
45 |
46 | // delete path directly
47 | ft.db.add(path, sync.NewNode("", v))
48 | ft.Delete(path)
49 | assert.Nil(t, ft.db.get(path))
50 |
51 | // delete parent
52 | ft.db.add(path, sync.NewNode("", v))
53 | ft.Delete("foo")
54 | assert.Nil(t, ft.db.get(path))
55 | }
56 |
57 | func TestUpdate(t *testing.T) {
58 | var (
59 | ft = New()
60 | path = "foo/bar"
61 | v = map[string]interface{}{
62 | "1": "one",
63 | "2": "two",
64 | "3": "three",
65 | }
66 | )
67 | ft.db.add(path, sync.NewNode("", v))
68 |
69 | ft.Update(path, map[string]interface{}{
70 | "1": "three",
71 | "3": "one",
72 | })
73 |
74 | one := ft.db.get(path + "/1")
75 | three := ft.db.get(path + "/3")
76 | assert.Equal(t, "three", one.Value)
77 | assert.Equal(t, "one", three.Value)
78 | }
79 |
80 | func TestUpdateNil(t *testing.T) {
81 | var (
82 | ft = New()
83 | path = "foo/bar"
84 | v = map[string]string{
85 | "1": "one",
86 | "2": "two",
87 | "3": "three",
88 | }
89 | )
90 | ft.db.add(path, sync.NewNode("", v))
91 |
92 | ft.Update(path, nil)
93 | assert.Nil(t, ft.db.get(path))
94 | assert.Nil(t, ft.db.get(path+"/1"))
95 | assert.Nil(t, ft.db.get(path+"/2"))
96 | assert.Nil(t, ft.db.get(path+"/3"))
97 | }
98 |
99 | func TestSet(t *testing.T) {
100 | var (
101 | ft = New()
102 | path = "foo/bar"
103 | v = true
104 | )
105 | ft.Set(path, v)
106 |
107 | n := ft.db.get(path)
108 | assert.Equal(t, v, n.Value)
109 | }
110 |
111 | func TestGet(t *testing.T) {
112 | var (
113 | ft = New()
114 | path = "foo/bar"
115 | v = true
116 | )
117 | ft.db.add(path, sync.NewNode("", v))
118 |
119 | val := ft.Get(path)
120 | assert.Equal(t, v, val)
121 | }
122 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/context/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | /*
6 | Package context stores values shared during a request lifetime.
7 |
8 | For example, a router can set variables extracted from the URL and later
9 | application handlers can access those values, or it can be used to store
10 | sessions values to be saved at the end of a request. There are several
11 | others common uses.
12 |
13 | The idea was posted by Brad Fitzpatrick to the go-nuts mailing list:
14 |
15 | http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53
16 |
17 | Here's the basic usage: first define the keys that you will need. The key
18 | type is interface{} so a key can be of any type that supports equality.
19 | Here we define a key using a custom int type to avoid name collisions:
20 |
21 | package foo
22 |
23 | import (
24 | "github.com/gorilla/context"
25 | )
26 |
27 | type key int
28 |
29 | const MyKey key = 0
30 |
31 | Then set a variable. Variables are bound to an http.Request object, so you
32 | need a request instance to set a value:
33 |
34 | context.Set(r, MyKey, "bar")
35 |
36 | The application can later access the variable using the same key you provided:
37 |
38 | func MyHandler(w http.ResponseWriter, r *http.Request) {
39 | // val is "bar".
40 | val := context.Get(r, foo.MyKey)
41 |
42 | // returns ("bar", true)
43 | val, ok := context.GetOk(r, foo.MyKey)
44 | // ...
45 | }
46 |
47 | And that's all about the basic usage. We discuss some other ideas below.
48 |
49 | Any type can be stored in the context. To enforce a given type, make the key
50 | private and wrap Get() and Set() to accept and return values of a specific
51 | type:
52 |
53 | type key int
54 |
55 | const mykey key = 0
56 |
57 | // GetMyKey returns a value for this package from the request values.
58 | func GetMyKey(r *http.Request) SomeType {
59 | if rv := context.Get(r, mykey); rv != nil {
60 | return rv.(SomeType)
61 | }
62 | return nil
63 | }
64 |
65 | // SetMyKey sets a value for this package in the request values.
66 | func SetMyKey(r *http.Request, val SomeType) {
67 | context.Set(r, mykey, val)
68 | }
69 |
70 | Variables must be cleared at the end of a request, to remove all values
71 | that were stored. This can be done in an http.Handler, after a request was
72 | served. Just call Clear() passing the request:
73 |
74 | context.Clear(r)
75 |
76 | ...or use ClearHandler(), which conveniently wraps an http.Handler to clear
77 | variables at the end of a request lifetime.
78 |
79 | The Routers from the packages gorilla/mux and gorilla/pat call Clear()
80 | so if you are using either of them you don't need to clear the context manually.
81 | */
82 | package context
83 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/notify_db.go:
--------------------------------------------------------------------------------
1 | package firetest
2 |
3 | import (
4 | "encoding/json"
5 | "strings"
6 | _sync "sync"
7 | "time"
8 |
9 | "github.com/zabawaba99/firego/sync"
10 | )
11 |
12 | type event struct {
13 | Name string
14 | Data eventData
15 | }
16 |
17 | type eventData struct {
18 | Path string `json:"path"`
19 | Data *sync.Node `json:"data"`
20 | }
21 |
22 | func (ed eventData) MarshalJSON() ([]byte, error) {
23 | type eventData2 eventData
24 | ed2 := eventData2(ed)
25 | ed2.Path = "/" + ed2.Path
26 | return json.Marshal(ed2)
27 | }
28 |
29 | func newEvent(name, path string, n *sync.Node) event {
30 | return event{
31 | Name: "put",
32 | Data: eventData{
33 | Path: path,
34 | Data: n,
35 | },
36 | }
37 | }
38 |
39 | type notifyDB struct {
40 | intDB *sync.Database
41 |
42 | watchersMtx _sync.RWMutex
43 | watchers map[string][]chan event
44 | }
45 |
46 | func newNotifyDB() *notifyDB {
47 | return ¬ifyDB{
48 | intDB: sync.NewDB(),
49 | watchers: map[string][]chan event{},
50 | }
51 | }
52 |
53 | func (db *notifyDB) add(path string, n *sync.Node) {
54 | db.intDB.Add(path, n)
55 | go db.notify(newEvent("put", path, n))
56 | }
57 |
58 | func (db *notifyDB) update(path string, n *sync.Node) {
59 | db.intDB.Update(path, n)
60 | go db.notify(newEvent("patch", path, n))
61 | }
62 |
63 | func (db *notifyDB) del(path string) {
64 | db.intDB.Del(path)
65 | go db.notify(newEvent("put", path, nil))
66 | }
67 |
68 | func (db *notifyDB) get(path string) *sync.Node {
69 | return db.intDB.Get(path)
70 | }
71 |
72 | func (db *notifyDB) notify(e event) {
73 | db.watchersMtx.RLock()
74 | for path, listeners := range db.watchers {
75 | if !strings.HasPrefix(e.Data.Path, path) {
76 | continue
77 | }
78 |
79 | // Make sure to not return full path when notifying
80 | // only return the path relative to the watcher
81 | e.Data.Path = strings.TrimPrefix(e.Data.Path, path)
82 | e.Data.Path = sanitizePath(e.Data.Path)
83 |
84 | for _, c := range listeners {
85 | select {
86 | case c <- e:
87 | case <-time.After(250 * time.Millisecond):
88 | continue
89 | }
90 | }
91 | }
92 | db.watchersMtx.RUnlock()
93 | }
94 |
95 | func (db *notifyDB) stopWatching(path string, c chan event) {
96 | db.watchersMtx.Lock()
97 | index := -1
98 | for i, ch := range db.watchers[path] {
99 | if ch == c {
100 | index = i
101 | break
102 | }
103 | }
104 |
105 | if index > -1 {
106 | a := db.watchers[path]
107 | db.watchers[path] = append(a[:index], a[index+1:]...)
108 | close(c)
109 | }
110 | db.watchersMtx.Unlock()
111 | }
112 |
113 | func (db *notifyDB) watch(path string) chan event {
114 | c := make(chan event)
115 |
116 | db.watchersMtx.Lock()
117 | db.watchers[path] = append(db.watchers[path], c)
118 | db.watchersMtx.Unlock()
119 |
120 | return c
121 | }
122 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/static_test.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "bytes"
5 | "net/http"
6 | "net/http/httptest"
7 | "testing"
8 | )
9 |
10 | func TestStatic(t *testing.T) {
11 | response := httptest.NewRecorder()
12 | response.Body = new(bytes.Buffer)
13 |
14 | n := New()
15 | n.Use(NewStatic(http.Dir(".")))
16 |
17 | req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil)
18 | if err != nil {
19 | t.Error(err)
20 | }
21 | n.ServeHTTP(response, req)
22 | expect(t, response.Code, http.StatusOK)
23 | expect(t, response.Header().Get("Expires"), "")
24 | if response.Body.Len() == 0 {
25 | t.Errorf("Got empty body for GET request")
26 | }
27 | }
28 |
29 | func TestStaticHead(t *testing.T) {
30 | response := httptest.NewRecorder()
31 | response.Body = new(bytes.Buffer)
32 |
33 | n := New()
34 | n.Use(NewStatic(http.Dir(".")))
35 | n.UseHandler(http.NotFoundHandler())
36 |
37 | req, err := http.NewRequest("HEAD", "http://localhost:3000/negroni.go", nil)
38 | if err != nil {
39 | t.Error(err)
40 | }
41 |
42 | n.ServeHTTP(response, req)
43 | expect(t, response.Code, http.StatusOK)
44 | if response.Body.Len() != 0 {
45 | t.Errorf("Got non-empty body for HEAD request")
46 | }
47 | }
48 |
49 | func TestStaticAsPost(t *testing.T) {
50 | response := httptest.NewRecorder()
51 |
52 | n := New()
53 | n.Use(NewStatic(http.Dir(".")))
54 | n.UseHandler(http.NotFoundHandler())
55 |
56 | req, err := http.NewRequest("POST", "http://localhost:3000/negroni.go", nil)
57 | if err != nil {
58 | t.Error(err)
59 | }
60 |
61 | n.ServeHTTP(response, req)
62 | expect(t, response.Code, http.StatusNotFound)
63 | }
64 |
65 | func TestStaticBadDir(t *testing.T) {
66 | response := httptest.NewRecorder()
67 |
68 | n := Classic()
69 | n.UseHandler(http.NotFoundHandler())
70 |
71 | req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil)
72 | if err != nil {
73 | t.Error(err)
74 | }
75 |
76 | n.ServeHTTP(response, req)
77 | refute(t, response.Code, http.StatusOK)
78 | }
79 |
80 | func TestStaticOptionsServeIndex(t *testing.T) {
81 | response := httptest.NewRecorder()
82 |
83 | n := New()
84 | s := NewStatic(http.Dir("."))
85 | s.IndexFile = "negroni.go"
86 | n.Use(s)
87 |
88 | req, err := http.NewRequest("GET", "http://localhost:3000/", nil)
89 | if err != nil {
90 | t.Error(err)
91 | }
92 |
93 | n.ServeHTTP(response, req)
94 | expect(t, response.Code, http.StatusOK)
95 | }
96 |
97 | func TestStaticOptionsPrefix(t *testing.T) {
98 | response := httptest.NewRecorder()
99 |
100 | n := New()
101 | s := NewStatic(http.Dir("."))
102 | s.Prefix = "/public"
103 | n.Use(s)
104 |
105 | // Check file content behaviour
106 | req, err := http.NewRequest("GET", "http://localhost:3000/public/negroni.go", nil)
107 | if err != nil {
108 | t.Error(err)
109 | }
110 |
111 | n.ServeHTTP(response, req)
112 | expect(t, response.Code, http.StatusOK)
113 | }
114 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/response_writer.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "net"
7 | "net/http"
8 | )
9 |
10 | // ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
11 | // the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
12 | // if the functionality calls for it.
13 | type ResponseWriter interface {
14 | http.ResponseWriter
15 | http.Flusher
16 | // Status returns the status code of the response or 0 if the response has not been written.
17 | Status() int
18 | // Written returns whether or not the ResponseWriter has been written.
19 | Written() bool
20 | // Size returns the size of the response body.
21 | Size() int
22 | // Before allows for a function to be called before the ResponseWriter has been written to. This is
23 | // useful for setting headers or any other operations that must happen before a response has been written.
24 | Before(func(ResponseWriter))
25 | }
26 |
27 | type beforeFunc func(ResponseWriter)
28 |
29 | // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
30 | func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
31 | return &responseWriter{
32 | ResponseWriter: rw,
33 | status: http.StatusOK,
34 | size: 0,
35 | beforeFuncs: nil}
36 | }
37 |
38 | type responseWriter struct {
39 | http.ResponseWriter
40 | status int
41 | size int
42 | beforeFuncs []beforeFunc
43 | }
44 |
45 | func (rw *responseWriter) WriteHeader(s int) {
46 | rw.status = s
47 | rw.callBefore()
48 | rw.ResponseWriter.WriteHeader(s)
49 | }
50 |
51 | func (rw *responseWriter) Write(b []byte) (int, error) {
52 | if !rw.Written() {
53 | // The status will be StatusOK if WriteHeader has not been called yet
54 | rw.WriteHeader(http.StatusOK)
55 | }
56 | size, err := rw.ResponseWriter.Write(b)
57 | rw.size += size
58 | return size, err
59 | }
60 |
61 | func (rw *responseWriter) Status() int {
62 | return rw.status
63 | }
64 |
65 | func (rw *responseWriter) Size() int {
66 | return rw.size
67 | }
68 |
69 | func (rw *responseWriter) Written() bool {
70 | return rw.status != 0
71 | }
72 |
73 | func (rw *responseWriter) Before(before func(ResponseWriter)) {
74 | rw.beforeFuncs = append(rw.beforeFuncs, before)
75 | }
76 |
77 | func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
78 | hijacker, ok := rw.ResponseWriter.(http.Hijacker)
79 | if !ok {
80 | return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
81 | }
82 | return hijacker.Hijack()
83 | }
84 |
85 | func (rw *responseWriter) CloseNotify() <-chan bool {
86 | return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
87 | }
88 |
89 | func (rw *responseWriter) callBefore() {
90 | for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
91 | rw.beforeFuncs[i](rw)
92 | }
93 | }
94 |
95 | func (rw *responseWriter) Flush() {
96 | flusher, ok := rw.ResponseWriter.(http.Flusher)
97 | if ok {
98 | flusher.Flush()
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/database.go:
--------------------------------------------------------------------------------
1 | package sync
2 |
3 | import (
4 | "strings"
5 | "sync"
6 | )
7 |
8 | // Database is a local representation of a Firebase database.
9 | type Database struct {
10 | root *Node
11 |
12 | mtx sync.RWMutex
13 | }
14 |
15 | // NewDB creates a new instance of a Database.
16 | func NewDB() *Database {
17 | return &Database{
18 | root: &Node{
19 | Children: map[string]*Node{},
20 | },
21 | }
22 | }
23 |
24 | // Add puts a Node into the database.
25 | func (d *Database) Add(path string, n *Node) {
26 | d.mtx.Lock()
27 | defer d.mtx.Unlock()
28 |
29 | if path == "" {
30 | d.root = n
31 | return
32 | }
33 |
34 | rabbitHole := strings.Split(path, "/")
35 | current := d.root
36 | for i := 0; i < len(rabbitHole)-1; i++ {
37 | step := rabbitHole[i]
38 | next, ok := current.Children[step]
39 | if !ok {
40 | next = &Node{
41 | Parent: current,
42 | Key: step,
43 | Children: map[string]*Node{},
44 | }
45 | current.Children[step] = next
46 | }
47 | next.Value = nil // no long has a value since it now has a child
48 | current, next = next, nil
49 | }
50 |
51 | lastPath := rabbitHole[len(rabbitHole)-1]
52 | current.Children[lastPath] = n
53 | n.Parent = current
54 | }
55 |
56 | // Update merges the current node with the given node.
57 | func (d *Database) Update(path string, n *Node) {
58 | d.mtx.Lock()
59 | defer d.mtx.Unlock()
60 |
61 | current := d.root
62 | rabbitHole := strings.Split(path, "/")
63 |
64 | for i := 0; i < len(rabbitHole); i++ {
65 | step := rabbitHole[i]
66 | if step == "" {
67 | // prevent against empty strings due to strings.Split
68 | continue
69 | }
70 | next, ok := current.Children[step]
71 | if !ok {
72 | next = &Node{
73 | Parent: current,
74 | Key: step,
75 | Children: map[string]*Node{},
76 | }
77 | current.Children[step] = next
78 | }
79 | next.Value = nil // no long has a value since it now has a child
80 | current, next = next, nil
81 | }
82 |
83 | current.merge(n)
84 |
85 | }
86 |
87 | // Del removes the node at the given path.
88 | func (d *Database) Del(path string) {
89 | d.mtx.Lock()
90 | defer d.mtx.Unlock()
91 |
92 | if path == "" {
93 | d.root = &Node{
94 | Children: map[string]*Node{},
95 | }
96 | return
97 | }
98 |
99 | rabbitHole := strings.Split(path, "/")
100 | current := d.root
101 |
102 | // traverse to target node's parent
103 | var delIdx int
104 | for ; delIdx < len(rabbitHole)-1; delIdx++ {
105 | next, ok := current.Children[rabbitHole[delIdx]]
106 | if !ok {
107 | // item does not exist, no need to do anything
108 | return
109 | }
110 |
111 | current = next
112 | }
113 |
114 | endNode := current
115 | leafPath := rabbitHole[len(rabbitHole)-1]
116 | delete(endNode.Children, leafPath)
117 |
118 | for tmp := endNode.prune(); tmp != nil; tmp = tmp.prune() {
119 | delIdx--
120 | endNode = tmp
121 | }
122 |
123 | if endNode != nil {
124 | delete(endNode.Children, rabbitHole[delIdx])
125 | }
126 | }
127 |
128 | // Get fetches a node at a given path.
129 | func (d *Database) Get(path string) *Node {
130 | d.mtx.RLock()
131 | defer d.mtx.RUnlock()
132 |
133 | current := d.root
134 | if path == "" {
135 | return current
136 | }
137 |
138 | rabbitHole := strings.Split(path, "/")
139 | for i := 0; i < len(rabbitHole); i++ {
140 | var ok bool
141 | current, ok = current.Children[rabbitHole[i]]
142 | if !ok {
143 | return nil
144 | }
145 | }
146 | return current
147 | }
148 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/context/context_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package context
6 |
7 | import (
8 | "net/http"
9 | "testing"
10 | )
11 |
12 | type keyType int
13 |
14 | const (
15 | key1 keyType = iota
16 | key2
17 | )
18 |
19 | func TestContext(t *testing.T) {
20 | assertEqual := func(val interface{}, exp interface{}) {
21 | if val != exp {
22 | t.Errorf("Expected %v, got %v.", exp, val)
23 | }
24 | }
25 |
26 | r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
27 | emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
28 |
29 | // Get()
30 | assertEqual(Get(r, key1), nil)
31 |
32 | // Set()
33 | Set(r, key1, "1")
34 | assertEqual(Get(r, key1), "1")
35 | assertEqual(len(data[r]), 1)
36 |
37 | Set(r, key2, "2")
38 | assertEqual(Get(r, key2), "2")
39 | assertEqual(len(data[r]), 2)
40 |
41 | //GetOk
42 | value, ok := GetOk(r, key1)
43 | assertEqual(value, "1")
44 | assertEqual(ok, true)
45 |
46 | value, ok = GetOk(r, "not exists")
47 | assertEqual(value, nil)
48 | assertEqual(ok, false)
49 |
50 | Set(r, "nil value", nil)
51 | value, ok = GetOk(r, "nil value")
52 | assertEqual(value, nil)
53 | assertEqual(ok, true)
54 |
55 | // GetAll()
56 | values := GetAll(r)
57 | assertEqual(len(values), 3)
58 |
59 | // GetAll() for empty request
60 | values = GetAll(emptyR)
61 | if values != nil {
62 | t.Error("GetAll didn't return nil value for invalid request")
63 | }
64 |
65 | // GetAllOk()
66 | values, ok = GetAllOk(r)
67 | assertEqual(len(values), 3)
68 | assertEqual(ok, true)
69 |
70 | // GetAllOk() for empty request
71 | values, ok = GetAllOk(emptyR)
72 | assertEqual(value, nil)
73 | assertEqual(ok, false)
74 |
75 | // Delete()
76 | Delete(r, key1)
77 | assertEqual(Get(r, key1), nil)
78 | assertEqual(len(data[r]), 2)
79 |
80 | Delete(r, key2)
81 | assertEqual(Get(r, key2), nil)
82 | assertEqual(len(data[r]), 1)
83 |
84 | // Clear()
85 | Clear(r)
86 | assertEqual(len(data), 0)
87 | }
88 |
89 | func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) {
90 | <-wait
91 | for i := 0; i < iterations; i++ {
92 | Get(r, key)
93 | }
94 | done <- struct{}{}
95 |
96 | }
97 |
98 | func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) {
99 | <-wait
100 | for i := 0; i < iterations; i++ {
101 | Set(r, key, value)
102 | }
103 | done <- struct{}{}
104 |
105 | }
106 |
107 | func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) {
108 |
109 | b.StopTimer()
110 | r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
111 | done := make(chan struct{})
112 | b.StartTimer()
113 |
114 | for i := 0; i < b.N; i++ {
115 | wait := make(chan struct{})
116 |
117 | for i := 0; i < numReaders; i++ {
118 | go parallelReader(r, "test", iterations, wait, done)
119 | }
120 |
121 | for i := 0; i < numWriters; i++ {
122 | go parallelWriter(r, "test", "123", iterations, wait, done)
123 | }
124 |
125 | close(wait)
126 |
127 | for i := 0; i < numReaders+numWriters; i++ {
128 | <-done
129 | }
130 |
131 | }
132 |
133 | }
134 |
135 | func BenchmarkMutexSameReadWrite1(b *testing.B) {
136 | benchmarkMutex(b, 1, 1, 32)
137 | }
138 | func BenchmarkMutexSameReadWrite2(b *testing.B) {
139 | benchmarkMutex(b, 2, 2, 32)
140 | }
141 | func BenchmarkMutexSameReadWrite4(b *testing.B) {
142 | benchmarkMutex(b, 4, 4, 32)
143 | }
144 | func BenchmarkMutex1(b *testing.B) {
145 | benchmarkMutex(b, 2, 8, 32)
146 | }
147 | func BenchmarkMutex2(b *testing.B) {
148 | benchmarkMutex(b, 16, 4, 64)
149 | }
150 | func BenchmarkMutex3(b *testing.B) {
151 | benchmarkMutex(b, 1, 2, 128)
152 | }
153 | func BenchmarkMutex4(b *testing.B) {
154 | benchmarkMutex(b, 128, 32, 256)
155 | }
156 | func BenchmarkMutex5(b *testing.B) {
157 | benchmarkMutex(b, 1024, 2048, 64)
158 | }
159 | func BenchmarkMutex6(b *testing.B) {
160 | benchmarkMutex(b, 2048, 1024, 512)
161 | }
162 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/response_writer_test.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "bufio"
5 | "net"
6 | "net/http"
7 | "net/http/httptest"
8 | "testing"
9 | "time"
10 | )
11 |
12 | type closeNotifyingRecorder struct {
13 | *httptest.ResponseRecorder
14 | closed chan bool
15 | }
16 |
17 | func newCloseNotifyingRecorder() *closeNotifyingRecorder {
18 | return &closeNotifyingRecorder{
19 | httptest.NewRecorder(),
20 | make(chan bool, 1),
21 | }
22 | }
23 |
24 | func (c *closeNotifyingRecorder) close() {
25 | c.closed <- true
26 | }
27 |
28 | func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
29 | return c.closed
30 | }
31 |
32 | type hijackableResponse struct {
33 | Hijacked bool
34 | }
35 |
36 | func newHijackableResponse() *hijackableResponse {
37 | return &hijackableResponse{}
38 | }
39 |
40 | func (h *hijackableResponse) Header() http.Header { return nil }
41 | func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil }
42 | func (h *hijackableResponse) WriteHeader(code int) {}
43 | func (h *hijackableResponse) Flush() {}
44 | func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
45 | h.Hijacked = true
46 | return nil, nil, nil
47 | }
48 |
49 | func TestResponseWriterWritingString(t *testing.T) {
50 | rec := httptest.NewRecorder()
51 | rw := NewResponseWriter(rec)
52 |
53 | rw.Write([]byte("Hello world"))
54 |
55 | expect(t, rec.Code, rw.Status())
56 | expect(t, rec.Body.String(), "Hello world")
57 | expect(t, rw.Status(), http.StatusOK)
58 | expect(t, rw.Size(), 11)
59 | expect(t, rw.Written(), true)
60 | }
61 |
62 | func TestResponseWriterWritingStrings(t *testing.T) {
63 | rec := httptest.NewRecorder()
64 | rw := NewResponseWriter(rec)
65 |
66 | rw.Write([]byte("Hello world"))
67 | rw.Write([]byte("foo bar bat baz"))
68 |
69 | expect(t, rec.Code, rw.Status())
70 | expect(t, rec.Body.String(), "Hello worldfoo bar bat baz")
71 | expect(t, rw.Status(), http.StatusOK)
72 | expect(t, rw.Size(), 26)
73 | }
74 |
75 | func TestResponseWriterWritingHeader(t *testing.T) {
76 | rec := httptest.NewRecorder()
77 | rw := NewResponseWriter(rec)
78 |
79 | rw.WriteHeader(http.StatusNotFound)
80 |
81 | expect(t, rec.Code, rw.Status())
82 | expect(t, rec.Body.String(), "")
83 | expect(t, rw.Status(), http.StatusNotFound)
84 | expect(t, rw.Size(), 0)
85 | }
86 |
87 | func TestResponseWriterBefore(t *testing.T) {
88 | rec := httptest.NewRecorder()
89 | rw := NewResponseWriter(rec)
90 | result := ""
91 |
92 | rw.Before(func(ResponseWriter) {
93 | result += "foo"
94 | })
95 | rw.Before(func(ResponseWriter) {
96 | result += "bar"
97 | })
98 |
99 | rw.WriteHeader(http.StatusNotFound)
100 |
101 | expect(t, rec.Code, rw.Status())
102 | expect(t, rec.Body.String(), "")
103 | expect(t, rw.Status(), http.StatusNotFound)
104 | expect(t, rw.Size(), 0)
105 | expect(t, result, "barfoo")
106 | }
107 |
108 | func TestResponseWriterHijack(t *testing.T) {
109 | hijackable := newHijackableResponse()
110 | rw := NewResponseWriter(hijackable)
111 | hijacker, ok := rw.(http.Hijacker)
112 | expect(t, ok, true)
113 | _, _, err := hijacker.Hijack()
114 | if err != nil {
115 | t.Error(err)
116 | }
117 | expect(t, hijackable.Hijacked, true)
118 | }
119 |
120 | func TestResponseWriteHijackNotOK(t *testing.T) {
121 | hijackable := new(http.ResponseWriter)
122 | rw := NewResponseWriter(*hijackable)
123 | hijacker, ok := rw.(http.Hijacker)
124 | expect(t, ok, true)
125 | _, _, err := hijacker.Hijack()
126 |
127 | refute(t, err, nil)
128 | }
129 |
130 | func TestResponseWriterCloseNotify(t *testing.T) {
131 | rec := newCloseNotifyingRecorder()
132 | rw := NewResponseWriter(rec)
133 | closed := false
134 | notifier := rw.(http.CloseNotifier).CloseNotify()
135 | rec.close()
136 | select {
137 | case <-notifier:
138 | closed = true
139 | case <-time.After(time.Second):
140 | }
141 | expect(t, closed, true)
142 | }
143 |
144 | func TestResponseWriterFlusher(t *testing.T) {
145 | rec := httptest.NewRecorder()
146 | rw := NewResponseWriter(rec)
147 |
148 | _, ok := rw.(http.Flusher)
149 | expect(t, ok, true)
150 | }
151 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/context/context.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package context
6 |
7 | import (
8 | "net/http"
9 | "sync"
10 | "time"
11 | )
12 |
13 | var (
14 | mutex sync.RWMutex
15 | data = make(map[*http.Request]map[interface{}]interface{})
16 | datat = make(map[*http.Request]int64)
17 | )
18 |
19 | // Set stores a value for a given key in a given request.
20 | func Set(r *http.Request, key, val interface{}) {
21 | mutex.Lock()
22 | if data[r] == nil {
23 | data[r] = make(map[interface{}]interface{})
24 | datat[r] = time.Now().Unix()
25 | }
26 | data[r][key] = val
27 | mutex.Unlock()
28 | }
29 |
30 | // Get returns a value stored for a given key in a given request.
31 | func Get(r *http.Request, key interface{}) interface{} {
32 | mutex.RLock()
33 | if ctx := data[r]; ctx != nil {
34 | value := ctx[key]
35 | mutex.RUnlock()
36 | return value
37 | }
38 | mutex.RUnlock()
39 | return nil
40 | }
41 |
42 | // GetOk returns stored value and presence state like multi-value return of map access.
43 | func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
44 | mutex.RLock()
45 | if _, ok := data[r]; ok {
46 | value, ok := data[r][key]
47 | mutex.RUnlock()
48 | return value, ok
49 | }
50 | mutex.RUnlock()
51 | return nil, false
52 | }
53 |
54 | // GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
55 | func GetAll(r *http.Request) map[interface{}]interface{} {
56 | mutex.RLock()
57 | if context, ok := data[r]; ok {
58 | result := make(map[interface{}]interface{}, len(context))
59 | for k, v := range context {
60 | result[k] = v
61 | }
62 | mutex.RUnlock()
63 | return result
64 | }
65 | mutex.RUnlock()
66 | return nil
67 | }
68 |
69 | // GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
70 | // the request was registered.
71 | func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
72 | mutex.RLock()
73 | context, ok := data[r]
74 | result := make(map[interface{}]interface{}, len(context))
75 | for k, v := range context {
76 | result[k] = v
77 | }
78 | mutex.RUnlock()
79 | return result, ok
80 | }
81 |
82 | // Delete removes a value stored for a given key in a given request.
83 | func Delete(r *http.Request, key interface{}) {
84 | mutex.Lock()
85 | if data[r] != nil {
86 | delete(data[r], key)
87 | }
88 | mutex.Unlock()
89 | }
90 |
91 | // Clear removes all values stored for a given request.
92 | //
93 | // This is usually called by a handler wrapper to clean up request
94 | // variables at the end of a request lifetime. See ClearHandler().
95 | func Clear(r *http.Request) {
96 | mutex.Lock()
97 | clear(r)
98 | mutex.Unlock()
99 | }
100 |
101 | // clear is Clear without the lock.
102 | func clear(r *http.Request) {
103 | delete(data, r)
104 | delete(datat, r)
105 | }
106 |
107 | // Purge removes request data stored for longer than maxAge, in seconds.
108 | // It returns the amount of requests removed.
109 | //
110 | // If maxAge <= 0, all request data is removed.
111 | //
112 | // This is only used for sanity check: in case context cleaning was not
113 | // properly set some request data can be kept forever, consuming an increasing
114 | // amount of memory. In case this is detected, Purge() must be called
115 | // periodically until the problem is fixed.
116 | func Purge(maxAge int) int {
117 | mutex.Lock()
118 | count := 0
119 | if maxAge <= 0 {
120 | count = len(data)
121 | data = make(map[*http.Request]map[interface{}]interface{})
122 | datat = make(map[*http.Request]int64)
123 | } else {
124 | min := time.Now().Unix() - int64(maxAge)
125 | for r := range data {
126 | if datat[r] < min {
127 | clear(r)
128 | count++
129 | }
130 | }
131 | }
132 | mutex.Unlock()
133 | return count
134 | }
135 |
136 | // ClearHandler wraps an http.Handler and clears request values at the end
137 | // of a request lifetime.
138 | func ClearHandler(h http.Handler) http.Handler {
139 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
140 | defer Clear(r)
141 | h.ServeHTTP(w, r)
142 | })
143 | }
144 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/example_test.go:
--------------------------------------------------------------------------------
1 | package firego_test
2 |
3 | import (
4 | "log"
5 | "time"
6 |
7 | "github.com/zabawaba99/firego"
8 | )
9 |
10 | func ExampleFirebase_Auth() {
11 | fb := firego.New("https://someapp.firebaseio.com", nil)
12 | fb.Auth("my-token")
13 | }
14 |
15 | func ExampleFirebase_Child() {
16 | fb := firego.New("https://someapp.firebaseio.com", nil)
17 | childFB := fb.Child("some/child/path")
18 |
19 | log.Printf("My new ref %s\n", childFB)
20 | }
21 |
22 | func ExampleFirebase_Shallow() {
23 | fb := firego.New("https://someapp.firebaseio.com", nil)
24 | // Set value
25 | fb.Shallow(true)
26 | // Remove query parameter
27 | fb.Shallow(false)
28 | }
29 |
30 | func ExampleFirebase_IncludePriority() {
31 | fb := firego.New("https://someapp.firebaseio.com", nil)
32 | // Set value
33 | fb.IncludePriority(true)
34 | // Remove query parameter
35 | fb.IncludePriority(false)
36 | }
37 |
38 | func ExampleFirebase_StartAt() {
39 | fb := firego.New("https://someapp.firebaseio.com", nil)
40 | // Set value
41 | fb = fb.StartAt("a")
42 | // Remove query parameter
43 | fb = fb.StartAt("")
44 | }
45 |
46 | func ExampleFirebase_EndAt() {
47 | fb := firego.New("https://someapp.firebaseio.com", nil)
48 | // Set value
49 | fb = fb.EndAt("a")
50 | // Remove query parameter
51 | fb = fb.EndAt("")
52 | }
53 |
54 | func ExampleFirebase_OrderBy() {
55 | fb := firego.New("https://someapp.firebaseio.com", nil)
56 | // Set value
57 | fb = fb.OrderBy("a")
58 | // Remove query parameter
59 | fb = fb.OrderBy("")
60 | }
61 |
62 | func ExampleFirebase_LimitToFirst() {
63 | fb := firego.New("https://someapp.firebaseio.com", nil)
64 | // Set value
65 | fb = fb.LimitToFirst(5)
66 | // Remove query parameter
67 | fb = fb.LimitToFirst(-1)
68 | }
69 |
70 | func ExampleFirebase_LimitToLast() {
71 | fb := firego.New("https://someapp.firebaseio.com", nil)
72 | // Set value
73 | fb = fb.LimitToLast(8)
74 | // Remove query parameter
75 | fb = fb.LimitToLast(-1)
76 | }
77 |
78 | func ExampleFirebase_Push() {
79 | fb := firego.New("https://someapp.firebaseio.com", nil)
80 | newRef, err := fb.Push("my-value")
81 | if err != nil {
82 | log.Fatal(err)
83 | }
84 |
85 | log.Printf("My new ref %s\n", newRef)
86 | }
87 |
88 | func ExampleFirebase_Remove() {
89 | fb := firego.New("https://someapp.firebaseio.com/some/value", nil)
90 | if err := fb.Remove(); err != nil {
91 | log.Fatal(err)
92 | }
93 | }
94 |
95 | func ExampleFirebase_Set() {
96 | fb := firego.New("https://someapp.firebaseio.com", nil)
97 |
98 | v := map[string]interface{}{
99 | "foo": "bar",
100 | "bar": 1,
101 | "bez": []string{"hello", "world"},
102 | }
103 | if err := fb.Set(v); err != nil {
104 | log.Fatal(err)
105 | }
106 | }
107 |
108 | func ExampleFirebase_Update() {
109 | fb := firego.New("https://someapp.firebaseio.com/some/value", nil)
110 | if err := fb.Update("new-value"); err != nil {
111 | log.Fatal(err)
112 | }
113 | }
114 |
115 | func ExampleFirebase_Value() {
116 | fb := firego.New("https://someapp.firebaseio.com/some/value", nil)
117 | var v interface{}
118 | if err := fb.Value(v); err != nil {
119 | log.Fatal(err)
120 | }
121 |
122 | log.Printf("My value %v\n", v)
123 | }
124 |
125 | func ExampleFirebase_Watch() {
126 | fb := firego.New("https://someapp.firebaseio.com/some/value", nil)
127 | notifications := make(chan firego.Event)
128 | if err := fb.Watch(notifications); err != nil {
129 | log.Fatal(err)
130 | }
131 |
132 | for event := range notifications {
133 | log.Println("Event Received")
134 | log.Printf("Type: %s\n", event.Type)
135 | log.Printf("Path: %s\n", event.Path)
136 | log.Printf("Data: %v\n", event.Data)
137 | if event.Type == firego.EventTypeError {
138 | log.Print("Error occurred, loop ending")
139 | }
140 | }
141 | }
142 |
143 | func ExampleFirebase_StopWatching() {
144 | fb := firego.New("https://someapp.firebaseio.com/some/value", nil)
145 | notifications := make(chan firego.Event)
146 | if err := fb.Watch(notifications); err != nil {
147 | log.Fatal(err)
148 | }
149 |
150 | go func() {
151 | for range notifications {
152 | }
153 | log.Println("Channel closed")
154 | }()
155 | time.Sleep(10 * time.Millisecond) // let go routine start
156 |
157 | fb.StopWatching()
158 | }
159 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/node.go:
--------------------------------------------------------------------------------
1 | package sync
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "reflect"
7 | "strconv"
8 | "strings"
9 | "sync"
10 | )
11 |
12 | // Node represents an object linked in Database. This object
13 | // should not be created by hand, use NewNode when creating
14 | // a new instance of Node.
15 | type Node struct {
16 | mtx sync.RWMutex
17 | Key string
18 | Value interface{}
19 | Children map[string]*Node
20 |
21 | Parent *Node
22 | sliceKids bool
23 | }
24 |
25 | // NewNode converts the given data into a node.
26 | func NewNode(key string, data interface{}) *Node {
27 | n := &Node{
28 | Key: key,
29 | }
30 |
31 | n.mtx.Lock()
32 | n.Children = map[string]*Node{}
33 | n.mtx.Unlock()
34 |
35 | if data == nil {
36 | return n
37 | }
38 |
39 | switch val := reflect.ValueOf(data); val.Kind() {
40 | case reflect.Map:
41 | for _, k := range val.MapKeys() {
42 | v := val.MapIndex(k)
43 | key := fmt.Sprintf("%s", k.Interface())
44 |
45 | child := NewNode(key, v.Interface())
46 | child.Parent = n
47 | n.Children[key] = child
48 | }
49 |
50 | case reflect.Array, reflect.Slice:
51 | n.sliceKids = true
52 |
53 | for i := 0; i < val.Len(); i++ {
54 | v := val.Index(i)
55 | key := strconv.FormatInt(int64(i), 10)
56 |
57 | child := NewNode(key, v.Interface())
58 | child.Parent = n
59 | n.Children[key] = child
60 | }
61 |
62 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
63 | fallthrough
64 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
65 | fallthrough
66 | case reflect.Float32, reflect.Float64:
67 | fallthrough
68 | case reflect.String, reflect.Bool, reflect.Interface:
69 | n.Value = val.Interface()
70 | default:
71 | fmt.Printf("Unsupported type %s(%#v)If you see this log please report an issue on https://github.com/zabawaba99/firego", data, data)
72 | }
73 |
74 | return n
75 | }
76 |
77 | // MarshalJSON turns the node object into JSON bytes.
78 | func (n *Node) MarshalJSON() ([]byte, error) {
79 | return json.Marshal(n.Objectify())
80 | }
81 |
82 | // Objectify turns the node and all its children into a go type.
83 | // If a node was created from a slice initially, a slice will be return.
84 | // If a node has child nodes, a map will be returned.
85 | // Otherwise, a primitive type will be returned.
86 | func (n *Node) Objectify() interface{} {
87 | n.mtx.RLock()
88 | defer n.mtx.RUnlock()
89 |
90 | if n.isNil() {
91 | return nil
92 | }
93 |
94 | if n.Value != nil {
95 | return n.Value
96 | }
97 |
98 | if n.sliceKids {
99 | obj := make([]interface{}, len(n.Children))
100 | for k, v := range n.Children {
101 | index, err := strconv.Atoi(k)
102 | if err != nil {
103 | continue
104 | }
105 | obj[index] = v.Objectify()
106 | }
107 | return obj
108 | }
109 |
110 | obj := map[string]interface{}{}
111 | for k, v := range n.Children {
112 | obj[k] = v.Objectify()
113 | }
114 |
115 | return obj
116 | }
117 |
118 | // Child gets a DataSnapshot for the location at the specified relative path.
119 | // The relative path can either be a simple child key (e.g. 'fred') or a deeper
120 | // slash-separated path (e.g. 'fred/name/first').
121 | func (n *Node) Child(name string) (*Node, bool) {
122 | n.mtx.RLock()
123 | defer n.mtx.RUnlock()
124 |
125 | name = strings.Trim(name, "/")
126 | rabbitHole := strings.Split(name, "/")
127 |
128 | current := n
129 | for i := 0; i < len(rabbitHole); i++ {
130 | next, ok := current.Children[rabbitHole[i]]
131 | if !ok {
132 | // item does not exist, no need to do anything
133 | return nil, false
134 | }
135 |
136 | current = next
137 | }
138 | return current, true
139 | }
140 |
141 | func (n *Node) isNil() bool {
142 | n.mtx.RLock()
143 | defer n.mtx.RUnlock()
144 |
145 | return n.Value == nil && len(n.Children) == 0
146 | }
147 |
148 | func (n *Node) merge(newNode *Node) {
149 | n.mtx.Lock()
150 | defer n.mtx.Unlock()
151 |
152 | for k, v := range newNode.Children {
153 | n.Children[k] = v
154 | }
155 | n.Value = newNode.Value
156 | }
157 |
158 | func (n *Node) prune() *Node {
159 | n.mtx.Lock()
160 | defer n.mtx.Unlock()
161 |
162 | if len(n.Children) > 0 || n.Value != nil {
163 | return nil
164 | }
165 |
166 | parent := n.Parent
167 | n.Parent = nil
168 | return parent
169 | }
170 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/negroni.go:
--------------------------------------------------------------------------------
1 | package negroni
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "os"
7 | )
8 |
9 | // Handler handler is an interface that objects can implement to be registered to serve as middleware
10 | // in the Negroni middleware stack.
11 | // ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
12 | // passed in.
13 | //
14 | // If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
15 | type Handler interface {
16 | ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
17 | }
18 |
19 | // HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
20 | // If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
21 | type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
22 |
23 | func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
24 | h(rw, r, next)
25 | }
26 |
27 | type middleware struct {
28 | handler Handler
29 | next *middleware
30 | }
31 |
32 | func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
33 | m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
34 | }
35 |
36 | // Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
37 | // middleware. The next http.HandlerFunc is automatically called after the Handler
38 | // is executed.
39 | func Wrap(handler http.Handler) Handler {
40 | return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
41 | handler.ServeHTTP(rw, r)
42 | next(rw, r)
43 | })
44 | }
45 |
46 | // Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
47 | // Negroni middleware is evaluated in the order that they are added to the stack using
48 | // the Use and UseHandler methods.
49 | type Negroni struct {
50 | middleware middleware
51 | handlers []Handler
52 | }
53 |
54 | // New returns a new Negroni instance with no middleware preconfigured.
55 | func New(handlers ...Handler) *Negroni {
56 | return &Negroni{
57 | handlers: handlers,
58 | middleware: build(handlers),
59 | }
60 | }
61 |
62 | // Classic returns a new Negroni instance with the default middleware already
63 | // in the stack.
64 | //
65 | // Recovery - Panic Recovery Middleware
66 | // Logger - Request/Response Logging
67 | // Static - Static File Serving
68 | func Classic() *Negroni {
69 | return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
70 | }
71 |
72 | func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
73 | n.middleware.ServeHTTP(NewResponseWriter(rw), r)
74 | }
75 |
76 | // Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
77 | func (n *Negroni) Use(handler Handler) {
78 | if handler == nil {
79 | panic("handler cannot be nil")
80 | }
81 |
82 | n.handlers = append(n.handlers, handler)
83 | n.middleware = build(n.handlers)
84 | }
85 |
86 | // UseFunc adds a Negroni-style handler function onto the middleware stack.
87 | func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
88 | n.Use(HandlerFunc(handlerFunc))
89 | }
90 |
91 | // UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
92 | func (n *Negroni) UseHandler(handler http.Handler) {
93 | n.Use(Wrap(handler))
94 | }
95 |
96 | // UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack.
97 | func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
98 | n.UseHandler(http.HandlerFunc(handlerFunc))
99 | }
100 |
101 | // Run is a convenience function that runs the negroni stack as an HTTP
102 | // server. The addr string takes the same format as http.ListenAndServe.
103 | func (n *Negroni) Run(addr string) {
104 | l := log.New(os.Stdout, "[negroni] ", 0)
105 | l.Printf("listening on %s", addr)
106 | l.Fatal(http.ListenAndServe(addr, n))
107 | }
108 |
109 | // Returns a list of all the handlers in the current Negroni middleware chain.
110 | func (n *Negroni) Handlers() []Handler {
111 | return n.handlers
112 | }
113 |
114 | func build(handlers []Handler) middleware {
115 | var next middleware
116 |
117 | if len(handlers) == 0 {
118 | return voidMiddleware()
119 | } else if len(handlers) > 1 {
120 | next = build(handlers[1:])
121 | } else {
122 | next = voidMiddleware()
123 | }
124 |
125 | return middleware{handlers[0], &next}
126 | }
127 |
128 | func voidMiddleware() middleware {
129 | return middleware{
130 | HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
131 | &middleware{},
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/README.md:
--------------------------------------------------------------------------------
1 | # Firego
2 | ---
3 | [](https://travis-ci.org/zabawaba99/firego) [](https://coveralls.io/github/zabawaba99/firego?branch=v1)
4 | ---
5 |
6 | A Firebase client written in Go
7 |
8 | ## Installation
9 |
10 | ```bash
11 | go get -u gopkg.in/zabawaba99/firego.v1
12 | ```
13 |
14 | ## Usage
15 |
16 | Import firego
17 |
18 | ```go
19 | import "gopkg.in/zabawaba99/firego.v1"
20 | ```
21 |
22 | Create a new firego reference
23 |
24 | ```go
25 | f := firego.New("https://my-firebase-app.firebaseIO.com", nil)
26 | ```
27 |
28 | with existing http client
29 |
30 | ```go
31 | f := firego.New("https://my-firebase-app.firebaseIO.com", client)
32 | ```
33 |
34 | ### Request Timeouts
35 |
36 | By default, the `Firebase` reference will timeout after 30 seconds of trying
37 | to reach a Firebase server. You can configure this value by setting the global
38 | timeout duration
39 |
40 | ```go
41 | firego.TimeoutDuration = time.Minute
42 | ```
43 |
44 | ### Authentication
45 |
46 | You can authenticate with your `service_account.json` file by using the
47 | `golang.org/x/oauth2` package (thanks @m00sey for the snippet)
48 |
49 | ```go
50 | d, err := ioutil.ReadFile("our_service_account.json")
51 | if err != nil {
52 | return nil, err
53 | }
54 |
55 | conf, err := google.JWTConfigFromJSON(d, "https://www.googleapis.com/auth/userinfo.email",
56 | "https://www.googleapis.com/auth/firebase.database")
57 | if err != nil {
58 | return nil, err
59 | }
60 |
61 | fb := firego.New("https://you.firebaseio.com", conf.Client(oauth2.NoContext))
62 | // use the authenticated fb instance
63 | ```
64 |
65 | ### Legacy Tokens
66 |
67 | ```go
68 | f.Auth("some-token-that-was-created-for-me")
69 | f.Unauth()
70 | ```
71 |
72 | Visit [Fireauth](https://github.com/zabawaba99/fireauth) if you'd like to generate your own auth tokens
73 |
74 | ### Get Value
75 |
76 | ```go
77 | var v map[string]interface{}
78 | if err := f.Value(&v); err != nil {
79 | log.Fatal(err)
80 | }
81 | fmt.Printf("%s\n", v)
82 | ```
83 |
84 | #### Querying
85 |
86 | Take a look at Firebase's [query parameters](https://www.firebase.com/docs/rest/guide/retrieving-data.html#section-rest-filtering)
87 | for more information on what each function does.
88 |
89 | ```go
90 | var v map[string]interface{}
91 | if err := f.StartAt("a").EndAt("c").LimitToFirst(8).OrderBy("field").Value(&v); err != nil {
92 | log.Fatal(err)
93 | }
94 | fmt.Printf("%s\n", v)
95 | ```
96 |
97 | ### Set Value
98 |
99 | ```go
100 | v := map[string]string{"foo":"bar"}
101 | if err := f.Set(v); err != nil {
102 | log.Fatal(err)
103 | }
104 | ```
105 |
106 | ### Push Value
107 |
108 | ```go
109 | v := "bar"
110 | pushedFirego, err := f.Push(v)
111 | if err != nil {
112 | log.Fatal(err)
113 | }
114 |
115 | var bar string
116 | if err := pushedFirego.Value(&bar); err != nil {
117 | log.Fatal(err)
118 | }
119 |
120 | // prints "https://my-firebase-app.firebaseIO.com/-JgvLHXszP4xS0AUN-nI: bar"
121 | fmt.Printf("%s: %s\n", pushedFirego, bar)
122 | ```
123 |
124 | ### Update Child
125 |
126 | ```go
127 | v := map[string]string{"foo":"bar"}
128 | if err := f.Update(v); err != nil {
129 | log.Fatal(err)
130 | }
131 | ```
132 |
133 | ### Remove Value
134 |
135 | ```go
136 | if err := f.Remove(); err != nil {
137 | log.Fatal(err)
138 | }
139 | ```
140 |
141 | ### Watch a Node
142 |
143 | ```go
144 | notifications := make(chan firego.Event)
145 | if err := f.Watch(notifications); err != nil {
146 | log.Fatal(err)
147 | }
148 |
149 | defer f.StopWatching()
150 | for event := range notifications {
151 | fmt.Printf("Event %#v\n", event)
152 | }
153 | fmt.Printf("Notifications have stopped")
154 | ```
155 | ### Change reference
156 |
157 | You can use a reference to save or read data from a specified reference
158 |
159 | ```go
160 | userID := "bar"
161 | usersRef,err := f.Ref("users/"+userID)
162 | if err != nil {
163 | log.Fatal(err)
164 | }
165 | v := map[string]string{"id":userID}
166 | if err := usersRef.Set(v); err != nil {
167 | log.Fatal(err)
168 | }
169 |
170 | ```
171 |
172 | Check the [GoDocs](http://godoc.org/gopkg.in/zabawaba99/firego.v1) or
173 | [Firebase Documentation](https://www.firebase.com/docs/rest/) for more details
174 |
175 | ## Running Tests
176 |
177 | In order to run the tests you need to `go get -t ./...`
178 | first to go-get the test dependencies.
179 |
180 | ## Issues Management
181 |
182 | Feel free to open an issue if you come across any bugs or
183 | if you'd like to request a new feature.
184 |
185 | ## Contributing
186 |
187 | 1. Fork it
188 | 2. Create your feature branch (`git checkout -b new-feature`)
189 | 3. Commit your changes (`git commit -am 'Some cool reflection'`)
190 | 4. Push to the branch (`git push origin new-feature`)
191 | 5. Create new Pull Request
192 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/firebase_test.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "net/http/httptest"
7 | "strings"
8 | "testing"
9 | "time"
10 |
11 | "github.com/stretchr/testify/assert"
12 | "github.com/stretchr/testify/require"
13 | "github.com/zabawaba99/firego/internal/firetest"
14 | )
15 |
16 | const URL = "https://somefirebaseapp.firebaseIO.com"
17 |
18 | const authToken = "token"
19 |
20 | type TestServer struct {
21 | *httptest.Server
22 | receivedReqs []*http.Request
23 | }
24 |
25 | func newTestServer(response string) *TestServer {
26 | ts := &TestServer{}
27 | ts.Server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
28 | ts.receivedReqs = append(ts.receivedReqs, req)
29 | fmt.Fprint(w, response)
30 | }))
31 | return ts
32 | }
33 |
34 | func TestNew(t *testing.T) {
35 | t.Parallel()
36 | testURLs := []string{
37 | URL,
38 | URL + "/",
39 | "somefirebaseapp.firebaseIO.com",
40 | "somefirebaseapp.firebaseIO.com/",
41 | }
42 |
43 | for _, url := range testURLs {
44 | fb := New(url, nil)
45 | assert.Equal(t, URL, fb.url, "givenURL: %s", url)
46 | }
47 | }
48 |
49 | func TestNewWithProvidedHttpClient(t *testing.T) {
50 | t.Parallel()
51 |
52 | var client = http.DefaultClient
53 | testURLs := []string{
54 | URL,
55 | URL + "/",
56 | "somefirebaseapp.firebaseIO.com",
57 | "somefirebaseapp.firebaseIO.com/",
58 | }
59 |
60 | for _, url := range testURLs {
61 | fb := New(url, client)
62 | assert.Equal(t, URL, fb.url, "givenURL: %s", url)
63 | assert.Equal(t, client, fb.client)
64 | }
65 | }
66 |
67 | func TestAuth(t *testing.T) {
68 | t.Parallel()
69 | server := firetest.New()
70 | server.Start()
71 | defer server.Close()
72 |
73 | server.RequireAuth(true)
74 | fb := New(server.URL, nil)
75 |
76 | fb.Auth(server.Secret)
77 | var v interface{}
78 | err := fb.Value(&v)
79 | assert.NoError(t, err)
80 | }
81 |
82 | func TestUnauth(t *testing.T) {
83 | t.Parallel()
84 | server := firetest.New()
85 | server.Start()
86 | defer server.Close()
87 |
88 | server.RequireAuth(true)
89 | fb := New(server.URL, nil)
90 |
91 | fb.params.Add("auth", server.Secret)
92 | fb.Unauth()
93 | err := fb.Value("")
94 | assert.Error(t, err)
95 | }
96 |
97 | func TestPush(t *testing.T) {
98 | t.Parallel()
99 | var (
100 | payload = map[string]interface{}{"foo": "bar"}
101 | server = firetest.New()
102 | )
103 | server.Start()
104 | defer server.Close()
105 |
106 | fb := New(server.URL, nil)
107 | childRef, err := fb.Push(payload)
108 | assert.NoError(t, err)
109 |
110 | path := strings.TrimPrefix(childRef.String(), server.URL+"/")
111 | v := server.Get(path)
112 | assert.Equal(t, payload, v)
113 |
114 | childRef.Auth(server.Secret)
115 | var m map[string]interface{}
116 | require.NoError(t, childRef.Value(&m))
117 | assert.Equal(t, payload, m, childRef.String())
118 | }
119 |
120 | func TestRemove(t *testing.T) {
121 | t.Parallel()
122 | server := firetest.New()
123 | server.Start()
124 | defer server.Close()
125 |
126 | server.Set("", true)
127 |
128 | fb := New(server.URL, nil)
129 | err := fb.Remove()
130 | assert.NoError(t, err)
131 |
132 | v := server.Get("")
133 | assert.Nil(t, v)
134 | }
135 |
136 | func TestSet(t *testing.T) {
137 | t.Parallel()
138 | var (
139 | payload = map[string]interface{}{"foo": "bar"}
140 | server = firetest.New()
141 | )
142 | server.Start()
143 | defer server.Close()
144 |
145 | fb := New(server.URL, nil)
146 | err := fb.Set(payload)
147 | assert.NoError(t, err)
148 |
149 | v := server.Get("")
150 | assert.Equal(t, payload, v)
151 | }
152 |
153 | func TestUpdate(t *testing.T) {
154 | t.Parallel()
155 | var (
156 | payload = map[string]interface{}{"foo": "bar"}
157 | server = firetest.New()
158 | )
159 | server.Start()
160 | defer server.Close()
161 |
162 | fb := New(server.URL, nil)
163 | err := fb.Update(payload)
164 | assert.NoError(t, err)
165 |
166 | v := server.Get("")
167 | assert.Equal(t, payload, v)
168 | }
169 |
170 | func TestValue(t *testing.T) {
171 | t.Parallel()
172 | var (
173 | response = map[string]interface{}{"foo": "bar"}
174 | server = firetest.New()
175 | )
176 | server.Start()
177 | defer server.Close()
178 |
179 | fb := New(server.URL, nil)
180 |
181 | server.Set("", response)
182 |
183 | var v map[string]interface{}
184 | err := fb.Value(&v)
185 | assert.NoError(t, err)
186 | assert.Equal(t, response, v)
187 | }
188 |
189 | func TestChild(t *testing.T) {
190 | t.Parallel()
191 | var (
192 | parent = New(URL, nil)
193 | childNode = "node"
194 | child = parent.Child(childNode)
195 | )
196 |
197 | assert.Equal(t, fmt.Sprintf("%s/%s", parent.url, childNode), child.url)
198 | }
199 |
200 | func TestChild_Issue26(t *testing.T) {
201 | t.Parallel()
202 | parent := New(URL, nil)
203 | child1 := parent.Child("one")
204 | child2 := child1.Child("two")
205 |
206 | child1.Shallow(true)
207 | assert.Len(t, child2.params, 0)
208 | }
209 |
210 | func TestTimeoutDuration_Headers(t *testing.T) {
211 | var fb *Firebase
212 | done := make(chan struct{})
213 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
214 | time.Sleep(2 * fb.clientTimeout)
215 | close(done)
216 | }))
217 | defer server.Close()
218 |
219 | fb = New(server.URL, nil)
220 | fb.clientTimeout = time.Millisecond
221 | err := fb.Value("")
222 | <-done
223 | assert.NotNil(t, err)
224 | assert.IsType(t, ErrTimeout{}, err)
225 |
226 | // ResponseHeaderTimeout should be TimeoutDuration less the time it took to dial, and should be positive
227 | require.IsType(t, (*http.Transport)(nil), fb.client.Transport)
228 | tr := fb.client.Transport.(*http.Transport)
229 | assert.True(t, tr.ResponseHeaderTimeout < TimeoutDuration)
230 | assert.True(t, tr.ResponseHeaderTimeout > 0)
231 | }
232 |
233 | func TestTimeoutDuration_Dial(t *testing.T) {
234 | fb := New("http://dialtimeouterr.or/", nil)
235 | fb.clientTimeout = time.Millisecond
236 |
237 | err := fb.Value("")
238 | assert.NotNil(t, err)
239 | assert.IsType(t, ErrTimeout{}, err)
240 |
241 | // ResponseHeaderTimeout should be negative since the total duration was consumed when dialing
242 | require.IsType(t, (*http.Transport)(nil), fb.client.Transport)
243 | assert.True(t, fb.client.Transport.(*http.Transport).ResponseHeaderTimeout < 0)
244 | }
245 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/translations/README_zh_tw.md:
--------------------------------------------------------------------------------
1 | # Negroni(尼格龍尼) [](http://godoc.org/github.com/codegangsta/negroni) [](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
2 |
3 | 尼格龍尼符合Go的web 中介器特性. 精簡、非侵入式、鼓勵使用 `net/http` Handler.
4 |
5 | 如果你喜歡[Martini](http://github.com/go-martini/martini),但覺得這其中包太多神奇的功能,那麼尼格龍尼會是你的最佳選擇。
6 |
7 | ## 入門
8 |
9 | 安裝完Go且設好[GOPATH](http://golang.org/doc/code.html#GOPATH),建立你的第一個`.go`檔。可以命名為`server.go`。
10 |
11 | ~~~ go
12 | package main
13 |
14 | import (
15 | "github.com/codegangsta/negroni"
16 | "net/http"
17 | "fmt"
18 | )
19 |
20 | func main() {
21 | mux := http.NewServeMux()
22 | mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
23 | fmt.Fprintf(w, "Welcome to the home page!")
24 | })
25 |
26 | n := negroni.Classic()
27 | n.UseHandler(mux)
28 | n.Run(":3000")
29 | }
30 | ~~~
31 |
32 | 安裝尼格龍尼套件 (最低需求為**go 1.1**或更高版本):
33 | ~~~
34 | go get github.com/codegangsta/negroni
35 | ~~~
36 |
37 | 執行伺服器:
38 | ~~~
39 | go run server.go
40 | ~~~
41 |
42 | 你現在起了一個Go的net/http網頁伺服器在`localhost:3000`.
43 |
44 | ## 有問題?
45 | 如果你有問題或新功能建議,[到這郵件群組討論](https://groups.google.com/forum/#!forum/negroni-users)。尼格龍尼在GitHub上的issues專欄是專門用來回報bug跟pull requests。
46 |
47 | ## 尼格龍尼是個framework嗎?
48 | 尼格龍尼**不是**framework,是個設計用來直接使用net/http的library。
49 |
50 | ## 路由?
51 | 尼格龍尼是BYOR (Bring your own Router,帶給你自訂路由)。在Go社群已經有大量可用的http路由器, 尼格龍尼試著做好完全支援`net/http`,例如與[Gorilla Mux](http://github.com/gorilla/mux)整合:
52 |
53 | ~~~ go
54 | router := mux.NewRouter()
55 | router.HandleFunc("/", HomeHandler)
56 |
57 | n := negroni.New(中介器1, 中介器2)
58 | // Or use a 中介器 with the Use() function
59 | n.Use(中介器3)
60 | // router goes last
61 | n.UseHandler(router)
62 |
63 | n.Run(":3000")
64 | ~~~
65 |
66 | ## `negroni.Classic()`
67 | `negroni.Classic()` 提供一些好用的預設中介器:
68 |
69 | * `negroni.Recovery` - Panic 還原中介器
70 | * `negroni.Logging` - Request/Response 紀錄中介器
71 | * `negroni.Static` - 在"public"目錄下的靜態檔案服務
72 |
73 | 尼格龍尼的這些功能讓你開發變得很簡單。
74 |
75 | ## 處理器(Handlers)
76 | 尼格龍尼提供一個雙向中介器的機制,介面為`negroni.Handler`:
77 |
78 | ~~~ go
79 | type Handler interface {
80 | ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
81 | }
82 | ~~~
83 |
84 | 如果中介器沒有寫入ResponseWriter,會呼叫通道裡面的下個`http.HandlerFunc`讓給中介處理器。可以被用來做良好的應用:
85 |
86 | ~~~ go
87 | func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
88 | // 在這之前做一些事
89 | next(rw, r)
90 | // 在這之後做一些事
91 | }
92 | ~~~
93 |
94 | 然後你可以透過`Use`函數對應到處理器的通道:
95 |
96 | ~~~ go
97 | n := negroni.New()
98 | n.Use(negroni.HandlerFunc(MyMiddleware))
99 | ~~~
100 |
101 | 你也可以應原始的舊`http.Handler`:
102 |
103 | ~~~ go
104 | n := negroni.New()
105 |
106 | mux := http.NewServeMux()
107 | // map your routes
108 |
109 | n.UseHandler(mux)
110 |
111 | n.Run(":3000")
112 | ~~~
113 |
114 | ## `Run()`
115 | 尼格龍尼有一個很好用的函數`Run`,`Run`接收addr字串辨識[http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe)。
116 |
117 | ~~~ go
118 | n := negroni.Classic()
119 | // ...
120 | log.Fatal(http.ListenAndServe(":8080", n))
121 | ~~~
122 |
123 | ## 路由特有中介器
124 | 如果你有一群路由需要執行特別的中介器,你可以簡單的建立一個新的尼格龍尼實體當作路由處理器。
125 |
126 | ~~~ go
127 | router := mux.NewRouter()
128 | adminRoutes := mux.NewRouter()
129 | // add admin routes here
130 |
131 | // 為管理中介器建立一個新的尼格龍尼
132 | router.Handle("/admin", negroni.New(
133 | Middleware1,
134 | Middleware2,
135 | negroni.Wrap(adminRoutes),
136 | ))
137 | ~~~
138 |
139 | ## 第三方中介器
140 |
141 | 以下為目前尼格龍尼兼容的中介器清單。如果你自己做了一個中介器請自由放入你的中介器互換連結:
142 |
143 | | 中介器 | 作者 | 說明 |
144 | | -----------|--------|-------------|
145 | | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | REST API入口的安全認證 |
146 | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | 優雅的HTTP關機 |
147 | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | 檢疫安全功能的中介器 |
148 | | [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | 檢查JWT的中介器用來解析傳入請求的`Authorization` header |
149 | | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | 將HTTP請求轉到structs的資料綁定 |
150 | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | 基於Logrus的紀錄器 |
151 | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | 渲染JSON、XML、HTML的樣板 |
152 | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | Go執行中的New Relic agent |
153 | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP回應壓縮 |
154 | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2中介器 |
155 | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session管理 |
156 | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies與使用者權限 |
157 | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | 快速產生TinySVG、HTM、CSS |
158 | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) 支援(CORS) |
159 | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | 在每個request指定一個隨機X-Request-Id header的中介器 |
160 | | [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC 授權中介器 |
161 | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | 儲存關於你的網頁應用資訊 (回應時間之類) |
162 |
163 | ## 範例
164 | [mooseware](https://github.com/xyproto/mooseware)是用來寫尼格龍尼中介處理器的骨架,由[Alexander Rødseth](https://github.com/xyproto)建立。
165 |
166 | ## 即時程式重載?
167 | [gin](https://github.com/codegangsta/gin)和[fresh](https://github.com/pilu/fresh)兩個尼格龍尼即時重載的應用。
168 |
169 | ## Go & 尼格龍尼初學者必讀
170 |
171 | * [使用Context將資訊從中介器送到處理器](http://elithrar.github.io/article/map-string-interface/)
172 | * [理解中介器](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
173 |
174 | ## 關於
175 |
176 | 尼格龍尼正是[Code Gangsta](http://codegangsta.io/)的執著設計。
177 | 譯者: Festum Qin (Festum@G.PL)
178 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/watch.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "encoding/json"
7 | "errors"
8 | "log"
9 | "net/http"
10 | "time"
11 | )
12 |
13 | const (
14 | // EventTypePut is the event type sent when new data is inserted to the
15 | // Firebase instance.
16 | EventTypePut = "put"
17 | // EventTypePatch is the event type sent when data at the Firebase instance is
18 | // updated.
19 | EventTypePatch = "patch"
20 | // EventTypeError is the event type sent when an unknown error is encountered.
21 | EventTypeError = "event_error"
22 | // EventTypeAuthRevoked is the event type sent when the supplied auth parameter
23 | // is no longer valid.
24 | EventTypeAuthRevoked = "auth_revoked"
25 |
26 | eventTypeKeepAlive = "keep-alive"
27 | eventTypeCancel = "cancel"
28 | eventTypeRulesDebug = "rules_debug"
29 | )
30 |
31 | // Event represents a notification received when watching a
32 | // firebase reference.
33 | type Event struct {
34 | // Type of event that was received
35 | Type string
36 | // Path to the data that changed
37 | Path string
38 | // Data that changed
39 | Data interface{}
40 |
41 | rawData []byte
42 | }
43 |
44 | // Value converts the raw payload of the event into the given interface.
45 | func (e Event) Value(v interface{}) error {
46 | var tmp struct {
47 | Data interface{} `json:"data"`
48 | }
49 | tmp.Data = &v
50 | return json.Unmarshal(e.rawData, &tmp)
51 | }
52 |
53 | // StopWatching stops tears down all connections that are watching.
54 | func (fb *Firebase) StopWatching() {
55 | fb.watchMtx.Lock()
56 | defer fb.watchMtx.Unlock()
57 |
58 | if fb.watching {
59 | // flip the bit back to not watching
60 | fb.watching = false
61 | // signal connection to terminal
62 | fb.stopWatching <- struct{}{}
63 | }
64 | }
65 |
66 | func (fb *Firebase) setWatching(v bool) {
67 | fb.watchMtx.Lock()
68 | fb.watching = v
69 | fb.watchMtx.Unlock()
70 | }
71 |
72 | // Watch listens for changes on a firebase instance and
73 | // passes over to the given chan.
74 | //
75 | // Only one connection can be established at a time. The
76 | // second call to this function without a call to fb.StopWatching
77 | // will close the channel given and return nil immediately.
78 | func (fb *Firebase) Watch(notifications chan Event) error {
79 | fb.watchMtx.Lock()
80 | if fb.watching {
81 | fb.watchMtx.Unlock()
82 | close(notifications)
83 | return nil
84 | }
85 | fb.watching = true
86 | fb.watchMtx.Unlock()
87 |
88 | stop := make(chan struct{})
89 | events, err := fb.watch(stop)
90 | if err != nil {
91 | return err
92 | }
93 |
94 | var closedManually bool
95 |
96 | go func() {
97 | <-fb.stopWatching
98 | closedManually = true
99 | stop <- struct{}{}
100 | }()
101 |
102 | go func() {
103 | defer close(notifications)
104 |
105 | for event := range events {
106 | if closedManually {
107 | return
108 | }
109 |
110 | notifications <- event
111 | }
112 | }()
113 |
114 | return nil
115 | }
116 |
117 | func readLine(rdr *bufio.Reader, prefix string) ([]byte, error) {
118 | // read event: line
119 | line, err := rdr.ReadBytes('\n')
120 | if err != nil {
121 | return nil, err
122 | }
123 |
124 | // empty line check for empty prefix
125 | if len(prefix) == 0 {
126 | line = bytes.TrimSpace(line)
127 | if len(line) != 0 {
128 | return nil, errors.New("expected empty line")
129 | }
130 | return line, nil
131 | }
132 |
133 | // check line has event prefix
134 | if !bytes.HasPrefix(line, []byte(prefix)) {
135 | return nil, errors.New("missing prefix")
136 | }
137 |
138 | // trim space
139 | line = line[len(prefix):]
140 | return bytes.TrimSpace(line), nil
141 | }
142 |
143 | func (fb *Firebase) watch(stop chan struct{}) (chan Event, error) {
144 | // build SSE request
145 | req, err := http.NewRequest("GET", fb.String(), nil)
146 | if err != nil {
147 | fb.setWatching(false)
148 | return nil, err
149 | }
150 | req.Header.Add("Accept", "text/event-stream")
151 |
152 | // do request
153 | resp, err := fb.client.Do(req)
154 | if err != nil {
155 | fb.setWatching(false)
156 | return nil, err
157 | }
158 |
159 | notifications := make(chan Event)
160 |
161 | go func() {
162 | <-stop
163 | resp.Body.Close()
164 | }()
165 |
166 | heartbeat := make(chan struct{})
167 | go func() {
168 | for {
169 | select {
170 | case <-heartbeat:
171 | // do nothing
172 | case <-time.After(fb.watchHeartbeat):
173 | resp.Body.Close()
174 | return
175 | }
176 | }
177 | }()
178 |
179 | // start parsing response body
180 | go func() {
181 | defer func() {
182 | resp.Body.Close()
183 | close(notifications)
184 | }()
185 |
186 | // build scanner for response body
187 | scanner := bufio.NewReader(resp.Body)
188 | sendError := func(err error) {
189 | notifications <- Event{
190 | Type: EventTypeError,
191 | Data: err,
192 | }
193 | }
194 | for {
195 | select {
196 | case heartbeat <- struct{}{}:
197 | default:
198 | }
199 | // scan for 'event:'
200 | evt, err := readLine(scanner, "event: ")
201 | if err != nil {
202 | sendError(err)
203 | return
204 | }
205 |
206 | // scan for 'data:'
207 | dat, err := readLine(scanner, "data: ")
208 | if err != nil {
209 | sendError(err)
210 | return
211 | }
212 |
213 | // read the empty line
214 | _, err = readLine(scanner, "")
215 | if err != nil {
216 | sendError(err)
217 | return
218 | }
219 |
220 | // create a base event
221 | event := Event{
222 | Type: string(evt),
223 | Data: string(dat),
224 | rawData: dat,
225 | }
226 |
227 | // should be reacting differently based off the type of event
228 | switch event.Type {
229 | case EventTypePut, EventTypePatch:
230 | // we've got extra data we've got to parse
231 | var data map[string]interface{}
232 | if err := json.Unmarshal(event.rawData, &data); err != nil {
233 | sendError(err)
234 | return
235 | }
236 |
237 | // set the extra fields
238 | event.Path = data["path"].(string)
239 | event.Data = data["data"]
240 |
241 | // ship it
242 | notifications <- event
243 | case eventTypeKeepAlive:
244 | // received ping - nothing to do here
245 | case eventTypeCancel:
246 | // The data for this event is null
247 | // This event will be sent if the Security and Firebase Rules
248 | // cause a read at the requested location to no longer be allowed
249 |
250 | // send the cancel event
251 | notifications <- event
252 | return
253 | case EventTypeAuthRevoked:
254 | // The data for this event is a string indicating that a the credential has expired
255 | // This event will be sent when the supplied auth parameter is no longer valid
256 | notifications <- event
257 | return
258 | case eventTypeRulesDebug:
259 | log.Printf("Rules-Debug: %s\n%s\n", evt, dat)
260 | }
261 | }
262 | }()
263 | return notifications, nil
264 | }
265 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/translations/README_zh_cn.md:
--------------------------------------------------------------------------------
1 | # Negroni [](http://godoc.org/github.com/codegangsta/negroni) [](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
2 |
3 | 在Go语言里,Negroni 是一个很地道的 web 中间件,它是微型,非嵌入式,并鼓励使用原生 `net/http` 处理器的库。
4 |
5 | 如果你用过并喜欢 [Martini](http://github.com/go-martini/martini) 框架,但又不想框架中有太多魔幻性的特征,那 Negroni 就是你的菜了,相信它非常适合你。
6 |
7 |
8 | 语言翻译:
9 | * [Português Brasileiro (pt_BR)](translations/README_pt_br.md)
10 | * [简体中文 (zh_CN)](translations/README_zh_cn.md)
11 |
12 | ## 入门指导
13 |
14 | 当安装了 Go 语言并设置好了 [GOPATH](http://golang.org/doc/code.html#GOPATH) 后,新建你第一个`.go` 文件,我们叫它 `server.go` 吧。
15 |
16 | ~~~ go
17 | package main
18 |
19 | import (
20 | "github.com/codegangsta/negroni"
21 | "net/http"
22 | "fmt"
23 | )
24 |
25 | func main() {
26 | mux := http.NewServeMux()
27 | mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
28 | fmt.Fprintf(w, "Welcome to the home page!")
29 | })
30 |
31 | n := negroni.Classic()
32 | n.UseHandler(mux)
33 | n.Run(":3000")
34 | }
35 | ~~~
36 |
37 | 然后安装 Negroni 包(它依赖 **Go 1.1** 或更高的版本):
38 | ~~~
39 | go get github.com/codegangsta/negroni
40 | ~~~
41 |
42 | 然后运行刚建好的 server.go 文件:
43 | ~~~
44 | go run server.go
45 | ~~~
46 |
47 | 这时一个 Go `net/http` Web 服务器就跑在 `localhost:3000` 上,使用浏览器打开 `localhost:3000` 可以看到输出结果。
48 |
49 | ## 需要你的贡献
50 | 如果你有问题或新想法,请到[邮件群组](https://groups.google.com/forum/#!forum/negroni-users)里反馈,GitHub issues 是专门给提交 bug 报告和 pull 请求用途的,欢迎你的参与。
51 |
52 | ## Negroni 是一个框架吗?
53 | Negroni **不**是一个框架,它是为了方便使用 `net/http` 而设计的一个库而已。
54 |
55 | ## 路由呢?
56 | Negroni 没有带路由功能,使用 Negroni 时,需要找一个适合你的路由。不过好在 Go 社区里已经有相当多可用的路由,Negroni 更喜欢和那些完全支持 `net/http` 库的路由组合使用,比如,结合 [Gorilla Mux](http://github.com/gorilla/mux) 使用像这样:
57 |
58 | ~~~ go
59 | router := mux.NewRouter()
60 | router.HandleFunc("/", HomeHandler)
61 |
62 | n := negroni.New(Middleware1, Middleware2)
63 | // Or use a middleware with the Use() function
64 | n.Use(Middleware3)
65 | // router goes last
66 | n.UseHandler(router)
67 |
68 | n.Run(":3000")
69 | ~~~
70 |
71 | ## `negroni.Classic()` 经典实例
72 | `negroni.Classic()` 提供一些默认的中间件,这些中间件在多数应用都很有用。
73 |
74 | * `negroni.Recovery` - 异常(恐慌)恢复中间件
75 | * `negroni.Logging` - 请求 / 响应 log 日志中间件
76 | * `negroni.Static` - 静态文件处理中间件,默认目录在 "public" 下.
77 |
78 | `negroni.Classic()` 让你一开始就非常容易上手 Negroni ,并使用它那些通用的功能。
79 |
80 | ## Handlers (处理器)
81 | Negroni 提供双向的中间件机制,这个特征很棒,都是得益于 `negroni.Handler` 这个接口。
82 |
83 | ~~~ go
84 | type Handler interface {
85 | ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
86 | }
87 | ~~~
88 |
89 | 如果一个中间件没有写入 ResponseWriter 响应,它会在中间件链里调用下一个 `http.HandlerFunc` 执行下去, 它可以这么优雅的使用。如下:
90 |
91 | ~~~ go
92 | func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
93 | // do some stuff before
94 | next(rw, r)
95 | // do some stuff after
96 | }
97 | ~~~
98 |
99 | 你也可以用 `Use` 函数把这些 `http.Handler` 处理器引进到处理器链上来:
100 |
101 | ~~~ go
102 | n := negroni.New()
103 | n.Use(negroni.HandlerFunc(MyMiddleware))
104 | ~~~
105 |
106 | 你还可以使用 `http.Handler`(s) 把 `http.Handler` 处理器引进来。
107 |
108 | ~~~ go
109 | n := negroni.New()
110 |
111 | mux := http.NewServeMux()
112 | // map your routes
113 |
114 | n.UseHandler(mux)
115 |
116 | n.Run(":3000")
117 | ~~~
118 |
119 | ## `Run()`
120 | Negroni 提供一个很好用的函数叫 `Run` ,把地址字符串传人该函数,即可实现很地道的 [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe) 函数功能了。
121 |
122 | ~~~ go
123 | n := negroni.Classic()
124 | // ...
125 | log.Fatal(http.ListenAndServe(":8080", n))
126 | ~~~
127 |
128 | ## 特定路由中间件
129 | 如果你需要群组路由功能,需要借助特定的路由中间件完成,做法很简单,只需建立一个新 Negroni 实例,传人路由处理器里即可。
130 |
131 | ~~~ go
132 | router := mux.NewRouter()
133 | adminRoutes := mux.NewRouter()
134 | // add admin routes here
135 |
136 | // Create a new negroni for the admin middleware
137 | router.Handle("/admin", negroni.New(
138 | Middleware1,
139 | Middleware2,
140 | negroni.Wrap(adminRoutes),
141 | ))
142 | ~~~
143 |
144 | ## 第三方中间件
145 |
146 | 以下的兼容 Negroni 的中间件列表,如果你也有兼容 Negroni 的中间件,可以提交到这个列表来交换链接,我们很乐意做这样有益的事情。
147 |
148 |
149 | | 中间件 | 作者 | 描述 |
150 | | -------------|------------|-------------|
151 | | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | REST API 接口的安全认证 |
152 | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | 优雅关闭 HTTP 的中间件 |
153 | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins |
154 | | [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it|
155 | | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | HTTP 请求数据注入到 structs 实体|
156 | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | 基于 Logrus-based logger 日志 |
157 | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | 渲染 JSON, XML and HTML 中间件 |
158 | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
159 | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | 响应流 GZIP 压缩 |
160 | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 中间件 |
161 | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session 会话管理 |
162 | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, 用户和权限 |
163 | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | 快速生成 TinySVG, HTML and CSS 中间件 |
164 | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support |
165 | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | 给每个请求指定一个随机 X-Request-Id 头的中间件 |
166 | | [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) 基于 HMAC 鉴权认证的中间件 |
167 | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | 检测 web 应用当前运行状态信息 (响应时间等等。) |
168 |
169 | ## 范例
170 | [Alexander Rødseth](https://github.com/xyproto) 创建的 [mooseware](https://github.com/xyproto/mooseware) 是一个写兼容 Negroni 中间件的处理器骨架的范例。
171 |
172 | ## 即时编译
173 | [gin](https://github.com/codegangsta/gin) 和 [fresh](https://github.com/pilu/fresh) 这两个应用是即时编译的 Negroni 工具,推荐用户开发的时候使用。
174 |
175 | ## Go & Negroni 初学者必读推荐
176 |
177 | * [在中间件中使用上下文把消息传递给后端处理器](http://elithrar.github.io/article/map-string-interface/)
178 | * [了解中间件](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
179 |
180 | ## 关于
181 |
182 | Negroni 由 [Code Gangsta](http://codegangsta.io/) 主导设计开发完成
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/watch_test.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "net/http/httptest"
7 | "strings"
8 | "testing"
9 | "time"
10 |
11 | "github.com/stretchr/testify/assert"
12 | "github.com/stretchr/testify/require"
13 | "github.com/zabawaba99/firego/internal/firetest"
14 | )
15 |
16 | func setupLargeResult() string {
17 | return "start" + strings.Repeat("0", 64*1024) + "end"
18 | }
19 |
20 | func TestWatch(t *testing.T) {
21 | server := firetest.New()
22 | server.Start()
23 | defer server.Close()
24 |
25 | fb := New(server.URL, nil)
26 |
27 | notifications := make(chan Event)
28 | err := fb.Watch(notifications)
29 | assert.NoError(t, err)
30 |
31 | l := setupLargeResult()
32 | server.Set("/foo", l)
33 |
34 | select {
35 | case event, ok := <-notifications:
36 | assert.True(t, ok)
37 | assert.Equal(t, "put", event.Type)
38 | assert.Equal(t, "/", event.Path)
39 | assert.Nil(t, event.Data)
40 | case <-time.After(250 * time.Millisecond):
41 | require.FailNow(t, "did not receive a notification initial notification")
42 | }
43 |
44 | select {
45 | case event, ok := <-notifications:
46 | assert.True(t, ok)
47 | assert.Equal(t, "/foo", event.Path)
48 | assert.EqualValues(t, l, event.Data)
49 | var v string
50 | assert.NoError(t, event.Value(&v))
51 | assert.EqualValues(t, l, v)
52 | case <-time.After(250 * time.Millisecond):
53 | require.FailNow(t, "did not receive a notification")
54 | }
55 | }
56 |
57 | func TestWatchRedirectPreservesHeader(t *testing.T) {
58 | t.Parallel()
59 |
60 | redirectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
61 | assert.Equal(t, []string{"text/event-stream"}, req.Header["Accept"])
62 | w.Header().Set("Content-Type", "text/event-stream")
63 | w.WriteHeader(http.StatusOK)
64 | }))
65 | defer redirectServer.Close()
66 |
67 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
68 | w.Header().Set("Content-Type", "application/json")
69 | w.Header().Set("Location", redirectServer.URL)
70 | w.WriteHeader(http.StatusTemporaryRedirect)
71 | }))
72 | defer server.Close()
73 |
74 | fb := New(server.URL, nil)
75 | notifications := make(chan Event)
76 |
77 | err := fb.Watch(notifications)
78 | assert.NoError(t, err)
79 | }
80 |
81 | func TestWatchHeartbeatTimeout(t *testing.T) {
82 | var fb *Firebase
83 |
84 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
85 | flusher, ok := w.(http.Flusher)
86 | require.True(t, ok, "streaming unsupported")
87 |
88 | w.Header().Set("Content-Type", "text/event-stream")
89 | w.Header().Set("Cache-Control", "no-cache")
90 | w.Header().Set("Connection", "keep-alive")
91 | w.Header().Set("Access-Control-Allow-Origin", "*")
92 | flusher.Flush()
93 | time.Sleep(2 * fb.watchHeartbeat)
94 | }))
95 | defer server.Close()
96 |
97 | notifications := make(chan Event)
98 | fb = New(server.URL, nil)
99 | fb.watchHeartbeat = 50 * time.Millisecond
100 |
101 | if err := fb.Watch(notifications); err != nil {
102 | t.Fatal(err)
103 | }
104 |
105 | event, ok := <-notifications
106 | require.True(t, ok, "notifications closed")
107 | assert.Equal(t, EventTypeError, event.Type, "event type doesn't match")
108 | assert.Empty(t, event.Path, "event path is not empty")
109 | assert.NotNil(t, event.Data, "event data is nil")
110 | assert.Implements(t, new(error), event.Data)
111 | t.Logf("%#v\n", event)
112 |
113 | _, ok = <-notifications
114 | require.False(t, ok, "notifications still open")
115 | }
116 |
117 | func TestWatchError(t *testing.T) {
118 | t.Parallel()
119 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
120 | flusher, ok := w.(http.Flusher)
121 | require.True(t, ok, "streaming unsupported")
122 |
123 | w.Header().Set("Content-Type", "text/event-stream")
124 | w.Header().Set("Cache-Control", "no-cache")
125 | w.Header().Set("Connection", "keep-alive")
126 | w.Header().Set("Access-Control-Allow-Origin", "*")
127 | flusher.Flush()
128 | }))
129 |
130 | var (
131 | notifications = make(chan Event)
132 | fb = New(server.URL, nil)
133 | )
134 | defer server.Close()
135 |
136 | if err := fb.Watch(notifications); err != nil {
137 | t.Fatal(err)
138 | }
139 |
140 | go server.Close()
141 | event, ok := <-notifications
142 | require.True(t, ok, "notifications closed")
143 | assert.Equal(t, EventTypeError, event.Type, "event type doesn't match")
144 | assert.Empty(t, event.Path, "event path is not empty")
145 | assert.NotNil(t, event.Data, "event data is nil")
146 | assert.Implements(t, new(error), event.Data)
147 | }
148 |
149 | func TestWatchAuthRevoked(t *testing.T) {
150 | t.Parallel()
151 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
152 | flusher, ok := w.(http.Flusher)
153 | require.True(t, ok, "streaming unsupported")
154 |
155 | w.Header().Set("Content-Type", "text/event-stream")
156 | w.Header().Set("Cache-Control", "no-cache")
157 | w.Header().Set("Connection", "keep-alive")
158 | w.Header().Set("Access-Control-Allow-Origin", "*")
159 | flusher.Flush()
160 | fmt.Fprintf(w, "event: %s\ndata: %q\n\n", EventTypeAuthRevoked, "token expired")
161 | }))
162 | defer server.Close()
163 |
164 | var (
165 | notifications = make(chan Event)
166 | fb = New(server.URL, nil)
167 | )
168 |
169 | if err := fb.Watch(notifications); err != nil {
170 | t.Fatal(err)
171 | }
172 |
173 | event, ok := <-notifications
174 | require.True(t, ok, "notifications closed")
175 | assert.Equal(t, EventTypeAuthRevoked, event.Type, "event type doesn't match")
176 | assert.Empty(t, event.Path, "event path is not empty")
177 | assert.Equal(t, event.Data, `"token expired"`, "event data does not match")
178 | }
179 |
180 | func TestWatch_Issue66(t *testing.T) {
181 | t.Parallel()
182 |
183 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
184 | flusher, ok := w.(http.Flusher)
185 | require.True(t, ok, "streaming unsupported")
186 |
187 | w.Header().Set("Content-Type", "text/event-stream")
188 | w.Header().Set("Cache-Control", "no-cache")
189 | w.Header().Set("Connection", "keep-alive")
190 | w.Header().Set("Access-Control-Allow-Origin", "*")
191 | flusher.Flush()
192 | }))
193 | defer server.Close()
194 |
195 | // create an initial sse connection
196 | fb := New(server.URL, nil)
197 | notifications := make(chan Event)
198 | err := fb.Watch(notifications)
199 | require.NoError(t, err)
200 |
201 | // read the first connection
202 | <-notifications
203 |
204 | // close the server connection and read the error event
205 | go server.Close()
206 | <-notifications
207 |
208 | // call stop watching - everything should be a-ok
209 | fb.StopWatching()
210 |
211 | _, ok := <-notifications
212 | assert.False(t, ok)
213 | }
214 |
215 | func TestStopWatch(t *testing.T) {
216 | t.Parallel()
217 |
218 | server := firetest.New()
219 | server.Start()
220 | defer server.Close()
221 |
222 | fb := New(server.URL, nil)
223 |
224 | notifications := make(chan Event)
225 | err := fb.Watch(notifications)
226 | assert.NoError(t, err)
227 |
228 | <-notifications // get initial notification
229 | fb.StopWatching()
230 | _, ok := <-notifications
231 | assert.False(t, ok, "notifications should be closed")
232 | }
233 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/translations/README_pt_br.md:
--------------------------------------------------------------------------------
1 | # Negroni [](http://godoc.org/github.com/codegangsta/negroni) [](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
2 |
3 | Negroni é uma abordagem idiomática para middleware web em Go. É pequeno, não intrusivo, e incentiva uso da biblioteca `net/http`.
4 |
5 | Se gosta da idéia do [Martini](http://github.com/go-martini/martini), mas acha que contém muita mágica, então Negroni é ideal.
6 |
7 | ## Começando
8 |
9 | Depois de instalar Go e definir seu [GOPATH](http://golang.org/doc/code.html#GOPATH), criar seu primeirto arquivo `.go`. Iremos chamá-lo `server.go`.
10 |
11 | ~~~ go
12 | package main
13 |
14 | import (
15 | "github.com/codegangsta/negroni"
16 | "net/http"
17 | "fmt"
18 | )
19 |
20 | func main() {
21 | mux := http.NewServeMux()
22 | mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
23 | fmt.Fprintf(w, "Welcome to the home page!")
24 | })
25 |
26 | n := negroni.Classic()
27 | n.UseHandler(mux)
28 | n.Run(":3000")
29 | }
30 | ~~~
31 |
32 | Depois instale o pacote Negroni (**go 1.1** ou superior)
33 | ~~~
34 | go get github.com/codegangsta/negroni
35 | ~~~
36 |
37 | Depois execute seu servidor:
38 | ~~~
39 | go run server.go
40 | ~~~
41 |
42 | Agora terá um servidor web Go net/http rodando em `localhost:3000`.
43 |
44 | ## Precisa de Ajuda?
45 | Se você tem uma pergunta ou pedido de recurso,[go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). O Github issues para o Negroni será usado exclusivamente para Reportar bugs e pull requests.
46 |
47 | ## Negroni é um Framework?
48 | Negroni **não** é a framework. É uma biblioteca que é desenhada para trabalhar diretamente com net/http.
49 |
50 | ## Roteamento?
51 | Negroni é TSPR(Traga seu próprio Roteamento). A comunidade Go já tem um grande número de roteadores http disponíveis, Negroni tenta rodar bem com todos eles pelo suporte total `net/http`/ Por exemplo, a integração com [Gorilla Mux](http://github.com/gorilla/mux) se parece com isso:
52 |
53 | ~~~ go
54 | router := mux.NewRouter()
55 | router.HandleFunc("/", HomeHandler)
56 |
57 | n := negroni.New(Middleware1, Middleware2)
58 | // Or use a middleware with the Use() function
59 | n.Use(Middleware3)
60 | // router goes last
61 | n.UseHandler(router)
62 |
63 | n.Run(":3000")
64 | ~~~
65 |
66 | ## `negroni.Classic()`
67 | `negroni.Classic()` fornece alguns middlewares padrão que são úteis para maioria das aplicações:
68 |
69 | * `negroni.Recovery` - Panic Recovery Middleware.
70 | * `negroni.Logging` - Request/Response Logging Middleware.
71 | * `negroni.Static` - Static File serving under the "public" directory.
72 |
73 | Isso torna muito fácil começar com alguns recursos úteis do Negroni.
74 |
75 | ## Handlers
76 | Negroni fornece um middleware de fluxo bidirecional. Isso é feito através da interface `negroni.Handler`:
77 |
78 | ~~~ go
79 | type Handler interface {
80 | ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
81 | }
82 | ~~~
83 |
84 | Se um middleware não tenha escrito o ResponseWriter, ele deve chamar a próxima `http.HandlerFunc` na cadeia para produzir o próximo handler middleware. Isso pode ser usado muito bem:
85 |
86 | ~~~ go
87 | func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
88 | // do some stuff before
89 | next(rw, r)
90 | // do some stuff after
91 | }
92 | ~~~
93 |
94 | E pode mapear isso para a cadeia de handler com a função `Use`:
95 |
96 | ~~~ go
97 | n := negroni.New()
98 | n.Use(negroni.HandlerFunc(MyMiddleware))
99 | ~~~
100 |
101 | Você também pode mapear `http.Handler` antigos:
102 |
103 | ~~~ go
104 | n := negroni.New()
105 |
106 | mux := http.NewServeMux()
107 | // map your routes
108 |
109 | n.UseHandler(mux)
110 |
111 | n.Run(":3000")
112 | ~~~
113 |
114 | ## `Run()`
115 | Negroni tem uma função de conveniência chamada `Run`. `Run` pega um endereço de string idêntico para [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe).
116 |
117 | ~~~ go
118 | n := negroni.Classic()
119 | // ...
120 | log.Fatal(http.ListenAndServe(":8080", n))
121 | ~~~
122 |
123 | ## Middleware para Rotas Específicas
124 | Se você tem um grupo de rota com rotas que precisam ser executadas por um middleware específico, pode simplesmente criar uma nova instância de Negroni e usar no seu Manipulador de rota.
125 |
126 | ~~~ go
127 | router := mux.NewRouter()
128 | adminRoutes := mux.NewRouter()
129 | // add admin routes here
130 |
131 | // Criar um middleware negroni para admin
132 | router.Handle("/admin", negroni.New(
133 | Middleware1,
134 | Middleware2,
135 | negroni.Wrap(adminRoutes),
136 | ))
137 | ~~~
138 |
139 | ## Middleware de Terceiros
140 |
141 | Aqui está uma lista atual de Middleware Compatíveis com Negroni. Sinta se livre para mandar um PR vinculando seu middleware se construiu um:
142 |
143 |
144 | | Middleware | Autor | Descrição |
145 | | -----------|--------|-------------|
146 | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
147 | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Implementa rapidamente itens de segurança.|
148 | | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Handler para mapeamento/validação de um request a estrutura. |
149 | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger |
150 | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Pacote para renderizar JSON, XML, e templates HTML. |
151 | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
152 | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | Handler para adicionar compreção gzip para as requisições |
153 | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | Handler que prove sistema de login OAuth 2.0 para aplicações Martini. Google Sign-in, Facebook Connect e Github login são suportados. |
154 | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Handler que provê o serviço de sessão. |
155 | | [permissions](https://github.com/xyproto/permissions) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, usuários e permissões. |
156 | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Pacote para gerar TinySVG, HTML e CSS em tempo real. |
157 |
158 | ## Exemplos
159 | [Alexander Rødseth](https://github.com/xyproto) criou [mooseware](https://github.com/xyproto/mooseware), uma estrutura para escrever um handler middleware Negroni.
160 |
161 | ## Servidor com autoreload?
162 | [gin](https://github.com/codegangsta/gin) e [fresh](https://github.com/pilu/fresh) são aplicativos para autoreload do Negroni.
163 |
164 | ## Leitura Essencial para Iniciantes em Go & Negroni
165 | * [Usando um contexto para passar informação de um middleware para o manipulador final](http://elithrar.github.io/article/map-string-interface/)
166 | * [Entendendo middleware](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
167 |
168 |
169 | ## Sobre
170 | Negroni é obsessivamente desenhado por ninguém menos que [Code Gangsta](http://codegangsta.io/)
171 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/query_test.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestShallow(t *testing.T) {
11 | t.Parallel()
12 | var (
13 | server = newTestServer("")
14 | fb = New(server.URL, nil)
15 | )
16 | defer server.Close()
17 |
18 | fb.Shallow(true)
19 | fb.Value("")
20 | require.Len(t, server.receivedReqs, 1)
21 |
22 | req := server.receivedReqs[0]
23 | assert.Equal(t, shallowParam+"=true", req.URL.Query().Encode())
24 |
25 | fb.Shallow(false)
26 | fb.Value("")
27 | require.Len(t, server.receivedReqs, 2)
28 |
29 | req = server.receivedReqs[1]
30 | assert.Equal(t, "", req.URL.Query().Encode())
31 | }
32 |
33 | func TestOrderBy(t *testing.T) {
34 | t.Parallel()
35 | var (
36 | server = newTestServer("")
37 | fb = New(server.URL, nil)
38 | )
39 | defer server.Close()
40 |
41 | fb.OrderBy("user_id").Value("")
42 | require.Len(t, server.receivedReqs, 1)
43 |
44 | req := server.receivedReqs[0]
45 | assert.Equal(t, orderByParam+"=%22user_id%22", req.URL.Query().Encode())
46 | }
47 |
48 | func TestEqualTo(t *testing.T) {
49 | t.Parallel()
50 | var (
51 | server = newTestServer("")
52 | fb = New(server.URL, nil)
53 | )
54 | defer server.Close()
55 |
56 | fb.EqualTo("user_id").Value("")
57 | require.Len(t, server.receivedReqs, 1)
58 |
59 | req := server.receivedReqs[0]
60 | assert.Equal(t, equalToParam+"=%22user_id%22", req.URL.Query().Encode())
61 | }
62 |
63 | func TestEqualToValue(t *testing.T) {
64 | t.Parallel()
65 | var (
66 | server = newTestServer("")
67 | fb = New(server.URL, nil)
68 | )
69 | defer server.Close()
70 |
71 | fb.EqualToValue(2).Value("")
72 | fb.EqualToValue("2").Value("")
73 | fb.EqualToValue(2.14).Value("")
74 | fb.EqualToValue("bar").Value("")
75 | require.Len(t, server.receivedReqs, 4)
76 |
77 | req := server.receivedReqs[0]
78 | assert.Equal(t, equalToParam+"=2", req.URL.Query().Encode())
79 |
80 | req = server.receivedReqs[1]
81 | assert.Equal(t, equalToParam+"=%222%22", req.URL.Query().Encode())
82 |
83 | req = server.receivedReqs[2]
84 | assert.Equal(t, equalToParam+"=2.14", req.URL.Query().Encode())
85 |
86 | req = server.receivedReqs[3]
87 | assert.Equal(t, equalToParam+"=%22bar%22", req.URL.Query().Encode())
88 |
89 | }
90 |
91 | func TestLimitToFirst(t *testing.T) {
92 | t.Parallel()
93 | var (
94 | server = newTestServer("")
95 | fb = New(server.URL, nil)
96 | )
97 | defer server.Close()
98 |
99 | fb.LimitToFirst(2).Value("")
100 | require.Len(t, server.receivedReqs, 1)
101 |
102 | req := server.receivedReqs[0]
103 | assert.Equal(t, limitToFirstParam+"=2", req.URL.Query().Encode())
104 | }
105 |
106 | func TestLimitToLast(t *testing.T) {
107 | t.Parallel()
108 | var (
109 | server = newTestServer("")
110 | fb = New(server.URL, nil)
111 | )
112 | defer server.Close()
113 |
114 | fb.LimitToLast(2).Value("")
115 | require.Len(t, server.receivedReqs, 1)
116 |
117 | req := server.receivedReqs[0]
118 | assert.Equal(t, limitToLastParam+"=2", req.URL.Query().Encode())
119 | }
120 |
121 | func TestStartAt(t *testing.T) {
122 | t.Parallel()
123 | var (
124 | server = newTestServer("")
125 | fb = New(server.URL, nil)
126 | )
127 | defer server.Close()
128 |
129 | fb.StartAt("3").Value("")
130 | fb.StartAt("foo").Value("")
131 | require.Len(t, server.receivedReqs, 2)
132 |
133 | req := server.receivedReqs[0]
134 | assert.Equal(t, startAtParam+"=3", req.URL.Query().Encode())
135 |
136 | req = server.receivedReqs[1]
137 | assert.Equal(t, startAtParam+"=%22foo%22", req.URL.Query().Encode())
138 | }
139 |
140 | func TestStartAtValue(t *testing.T) {
141 | t.Parallel()
142 | var (
143 | server = newTestServer("")
144 | fb = New(server.URL, nil)
145 | )
146 | defer server.Close()
147 |
148 | fb.StartAtValue(3).Value("")
149 | fb.StartAtValue("3").Value("")
150 | fb.StartAtValue(3.14).Value("")
151 | fb.StartAtValue("foo").Value("")
152 | require.Len(t, server.receivedReqs, 4)
153 |
154 | req := server.receivedReqs[0]
155 | assert.Equal(t, startAtParam+"=3", req.URL.Query().Encode())
156 |
157 | req = server.receivedReqs[1]
158 | assert.Equal(t, startAtParam+"=%223%22", req.URL.Query().Encode())
159 |
160 | req = server.receivedReqs[2]
161 | assert.Equal(t, startAtParam+"=3.14", req.URL.Query().Encode())
162 |
163 | req = server.receivedReqs[3]
164 | assert.Equal(t, startAtParam+"=%22foo%22", req.URL.Query().Encode())
165 | }
166 |
167 | func TestEndAt(t *testing.T) {
168 | t.Parallel()
169 | var (
170 | server = newTestServer("")
171 | fb = New(server.URL, nil)
172 | )
173 | defer server.Close()
174 |
175 | fb.EndAt("4").Value("")
176 | fb.EndAt("theend").Value("")
177 | require.Len(t, server.receivedReqs, 2)
178 |
179 | req := server.receivedReqs[0]
180 | assert.Equal(t, endAtParam+"=4", req.URL.Query().Encode())
181 |
182 | req = server.receivedReqs[1]
183 | assert.Equal(t, endAtParam+"=%22theend%22", req.URL.Query().Encode())
184 | }
185 |
186 | func TestEndAtValue(t *testing.T) {
187 | t.Parallel()
188 | var (
189 | server = newTestServer("")
190 | fb = New(server.URL, nil)
191 | )
192 | defer server.Close()
193 |
194 | fb.EndAtValue(4).Value("")
195 | fb.EndAtValue(3.14).Value("")
196 | fb.EndAtValue("4").Value("")
197 | fb.EndAtValue("theend").Value("")
198 | require.Len(t, server.receivedReqs, 4)
199 |
200 | req := server.receivedReqs[0]
201 | assert.Equal(t, endAtParam+"=4", req.URL.Query().Encode())
202 |
203 | req = server.receivedReqs[1]
204 | assert.Equal(t, endAtParam+"=3.14", req.URL.Query().Encode())
205 |
206 | req = server.receivedReqs[2]
207 | assert.Equal(t, endAtParam+"=%224%22", req.URL.Query().Encode())
208 |
209 | req = server.receivedReqs[3]
210 | assert.Equal(t, endAtParam+"=%22theend%22", req.URL.Query().Encode())
211 | }
212 |
213 | func TestIncludePriority(t *testing.T) {
214 | t.Parallel()
215 | var (
216 | server = newTestServer("")
217 | fb = New(server.URL, nil)
218 | )
219 | defer server.Close()
220 |
221 | fb.IncludePriority(true)
222 | fb.Value("")
223 | require.Len(t, server.receivedReqs, 1)
224 |
225 | req := server.receivedReqs[0]
226 | assert.Equal(t, formatParam+"="+formatVal, req.URL.Query().Encode())
227 |
228 | fb.IncludePriority(false)
229 | fb.Value("")
230 | require.Len(t, server.receivedReqs, 2)
231 |
232 | req = server.receivedReqs[1]
233 | assert.Equal(t, "", req.URL.Query().Encode())
234 | }
235 |
236 | func TestQueryMultipleParams(t *testing.T) {
237 | t.Parallel()
238 | var (
239 | server = newTestServer("")
240 | fb = New(server.URL, nil)
241 | )
242 | defer server.Close()
243 |
244 | fb.OrderBy("user_id").StartAt("7").Value("")
245 | require.Len(t, server.receivedReqs, 1)
246 |
247 | req := server.receivedReqs[0]
248 | assert.Equal(t, orderByParam+"=%22user_id%22&startAt=7", req.URL.Query().Encode())
249 | }
250 |
251 | func TestEscapeString(t *testing.T) {
252 | t.Parallel()
253 |
254 | testCases := []struct {
255 | value string
256 | expected string
257 | }{
258 | {"foo", `"foo"`},
259 | {"2", `2`},
260 | {"false", `false`},
261 | }
262 | for _, testCase := range testCases {
263 | assert.Equal(t, testCase.expected, escapeString(testCase.value))
264 | }
265 | }
266 |
267 | func TestEscapeParameter(t *testing.T) {
268 | t.Parallel()
269 |
270 | testCases := []struct {
271 | value interface{}
272 | expected string
273 | }{
274 | {"foo", `"foo"`},
275 | {2, `2`},
276 | {"3", `"3"`},
277 | {true, `true`},
278 | {"false", `"false"`},
279 | {3.14, `3.14`},
280 | }
281 | for _, testCase := range testCases {
282 | assert.Equal(t, testCase.expected, escapeParameter(testCase.value))
283 | }
284 | }
285 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/query.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | // StartAt creates a new Firebase reference with the
10 | // requested StartAt configuration. The value that is passed in
11 | // is automatically escaped if it is a string value.
12 | // Numeric strings are automatically converted to numbers.
13 | //
14 | // StartAt(7) // -> startAt=7
15 | // StartAt("7") // -> startAt=7
16 | // StartAt("foo") // -> startAt="foo"
17 | // StartAt(`"foo"`) // -> startAt="foo"
18 | //
19 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
20 | func (fb *Firebase) StartAt(value string) *Firebase {
21 | c := fb.copy()
22 | if value != "" {
23 | c.params.Set(startAtParam, escapeString(value))
24 | } else {
25 | c.params.Del(startAtParam)
26 | }
27 | return c
28 | }
29 |
30 | // StartAtValue creates a new Firebase reference with the
31 | // requested StartAt configuration. The value that is passed in
32 | // is automatically escaped if it is a string value.
33 | // Numeric strings are preserved as strings.
34 | //
35 | // StartAtValue(7) // -> startAt=7
36 | // StartAtValue("7") // -> startAt="7"
37 | // StartAtValue("foo") // -> startAt="foo"
38 | // StartAtValue(`"foo"`) // -> startAt="foo"
39 | //
40 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
41 | func (fb *Firebase) StartAtValue(value interface{}) *Firebase {
42 | c := fb.copy()
43 | if value != "" {
44 | c.params.Set(startAtParam, escapeParameter(value))
45 | } else {
46 | c.params.Del(startAtParam)
47 | }
48 | return c
49 | }
50 |
51 | // EndAt creates a new Firebase reference with the
52 | // requested EndAt configuration. The value that is passed in
53 | // is automatically escaped if it is a string value.
54 | // Numeric strings are automatically converted to numbers.
55 | //
56 | // EndAt(7) // -> endAt=7
57 | // EndAt("7") // -> endAt=7
58 | // EndAt("foo") // -> endAt="foo"
59 | // EndAt(`"foo"`) // -> endAt="foo"
60 | //
61 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
62 | func (fb *Firebase) EndAt(value string) *Firebase {
63 | c := fb.copy()
64 | if value != "" {
65 | c.params.Set(endAtParam, escapeString(value))
66 | } else {
67 | c.params.Del(endAtParam)
68 | }
69 | return c
70 | }
71 |
72 | // EndAtValue creates a new Firebase reference with the
73 | // requested EndAt configuration. The value that is passed in
74 | // is automatically escaped if it is a string value.
75 | // Numeric strings are preserved as strings.
76 | //
77 | // EndAtValue(7) // -> endAt=7
78 | // EndAtValue("7") // -> endAt="7"
79 | // EndAtValue("foo") // -> endAt="foo"
80 | // EndAtValue(`"foo"`) // -> endAt="foo"
81 | //
82 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
83 | func (fb *Firebase) EndAtValue(value interface{}) *Firebase {
84 | c := fb.copy()
85 | if value != "" {
86 | c.params.Set(endAtParam, escapeParameter(value))
87 | } else {
88 | c.params.Del(endAtParam)
89 | }
90 | return c
91 | }
92 |
93 | // OrderBy creates a new Firebase reference with the
94 | // requested OrderBy configuration. The value that is passed in
95 | // is automatically escaped if it is a string value.
96 | //
97 | // OrderBy("foo") // -> orderBy="foo"
98 | // OrderBy(`"foo"`) // -> orderBy="foo"
99 | // OrderBy("$key") // -> orderBy="$key"
100 | //
101 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#orderby
102 | func (fb *Firebase) OrderBy(value string) *Firebase {
103 | c := fb.copy()
104 | if value != "" {
105 | c.params.Set(orderByParam, escapeString(value))
106 | } else {
107 | c.params.Del(orderByParam)
108 | }
109 | return c
110 | }
111 |
112 | // EqualTo sends the query string equalTo so that one can find nodes with
113 | // exactly matching values. The value that is passed in is automatically escaped
114 | // if it is a string value.
115 | // Numeric strings are automatically converted to numbers.
116 | //
117 | // EqualTo(7) // -> equalTo=7
118 | // EqualTo("7") // -> equalTo=7
119 | // EqualTo("foo") // -> equalTo="foo"
120 | // EqualTo(`"foo"`) // -> equalTo="foo"
121 | //
122 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
123 | func (fb *Firebase) EqualTo(value string) *Firebase {
124 | c := fb.copy()
125 | if value != "" {
126 | c.params.Set(equalToParam, escapeString(value))
127 | } else {
128 | c.params.Del(equalToParam)
129 | }
130 | return c
131 | }
132 |
133 | // EqualToValue sends the query string equalTo so that one can find nodes with
134 | // exactly matching values. The value that is passed in is automatically escaped
135 | // if it is a string value.
136 | // Numeric strings are preserved as strings.
137 | //
138 | // EqualToValue(7) // -> equalTo=7
139 | // EqualToValue("7") // -> equalTo="7"
140 | // EqualToValue("foo") // -> equalTo="foo"
141 | // EqualToValue(`"foo"`) // -> equalTo="foo"
142 | //
143 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
144 | func (fb *Firebase) EqualToValue(value interface{}) *Firebase {
145 | c := fb.copy()
146 | if value != "" {
147 | c.params.Set(equalToParam, escapeParameter(value))
148 | } else {
149 | c.params.Del(equalToParam)
150 | }
151 | return c
152 | }
153 |
154 | func escapeString(s string) string {
155 | _, errNotInt := strconv.ParseInt(s, 10, 64)
156 | _, errNotBool := strconv.ParseBool(s)
157 | if errNotInt == nil || errNotBool == nil {
158 | // we shouldn't escape bools or ints
159 | return s
160 | }
161 | return fmt.Sprintf(`%q`, strings.Trim(s, `"`))
162 | }
163 |
164 | func escapeParameter(s interface{}) string {
165 | switch s.(type) {
166 | case string:
167 | return fmt.Sprintf(`%q`, strings.Trim(s.(string), `"`))
168 | default:
169 | return fmt.Sprintf(`%v`, s)
170 | }
171 | }
172 |
173 | // LimitToFirst creates a new Firebase reference with the
174 | // requested limitToFirst configuration.
175 | //
176 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#limit-queries
177 | func (fb *Firebase) LimitToFirst(value int64) *Firebase {
178 | c := fb.copy()
179 | if value > 0 {
180 | c.params.Set(limitToFirstParam, strconv.FormatInt(value, 10))
181 | } else {
182 | c.params.Del(limitToFirstParam)
183 | }
184 | return c
185 | }
186 |
187 | // LimitToLast creates a new Firebase reference with the
188 | // requested limitToLast configuration.
189 | //
190 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#limit-queries
191 | func (fb *Firebase) LimitToLast(value int64) *Firebase {
192 | c := fb.copy()
193 | if value > 0 {
194 | c.params.Set(limitToLastParam, strconv.FormatInt(value, 10))
195 | } else {
196 | c.params.Del(limitToLastParam)
197 | }
198 | return c
199 | }
200 |
201 | // Shallow limits the depth of the data returned when calling Value.
202 | // If the data at the location is a JSON primitive (string, number or boolean),
203 | // its value will be returned. If the data is a JSON object, the values
204 | // for each key will be truncated to true.
205 | //
206 | // Reference https://firebase.google.com/docs/database/rest/retrieve-data#shallow
207 | func (fb *Firebase) Shallow(v bool) {
208 | if v {
209 | fb.params.Set(shallowParam, "true")
210 | } else {
211 | fb.params.Del(shallowParam)
212 | }
213 | }
214 |
215 | // IncludePriority determines whether or not to ask Firebase
216 | // for the values priority. By default, the priority is not returned.
217 | //
218 | // Reference https://www.firebase.com/docs/rest/api/#section-param-format
219 | func (fb *Firebase) IncludePriority(v bool) {
220 | if v {
221 | fb.params.Set(formatParam, formatVal)
222 | } else {
223 | fb.params.Del(formatParam)
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/sync/node_test.go:
--------------------------------------------------------------------------------
1 | package sync
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "testing"
8 |
9 | "github.com/stretchr/testify/assert"
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | func newTestNodeWithKids(children map[string]*Node) *Node {
14 | n := &Node{}
15 | for _, child := range children {
16 | child.Parent = n
17 | }
18 | n.Children = children
19 | return n
20 | }
21 |
22 | func equalNodes(expected, actual *Node) error {
23 | if ec, ac := len(expected.Children), len(actual.Children); ec != ac {
24 | return fmt.Errorf("Children count is not the same\n\tExpected: %d\n\tActual: %d", ec, ac)
25 | }
26 |
27 | if len(expected.Children) == 0 {
28 | if !assert.ObjectsAreEqualValues(expected.Value, actual.Value) {
29 | return fmt.Errorf("Node values not equal\n\tExpected: %T %v\n\tActual: %T %v", expected.Value, expected.Value, actual.Value, actual.Value)
30 | }
31 | return nil
32 | }
33 |
34 | for child, n := range expected.Children {
35 | n2, ok := actual.Children[child]
36 | if !ok {
37 | return fmt.Errorf("Expected node to have child: %s", child)
38 | }
39 |
40 | err := equalNodes(n, n2)
41 | if err != nil {
42 | return err
43 | }
44 | }
45 | return nil
46 | }
47 |
48 | func TestNewNode(t *testing.T) {
49 |
50 | for _, test := range []struct {
51 | name string
52 | node *Node
53 | }{
54 | {
55 | name: "scalars/string",
56 | node: NewNode("", "foo"),
57 | },
58 | {
59 | name: "scalars/number",
60 | node: NewNode("", 2),
61 | },
62 | {
63 | name: "scalars/decimal",
64 | node: NewNode("", 2.2),
65 | },
66 | {
67 | name: "scalars/boolean",
68 | node: NewNode("", false),
69 | },
70 | {
71 | name: "arrays/strings",
72 | node: NewNode("", []interface{}{"foo", "bar"}),
73 | },
74 | {
75 | name: "arrays/booleans",
76 | node: NewNode("", []interface{}{true, false}),
77 | },
78 | {
79 | name: "arrays/numbers",
80 | node: NewNode("", []interface{}{1, 2, 3}),
81 | },
82 | {
83 | name: "arrays/decimals",
84 | node: NewNode("", []interface{}{1.1, 2.2, 3.3}),
85 | },
86 | {
87 | name: "objects/simple",
88 | node: newTestNodeWithKids(map[string]*Node{
89 | "foo": NewNode("", "bar"),
90 | }),
91 | },
92 | {
93 | name: "objects/complex",
94 | node: newTestNodeWithKids(map[string]*Node{
95 | "foo": NewNode("", "bar"),
96 | "foo1": NewNode("", 2),
97 | "foo2": NewNode("", true),
98 | "foo3": NewNode("", 3.42),
99 | }),
100 | },
101 | {
102 | name: "objects/nested",
103 | node: newTestNodeWithKids(map[string]*Node{
104 | "dinosaurs": newTestNodeWithKids(map[string]*Node{
105 | "bruhathkayosaurus": newTestNodeWithKids(map[string]*Node{
106 | "appeared": NewNode("", -70000000),
107 | "height": NewNode("", 25),
108 | "length": NewNode("", 44),
109 | "order": NewNode("", "saurischia"),
110 | "vanished": NewNode("", -70000000),
111 | "weight": NewNode("", 135000),
112 | }),
113 | "lambeosaurus": newTestNodeWithKids(map[string]*Node{
114 | "appeared": NewNode("", -76000000),
115 | "height": NewNode("", 2.1),
116 | "length": NewNode("", 12.5),
117 | "order": NewNode("", "ornithischia"),
118 | "vanished": NewNode("", -75000000),
119 | "weight": NewNode("", 5000),
120 | }),
121 | }),
122 | "scores": newTestNodeWithKids(map[string]*Node{
123 | "bruhathkayosaurus": NewNode("", 55),
124 | "lambeosaurus": NewNode("", 21),
125 | }),
126 | }),
127 | },
128 | {
129 | name: "objects/with_arrays",
130 | node: newTestNodeWithKids(map[string]*Node{
131 | "regular": NewNode("", "item"),
132 | "booleans": NewNode("", []interface{}{false, true}),
133 | "numbers": NewNode("", []interface{}{1, 2}),
134 | "decimals": NewNode("", []interface{}{1.1, 2.2}),
135 | "strings": NewNode("", []interface{}{"foo", "bar"}),
136 | }),
137 | },
138 | } {
139 | data, err := ioutil.ReadFile("fixtures/" + test.name + ".json")
140 | require.NoError(t, err, test.name)
141 |
142 | var v interface{}
143 | require.NoError(t, json.Unmarshal(data, &v), test.name)
144 |
145 | n := NewNode("", v)
146 | assert.NoError(t, equalNodes(test.node, n), test.name)
147 | }
148 | }
149 |
150 | func TestObjectify(t *testing.T) {
151 | for _, test := range []struct {
152 | name string
153 | object interface{}
154 | }{
155 | {
156 | name: "nil",
157 | },
158 | {
159 | name: "string",
160 | object: "foo",
161 | },
162 | {
163 | name: "number",
164 | object: 2,
165 | },
166 | {
167 | name: "decimal",
168 | object: 2.2,
169 | },
170 | {
171 | name: "boolean",
172 | object: false,
173 | },
174 | {
175 | name: "arrays",
176 | object: []interface{}{"foo", 2, 2.2, false},
177 | },
178 | {
179 | name: "object",
180 | object: map[string]interface{}{
181 | "one_fish": "two_fish",
182 | "red_fish": 2.2,
183 | "netflix_list": []interface{}{"Orange is the New Black", "House of Cards"},
184 | "shopping_list": map[string]interface{}{
185 | "publix": "milk",
186 | "walmart": "reese's pieces",
187 | },
188 | },
189 | },
190 | } {
191 | node := NewNode("", test.object)
192 | assert.Equal(t, test.object, node.Objectify())
193 | }
194 | }
195 |
196 | func TestChild(t *testing.T) {
197 | node := NewNode("", map[string]interface{}{
198 | "one": map[string]interface{}{
199 | "two": map[string]interface{}{
200 | "three": true,
201 | },
202 | },
203 | })
204 |
205 | one, ok := node.Child("one")
206 | require.True(t, ok)
207 | require.NotNil(t, one)
208 |
209 | two, ok := one.Child("two")
210 | require.True(t, ok)
211 | require.NotNil(t, two)
212 |
213 | three, ok := two.Child("three")
214 | require.True(t, ok)
215 | require.NotNil(t, three)
216 |
217 | threeNested, ok := node.Child("one/two/three")
218 | require.True(t, ok)
219 | assert.Equal(t, three, threeNested)
220 |
221 | one, ok = node.Child("nope")
222 | assert.False(t, ok)
223 | assert.Nil(t, one)
224 | }
225 |
226 | func TestMerge(t *testing.T) {
227 | base := &Node{Children: map[string]*Node{
228 | "foo": NewNode("", "bar"),
229 | "notreplace": NewNode("", "yes"),
230 | }}
231 |
232 | newNode := &Node{Children: map[string]*Node{
233 | "foo": NewNode("", "troll"),
234 | "new": NewNode("", "lala"),
235 | }}
236 |
237 | base.merge(newNode)
238 |
239 | expected := NewNode("", map[string]string{
240 | "foo": "troll",
241 | "notreplace": "yes",
242 | "new": "lala",
243 | })
244 |
245 | err := equalNodes(expected, base)
246 | assert.NoError(t, err)
247 | }
248 |
249 | func TestPrune(t *testing.T) {
250 | /*
251 | Children: 0
252 | Value: Non nil
253 | Parent: nil
254 | */
255 | n := NewNode("", "foo")
256 | assert.Nil(t, n.prune())
257 |
258 | /*
259 | Children: 0
260 | Value: Non nil
261 | Parent: Non nil
262 | */
263 | n = NewNode("", "foo")
264 | n.Parent = NewNode("", 1)
265 | assert.Nil(t, n.prune())
266 |
267 | /*
268 | Children: 0
269 | Value: nil
270 | Parent: Non nil
271 | */
272 | n = &Node{}
273 | parent := newTestNodeWithKids(map[string]*Node{"foo": n})
274 | parentFromPrune := n.prune()
275 |
276 | assert.NotNil(t, parentFromPrune)
277 | assert.Equal(t, parent, parentFromPrune)
278 | assert.Nil(t, n.Parent)
279 | assert.Nil(t, n.Children)
280 |
281 | /*
282 | Children: 1
283 | Value: nil
284 | Parent: Non nil
285 | */
286 | n = newTestNodeWithKids(map[string]*Node{"c1": n})
287 | parent = newTestNodeWithKids(map[string]*Node{"foo": n})
288 | assert.Nil(t, n.prune())
289 |
290 | /*
291 | Children: 1
292 | Value: nil
293 | Parent: nil
294 | */
295 | n = newTestNodeWithKids(map[string]*Node{"c1": n})
296 | assert.Nil(t, n.prune())
297 |
298 | /*
299 | Children: 2
300 | Value: nil
301 | Parent: Non nil
302 | */
303 | n = newTestNodeWithKids(map[string]*Node{
304 | "c1": NewNode("", 1),
305 | "c2": NewNode("", 2),
306 | })
307 | n.Parent = NewNode("", "hello!")
308 | assert.Nil(t, n.prune())
309 | }
310 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/event_callback.go:
--------------------------------------------------------------------------------
1 | package firego
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "sort"
7 | "strings"
8 | "time"
9 |
10 | "github.com/zabawaba99/firego/sync"
11 | )
12 |
13 | // ChildEventFunc is the type of function that is called for every
14 | // new child added under a firebase reference. The snapshot argument
15 | // contains the data that was added. The previousChildKey argument
16 | // contains the key of the previous child that this function was called for.
17 | type ChildEventFunc func(snapshot DataSnapshot, previousChildKey string)
18 |
19 | // ChildAdded listens on the firebase instance and executes the callback
20 | // for every child that is added.
21 | //
22 | // You cannot set the same function twice on a Firebase reference, if you do
23 | // the first function will be overridden and you will not be able to close the
24 | // connection.
25 | func (fb *Firebase) ChildAdded(fn ChildEventFunc) error {
26 | return fb.addEventFunc(fn, fn.childAdded)
27 | }
28 |
29 | func (fn ChildEventFunc) childAdded(db *sync.Database, prevKey *string, notifications chan Event) error {
30 | for event := range notifications {
31 | if event.Type == EventTypeError {
32 | err, ok := event.Data.(error)
33 | if !ok {
34 | err = fmt.Errorf("Got error from event %#v", event)
35 | }
36 | return err
37 | }
38 |
39 | if event.Type != EventTypePut {
40 | continue
41 | }
42 |
43 | child := strings.Split(event.Path[1:], "/")[0]
44 | if event.Data == nil {
45 | db.Del(child)
46 | continue
47 | }
48 |
49 | if _, ok := db.Get("").Child(child); ok {
50 | // if the child isn't being added, forget it
51 | continue
52 | }
53 |
54 | m, ok := event.Data.(map[string]interface{})
55 | if child == "" && ok {
56 | // if we were given a map at the root then we have
57 | // to send an event per child
58 | for _, k := range sortedKeys(m) {
59 | v := m[k]
60 | node := sync.NewNode(k, v)
61 | db.Add(k, node)
62 | fn(newSnapshot(node), *prevKey)
63 | *prevKey = k
64 | }
65 | continue
66 | }
67 |
68 | // we have a single event to process
69 | node := sync.NewNode(child, event.Data)
70 | db.Add(strings.Trim(child, "/"), node)
71 |
72 | fn(newSnapshot(node), *prevKey)
73 | *prevKey = child
74 | }
75 | return nil
76 | }
77 |
78 | // ChildChanged listens on the firebase instance and executes the callback
79 | // for every child that is changed.
80 | //
81 | // You cannot set the same function twice on a Firebase reference, if you do
82 | // the first function will be overridden and you will not be able to close the
83 | // connection.
84 | func (fb *Firebase) ChildChanged(fn ChildEventFunc) error {
85 | return fb.addEventFunc(fn, fn.childChanged)
86 | }
87 |
88 | func (fn ChildEventFunc) childChanged(db *sync.Database, prevKey *string, notifications chan Event) error {
89 | first, ok := <-notifications
90 | if !ok {
91 | return errors.New("channel closed")
92 | }
93 |
94 | db.Add("", sync.NewNode("", first.Data))
95 | for event := range notifications {
96 | if event.Type == EventTypeError {
97 | err, ok := event.Data.(error)
98 | if !ok {
99 | err = fmt.Errorf("Got error from event %#v", event)
100 | }
101 | return err
102 | }
103 |
104 | path := strings.Trim(event.Path, "/")
105 | if event.Data == nil {
106 | db.Del(path)
107 | continue
108 | }
109 |
110 | child := strings.Split(path, "/")[0]
111 | node := sync.NewNode(child, event.Data)
112 |
113 | dbNode := db.Get("")
114 | if _, ok := dbNode.Child(child); child != "" && !ok {
115 | // if the child is new, ignore it.
116 | db.Add(path, node)
117 | continue
118 | }
119 |
120 | if m, ok := event.Data.(map[string]interface{}); child == "" && ok {
121 | // we've got children so send an event per child
122 | for _, k := range sortedKeys(m) {
123 | v := m[k]
124 | node := sync.NewNode(k, v)
125 | newPath := strings.TrimPrefix(child+"/"+k, "/")
126 | if _, ok := dbNode.Child(k); !ok {
127 | db.Add(newPath, node)
128 | continue
129 | }
130 |
131 | db.Update(newPath, node)
132 | fn(newSnapshot(node), *prevKey)
133 | *prevKey = k
134 | }
135 | continue
136 | }
137 |
138 | db.Update(path, node)
139 | fn(newSnapshot(db.Get(child)), *prevKey)
140 | *prevKey = child
141 | }
142 | return nil
143 | }
144 |
145 | // ChildRemoved listens on the firebase instance and executes the callback
146 | // for every child that is deleted.
147 | //
148 | // You cannot set the same function twice on a Firebase reference, if you do
149 | // the first function will be overridden and you will not be able to close the
150 | // connection.
151 | func (fb *Firebase) ChildRemoved(fn ChildEventFunc) error {
152 | return fb.addEventFunc(fn, fn.childRemoved)
153 | }
154 |
155 | func (fn ChildEventFunc) childRemoved(db *sync.Database, prevKey *string, notifications chan Event) error {
156 | first, ok := <-notifications
157 | if !ok {
158 | return errors.New("channel closed")
159 | }
160 |
161 | node := sync.NewNode("", first.Data)
162 | db.Add("", node)
163 |
164 | for event := range notifications {
165 | if event.Type == EventTypeError {
166 | err, ok := event.Data.(error)
167 | if !ok {
168 | err = fmt.Errorf("Got error from event %#v", event)
169 | }
170 | return err
171 | }
172 |
173 | path := strings.Trim(event.Path, "/")
174 | node := sync.NewNode(path, event.Data)
175 |
176 | if event.Type == EventTypePatch {
177 | db.Update(path, node)
178 | continue
179 | }
180 |
181 | if event.Data != nil {
182 | db.Add(path, node)
183 | continue
184 | }
185 |
186 | if path == "" {
187 | // if node that is being listened to is deleted,
188 | // an event should be triggered for every child
189 | children := db.Get("").Children
190 | orderedChildren := make([]string, len(children))
191 | var i int
192 | for k := range children {
193 | orderedChildren[i] = k
194 | i++
195 | }
196 |
197 | sort.Strings(orderedChildren)
198 |
199 | for _, k := range orderedChildren {
200 | node := db.Get(k)
201 | fn(newSnapshot(node), "")
202 | db.Del(k)
203 | }
204 |
205 | db.Del(path)
206 | continue
207 | }
208 |
209 | node = db.Get(path)
210 | fn(newSnapshot(node), "")
211 | db.Del(path)
212 | }
213 | return nil
214 | }
215 |
216 | type handleSSEFunc func(*sync.Database, *string, chan Event) error
217 |
218 | func (fb *Firebase) addEventFunc(fn ChildEventFunc, handleSSE handleSSEFunc) error {
219 | fb.eventMtx.Lock()
220 | defer fb.eventMtx.Unlock()
221 |
222 | stop := make(chan struct{})
223 | key := fmt.Sprintf("%v", fn)
224 | if _, ok := fb.eventFuncs[key]; ok {
225 | return nil
226 | }
227 |
228 | fb.eventFuncs[key] = stop
229 | notifications, err := fb.watch(stop)
230 | if err != nil {
231 | return err
232 | }
233 |
234 | db := sync.NewDB()
235 | prevKey := new(string)
236 | var run func(notifications chan Event, backoff time.Duration)
237 | run = func(notifications chan Event, backoff time.Duration) {
238 | fb.eventMtx.Lock()
239 | if _, ok := fb.eventFuncs[key]; !ok {
240 | fb.eventMtx.Unlock()
241 | // the func has been removed
242 | return
243 | }
244 | fb.eventMtx.Unlock()
245 |
246 | if err := handleSSE(db, prevKey, notifications); err == nil {
247 | // we returned gracefully
248 | return
249 | }
250 |
251 | // give firebase some time
252 | backoff *= 2
253 | time.Sleep(backoff)
254 |
255 | // try and reconnect
256 | for notifications, err = fb.watch(stop); err != nil; time.Sleep(backoff) {
257 | fb.eventMtx.Lock()
258 | if _, ok := fb.eventFuncs[key]; !ok {
259 | fb.eventMtx.Unlock()
260 | // func has been removed
261 | return
262 | }
263 | fb.eventMtx.Unlock()
264 | }
265 |
266 | // give this another shot
267 | run(notifications, backoff)
268 | }
269 |
270 | go run(notifications, fb.watchHeartbeat)
271 | return nil
272 | }
273 |
274 | // RemoveEventFunc removes the given function from the firebase
275 | // reference.
276 | func (fb *Firebase) RemoveEventFunc(fn ChildEventFunc) {
277 | fb.eventMtx.Lock()
278 | defer fb.eventMtx.Unlock()
279 |
280 | key := fmt.Sprintf("%v", fn)
281 | stop, ok := fb.eventFuncs[key]
282 | if !ok {
283 | return
284 | }
285 |
286 | delete(fb.eventFuncs, key)
287 | close(stop)
288 | }
289 |
290 | func sortedKeys(m map[string]interface{}) []string {
291 | orderedKeys := make([]string, len(m))
292 | var i int
293 | for k := range m {
294 | orderedKeys[i] = k
295 | i++
296 | }
297 |
298 | sort.Strings(orderedKeys)
299 | return orderedKeys
300 | }
301 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/firebase.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package firego is a REST client for Firebase (https://firebase.com).
3 | */
4 | package firego
5 |
6 | import (
7 | "bytes"
8 | "encoding/json"
9 | "errors"
10 | "fmt"
11 | "io/ioutil"
12 | "net"
13 | "net/http"
14 | _url "net/url"
15 | "strings"
16 | "sync"
17 | "time"
18 | )
19 |
20 | // TimeoutDuration is the length of time any request will have to establish
21 | // a connection and receive headers from Firebase before returning
22 | // an ErrTimeout error.
23 | var TimeoutDuration = 30 * time.Second
24 |
25 | var defaultRedirectLimit = 30
26 |
27 | // ErrTimeout is an error type is that is returned if a request
28 | // exceeds the TimeoutDuration configured.
29 | type ErrTimeout struct {
30 | error
31 | }
32 |
33 | // query parameter constants
34 | const (
35 | authParam = "auth"
36 | shallowParam = "shallow"
37 | formatParam = "format"
38 | formatVal = "export"
39 | orderByParam = "orderBy"
40 | limitToFirstParam = "limitToFirst"
41 | limitToLastParam = "limitToLast"
42 | startAtParam = "startAt"
43 | endAtParam = "endAt"
44 | equalToParam = "equalTo"
45 | )
46 |
47 | const defaultHeartbeat = 2 * time.Minute
48 |
49 | // Firebase represents a location in the cloud.
50 | type Firebase struct {
51 | url string
52 | params _url.Values
53 | client *http.Client
54 | clientTimeout time.Duration
55 |
56 | eventMtx sync.Mutex
57 | eventFuncs map[string]chan struct{}
58 |
59 | watchMtx sync.Mutex
60 | watching bool
61 | watchHeartbeat time.Duration
62 | stopWatching chan struct{}
63 | }
64 |
65 | // New creates a new Firebase reference,
66 | // if client is nil, http.DefaultClient is used.
67 | func New(url string, client *http.Client) *Firebase {
68 | fb := &Firebase{
69 | url: sanitizeURL(url),
70 | params: _url.Values{},
71 | clientTimeout: TimeoutDuration,
72 | stopWatching: make(chan struct{}),
73 | watchHeartbeat: defaultHeartbeat,
74 | eventFuncs: map[string]chan struct{}{},
75 | }
76 | if client == nil {
77 | var tr *http.Transport
78 | tr = &http.Transport{
79 | Dial: func(network, address string) (net.Conn, error) {
80 | start := time.Now()
81 | c, err := net.DialTimeout(network, address, fb.clientTimeout)
82 | tr.ResponseHeaderTimeout = fb.clientTimeout - time.Since(start)
83 | return c, err
84 | },
85 | }
86 |
87 | client = &http.Client{
88 | Transport: tr,
89 | CheckRedirect: redirectPreserveHeaders,
90 | }
91 | }
92 |
93 | fb.client = client
94 | return fb
95 | }
96 |
97 | // Auth sets the custom Firebase token used to authenticate to Firebase.
98 | func (fb *Firebase) Auth(token string) {
99 | fb.params.Set(authParam, token)
100 | }
101 |
102 | // Unauth removes the current token being used to authenticate to Firebase.
103 | func (fb *Firebase) Unauth() {
104 | fb.params.Del(authParam)
105 | }
106 |
107 | // Ref returns a copy of an existing Firebase reference with a new path.
108 | func (fb *Firebase) Ref(path string) (*Firebase, error) {
109 | newFB := fb.copy()
110 | parsedURL, err := _url.Parse(fb.url)
111 | if err != nil {
112 | return newFB, err
113 | }
114 | newFB.url = parsedURL.Scheme + "://" + parsedURL.Host + "/" + strings.Trim(path, "/")
115 | return newFB, nil
116 | }
117 |
118 | // SetURL changes the url for a firebase reference.
119 | func (fb *Firebase) SetURL(url string) {
120 | fb.url = sanitizeURL(url)
121 | }
122 |
123 | // URL returns firebase reference URL
124 | func (fb *Firebase) URL() string {
125 | return fb.url
126 | }
127 |
128 | // Push creates a reference to an auto-generated child location.
129 | func (fb *Firebase) Push(v interface{}) (*Firebase, error) {
130 | bytes, err := json.Marshal(v)
131 | if err != nil {
132 | return nil, err
133 | }
134 | _, bytes, err = fb.doRequest("POST", bytes)
135 | if err != nil {
136 | return nil, err
137 | }
138 | var m map[string]string
139 | if err := json.Unmarshal(bytes, &m); err != nil {
140 | return nil, err
141 | }
142 | newRef := fb.copy()
143 | newRef.url = fb.url + "/" + m["name"]
144 | return newRef, err
145 | }
146 |
147 | // Remove the Firebase reference from the cloud.
148 | func (fb *Firebase) Remove() error {
149 | _, _, err := fb.doRequest("DELETE", nil)
150 | if err != nil {
151 | return err
152 | }
153 | return nil
154 | }
155 |
156 | // Set the value of the Firebase reference.
157 | func (fb *Firebase) Set(v interface{}) error {
158 | bytes, err := json.Marshal(v)
159 | if err != nil {
160 | return err
161 | }
162 | _, _, err = fb.doRequest("PUT", bytes)
163 | return err
164 | }
165 |
166 | // Update the specific child with the given value.
167 | func (fb *Firebase) Update(v interface{}) error {
168 | bytes, err := json.Marshal(v)
169 | if err != nil {
170 | return err
171 | }
172 | _, _, err = fb.doRequest("PATCH", bytes)
173 | return err
174 | }
175 |
176 | // Value gets the value of the Firebase reference.
177 | func (fb *Firebase) Value(v interface{}) error {
178 | _, bytes, err := fb.doRequest("GET", nil)
179 | if err != nil {
180 | return err
181 | }
182 | return json.Unmarshal(bytes, v)
183 | }
184 |
185 | // String returns the string representation of the
186 | // Firebase reference.
187 | func (fb *Firebase) String() string {
188 | path := fb.url + "/.json"
189 |
190 | if len(fb.params) > 0 {
191 | path += "?" + fb.params.Encode()
192 | }
193 | return path
194 | }
195 |
196 | // Child creates a new Firebase reference for the requested
197 | // child with the same configuration as the parent.
198 | func (fb *Firebase) Child(child string) *Firebase {
199 | c := fb.copy()
200 | c.url = c.url + "/" + child
201 | return c
202 | }
203 |
204 | func (fb *Firebase) copy() *Firebase {
205 | c := &Firebase{
206 | url: fb.url,
207 | params: _url.Values{},
208 | client: fb.client,
209 | clientTimeout: fb.clientTimeout,
210 | stopWatching: make(chan struct{}),
211 | watchHeartbeat: defaultHeartbeat,
212 | eventFuncs: map[string]chan struct{}{},
213 | }
214 |
215 | // making sure to manually copy the map items into a new
216 | // map to avoid modifying the map reference.
217 | for k, v := range fb.params {
218 | c.params[k] = v
219 | }
220 | return c
221 | }
222 |
223 | func sanitizeURL(url string) string {
224 | if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
225 | url = "https://" + url
226 | }
227 |
228 | if strings.HasSuffix(url, "/") {
229 | url = url[:len(url)-1]
230 | }
231 |
232 | return url
233 | }
234 |
235 | // Preserve headers on redirect.
236 | //
237 | // Reference https://github.com/golang/go/issues/4800
238 | func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
239 | if len(via) == 0 {
240 | // No redirects
241 | return nil
242 | }
243 |
244 | if len(via) > defaultRedirectLimit {
245 | return fmt.Errorf("%d consecutive requests(redirects)", len(via))
246 | }
247 |
248 | // mutate the subsequent redirect requests with the first Header
249 | for key, val := range via[0].Header {
250 | req.Header[key] = val
251 | }
252 | return nil
253 | }
254 |
255 | func withHeader(key, value string) func(*http.Request) {
256 | return func(req *http.Request) {
257 | req.Header.Add(key, value)
258 | }
259 | }
260 |
261 | func (fb *Firebase) doRequest(method string, body []byte, options ...func(*http.Request)) (http.Header, []byte, error) {
262 | req, err := http.NewRequest(method, fb.String(), bytes.NewReader(body))
263 | if err != nil {
264 | return nil, nil, err
265 | }
266 |
267 | for _, opt := range options {
268 | opt(req)
269 | }
270 |
271 | resp, err := fb.client.Do(req)
272 | switch err := err.(type) {
273 | default:
274 | return nil, nil, err
275 | case nil:
276 | // carry on
277 |
278 | case *_url.Error:
279 | // `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
280 | // when exceeding it's `Transport`'s `ResponseHeadersTimeout`
281 | e1, ok := err.Err.(net.Error)
282 | if ok && e1.Timeout() {
283 | return nil, nil, ErrTimeout{err}
284 | }
285 |
286 | return nil, nil, err
287 |
288 | case net.Error:
289 | // `http.Client.Do` will return a `net.Error` directly when Dial times
290 | // out, or when the Client's RoundTripper otherwise returns an err
291 | if err.Timeout() {
292 | return nil, nil, ErrTimeout{err}
293 | }
294 |
295 | return nil, nil, err
296 | }
297 |
298 | defer resp.Body.Close()
299 | respBody, err := ioutil.ReadAll(resp.Body)
300 | if err != nil {
301 | return nil, nil, err
302 | }
303 | if resp.StatusCode/200 != 1 {
304 | return resp.Header, respBody, errors.New(string(respBody))
305 | }
306 | return resp.Header, respBody, nil
307 | }
308 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/negroni/translations/README_de_de.md:
--------------------------------------------------------------------------------
1 | # Negroni [](http://godoc.org/github.com/codegangsta/negroni) [](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
2 |
3 | Negroni ist ein Ansatz für eine idiomatische Middleware in Go. Sie ist klein, nicht-intrusiv und unterstützt die Nutzung von `net/http` Handlern.
4 |
5 | Wenn Dir die Idee hinter [Martini](http://github.com/go-martini/martini) gefällt, aber Du denkst, es stecke zu viel Magie darin, dann ist Negroni eine passende Alternative.
6 |
7 | ## Wo fange ich an?
8 |
9 | Nachdem Du Go installiert und den [GOPATH](http://golang.org/doc/code.html#GOPATH) eingerichtet hast, erstelle eine `.go`-Datei. Nennen wir sie `server.go`.
10 |
11 | ~~~ go
12 | package main
13 |
14 | import (
15 | "github.com/codegangsta/negroni"
16 | "net/http"
17 | "fmt"
18 | )
19 |
20 | func main() {
21 | mux := http.NewServeMux()
22 | mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
23 | fmt.Fprintf(w, "Willkommen auf der Homepage!")
24 | })
25 |
26 | n := negroni.Classic()
27 | n.UseHandler(mux)
28 | n.Run(":3000")
29 | }
30 | ~~~
31 |
32 | Installiere nun das Negroni Package (**go 1.1** und höher werden vorausgesetzt):
33 | ~~~
34 | go get github.com/codegangsta/negroni
35 | ~~~
36 |
37 | Dann starte Deinen Server:
38 | ~~~
39 | go run server.go
40 | ~~~
41 |
42 | Nun läuft ein `net/http`-Webserver von Go unter `localhost:3000`.
43 |
44 | ## Hilfe benötigt?
45 | Wenn Du eine Frage hast oder Dir ein bestimmte Funktion wünscht, nutze die [Mailing Liste](https://groups.google.com/forum/#!forum/negroni-users). Issues auf Github werden ausschließlich für Bug Reports und Pull Requests genutzt.
46 |
47 | ## Ist Negroni ein Framework?
48 | Negroni ist **kein** Framework. Es ist eine Bibliothek, geschaffen, um kompatibel mit `net/http` zu sein.
49 |
50 | ## Routing?
51 | Negroni ist BYOR (Bring your own Router - Nutze Deinen eigenen Router). Die Go-Community verfügt bereits über eine Vielzahl von großartigen Routern. Negroni versucht möglichst alle zu unterstützen, indem es `net/http` vollständig unterstützt. Beispielsweise sieht eine Implementation mit [Gorilla Mux](http://github.com/gorilla/mux) folgendermaßen aus:
52 |
53 | ~~~ go
54 | router := mux.NewRouter()
55 | router.HandleFunc("/", HomeHandler)
56 |
57 | n := negroni.New(Middleware1, Middleware2)
58 | // Oder nutze eine Middleware mit der Use()-Funktion
59 | n.Use(Middleware3)
60 | // Der Router kommt als letztes
61 | n.UseHandler(router)
62 |
63 | n.Run(":3000")
64 | ~~~
65 |
66 | ## `negroni.Classic()`
67 | `negroni.Classic()` stellt einige Standard-Middlewares bereit, die für die meisten Anwendungen von Nutzen ist:
68 |
69 | * `negroni.Recovery` - Middleware für Panic Recovery .
70 | * `negroni.Logging` - Anfrage/Rückmeldungs-Logging-Middleware.
71 | * `negroni.Static` - Ausliefern von statischen Dateien unter dem "public" Verzeichnis.
72 |
73 | Dies macht es wirklich einfach, mit den nützlichen Funktionen von Negroni zu starten.
74 |
75 | ## Handlers
76 | Negroni stellt einen bidirektionalen Middleware-Flow bereit. Dies wird durch das `negroni.Handler`-Interface erreicht:
77 |
78 | ~~~ go
79 | type Handler interface {
80 | ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
81 | }
82 | ~~~
83 |
84 | Wenn eine Middleware nicht bereits den ResponseWriter genutzt hat, sollte sie die nächste `http.HandlerFunc` in der Verkettung von Middlewares aufrufen und diese ausführen. Das kann von großem Nutzen sein:
85 |
86 | ~~~ go
87 | func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
88 | // Mache etwas vor dem Aufruf
89 | next(rw, r)
90 | // Mache etwas nach dem Aufruf
91 | }
92 | ~~~
93 |
94 | Und Du kannst eine Middleware durch die `Use`-Funktion der Verkettung von Middlewares zuordnen.
95 |
96 | ~~~ go
97 | n := negroni.New()
98 | n.Use(negroni.HandlerFunc(MyMiddleware))
99 | ~~~
100 |
101 | Stattdessen kannst Du auch herkömmliche `http.Handler` zuordnen:
102 |
103 | ~~~ go
104 | n := negroni.New()
105 |
106 | mux := http.NewServeMux()
107 | // Ordne Deine Routen zu
108 |
109 | n.UseHandler(mux)
110 |
111 | n.Run(":3000")
112 | ~~~
113 |
114 | ## `Run()`
115 | Negroni hat eine nützliche Funktion namens `Run`. `Run` übernimmt eine Zeichenkette `addr` ähnlich wie [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe).
116 |
117 | ~~~ go
118 | n := negroni.Classic()
119 | // ...
120 | log.Fatal(http.ListenAndServe(":8080", n))
121 | ~~~
122 |
123 | ## Routenspezifische Middleware
124 | Wenn Du eine Gruppe von Routen hast, welche alle die gleiche Middleware ausführen müssen, kannst Du einfach eine neue Negroni-Instanz erstellen und sie als Route-Handler nutzen:
125 |
126 | ~~~ go
127 | router := mux.NewRouter()
128 | adminRoutes := mux.NewRouter()
129 | // Füge die Admin-Routen hier hinzu
130 |
131 | // Erstelle eine neue Negroni-Instanz für die Admin-Middleware
132 | router.Handle("/admin", negroni.New(
133 | Middleware1,
134 | Middleware2,
135 | negroni.Wrap(adminRoutes),
136 | ))
137 | ~~~
138 |
139 | ## Middlewares von Dritten
140 |
141 | Hier ist eine aktuelle Liste von Middlewares, die kompatible mit Negroni sind. Tue Dir keinen Zwang an, Dich einzutragen, wenn Du selbst eine Middleware programmiert hast:
142 |
143 |
144 | | Middleware | Autor | Beschreibung |
145 | | -----------|--------|-------------|
146 | | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Sichere Authentifikation für Endpunkte einer REST API |
147 | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
148 | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Eine Middleware mit ein paar nützlichen Sicherheitseinstellungen |
149 | | [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Eine Middleware die nach JWTs im `Authorization`-Feld des Header sucht und sie dekodiert.|
150 | | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data Binding von HTTP-Anfragen in Structs |
151 | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-basierender Logger |
152 | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Rendere JSON, XML und HTML Vorlagen |
153 | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic Agent für die Go-Echtzeitumgebung |
154 | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | Kompression von HTTP-Rückmeldungen via GZIP |
155 | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 Middleware |
156 | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management |
157 | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, Benutzer und Berechtigungen |
158 | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generiere TinySVG, HTML und CSS spontan |
159 | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) Unterstützung |
160 | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Eine Middleware die zufällige X-Request-Id-Header jedem Request anfügt |
161 | | [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC-basierte Middleware zur Authentifikation |
162 | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Speichere wichtige Informationen über Deine Webanwendung (Reaktionszeit, etc.) |
163 |
164 | ## Beispiele
165 | [Alexander Rødseth](https://github.com/xyproto) programmierte [mooseware](https://github.com/xyproto/mooseware), ein Grundgerüst zum Erstellen von Negroni Middleware-Handerln.
166 |
167 | ## Aktualisieren in Echtzeit?
168 | [gin](https://github.com/codegangsta/gin) und [fresh](https://github.com/pilu/fresh) aktualisieren Deine Negroni-Anwendung automatisch.
169 |
170 | ## Unverzichbare Informationen für Go- & Negronineulinge
171 |
172 | * [Nutze einen Kontext zum Übertragen von Middlewareinformationen an Handler (Englisch)](http://elithrar.github.io/article/map-string-interface/)
173 | * [Middlewares verstehen (Englisch)](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
174 |
175 | ## Über das Projekt
176 |
177 | Negroni wurde obsseziv von Niemand gerigeren als dem [Code Gangsta](http://codegangsta.io/) entwickelt.
178 |
--------------------------------------------------------------------------------
/vendor/github.com/zabawaba99/firego/internal/firetest/server.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package firetest provides utilities for Firebase testing
3 |
4 | */
5 | package firetest
6 |
7 | import (
8 | "crypto/hmac"
9 | "crypto/sha256"
10 | "encoding/base64"
11 | "encoding/json"
12 | "fmt"
13 | "io"
14 | "io/ioutil"
15 | "log"
16 | "net"
17 | "net/http"
18 | "strings"
19 | "sync/atomic"
20 | "time"
21 | )
22 |
23 | var (
24 | missingJSONExtension = []byte("append .json to your request URI to use the REST API")
25 | missingBody = []byte(`{"error":"Error: No data supplied."}`)
26 | invalidJSON = []byte(`{"error":"Invalid data; couldn't parse JSON object, array, or value. Perhaps you're using invalid characters in your key names."}`)
27 | invalidAuth = []byte(`{"error" : "Could not parse auth token."}`)
28 | )
29 |
30 | // Firetest is a Firebase server implementation
31 | type Firetest struct {
32 | // URL of form http://ipaddr:port with no trailing slash
33 | URL string
34 | // Secret used to authenticate with server
35 | Secret string
36 |
37 | listener net.Listener
38 | db *notifyDB
39 |
40 | requireAuth *int32
41 | }
42 |
43 | // New creates a new Firetest server
44 | func New() *Firetest {
45 | secret := []byte(fmt.Sprint(time.Now().UnixNano()))
46 | return &Firetest{
47 | db: newNotifyDB(),
48 | Secret: base64.URLEncoding.EncodeToString(secret),
49 | requireAuth: new(int32),
50 | }
51 | }
52 |
53 | // Start starts the server
54 | func (ft *Firetest) Start() {
55 | l, err := net.Listen("tcp", "127.0.0.1:0")
56 | if err != nil {
57 | if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
58 | panic(fmt.Errorf("failed to listen on a port: %v", err))
59 | }
60 | }
61 | ft.listener = l
62 |
63 | s := http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
64 | ft.serveHTTP(w, req)
65 | })}
66 | go func() {
67 | if err := s.Serve(l); err != nil {
68 | log.Printf("error serving: %s", err)
69 | }
70 |
71 | ft.Close()
72 | }()
73 | ft.URL = "http://" + ft.listener.Addr().String()
74 | }
75 |
76 | // Close closes the server
77 | func (ft *Firetest) Close() {
78 | if ft.listener != nil {
79 | ft.listener.Close()
80 | }
81 | }
82 |
83 | func (ft *Firetest) serveHTTP(w http.ResponseWriter, req *http.Request) {
84 | if !strings.HasSuffix(req.URL.Path, ".json") {
85 | w.WriteHeader(http.StatusForbidden)
86 | w.Write([]byte(missingJSONExtension))
87 | return
88 | }
89 |
90 | if atomic.LoadInt32(ft.requireAuth) == 1 {
91 | var authenticated bool
92 | authHeader := req.URL.Query().Get("auth")
93 | switch {
94 | case strings.Contains(authHeader, "."):
95 | authenticated = ft.validJWT(authHeader)
96 | default:
97 | authenticated = authHeader == ft.Secret
98 | }
99 |
100 | if !authenticated {
101 | w.WriteHeader(http.StatusUnauthorized)
102 | w.Write(invalidAuth)
103 | return
104 | }
105 | }
106 |
107 | switch req.Method {
108 | case "PUT":
109 | ft.set(w, req)
110 | case "PATCH":
111 | ft.update(w, req)
112 | case "POST":
113 | ft.create(w, req)
114 | case "GET":
115 | switch req.Header.Get("Accept") {
116 | case "text/event-stream":
117 | ft.sse(w, req)
118 | default:
119 | ft.get(w, req)
120 | }
121 | case "DELETE":
122 | ft.del(w, req)
123 | default:
124 | w.WriteHeader(http.StatusMethodNotAllowed)
125 | log.Println("not implemented yet")
126 | }
127 | }
128 |
129 | func decodeSegment(seg string) ([]byte, error) {
130 | if l := len(seg) % 4; l > 0 {
131 | seg += strings.Repeat("=", 4-l)
132 | }
133 |
134 | return base64.URLEncoding.DecodeString(seg)
135 | }
136 |
137 | func (ft *Firetest) validJWT(val string) bool {
138 | parts := strings.Split(val, ".")
139 | if len(parts) != 3 {
140 | return false
141 | }
142 |
143 | // validate header
144 | hb, err := decodeSegment(parts[0])
145 | if err != nil {
146 | log.Println("error decoding header", err)
147 | return false
148 | }
149 | var header map[string]string
150 | if err := json.Unmarshal(hb, &header); err != nil {
151 | log.Println("error unmarshaling header", err)
152 | return false
153 | }
154 | if header["alg"] != "HS256" || header["typ"] != "JWT" {
155 | return false
156 | }
157 |
158 | // validate claim
159 | cb, err := decodeSegment(parts[1])
160 | if err != nil {
161 | log.Println("error decoding claim", err)
162 | return false
163 | }
164 | var claim map[string]interface{}
165 | if err := json.Unmarshal(cb, &claim); err != nil {
166 | log.Println("error unmarshaling claim", err)
167 | return false
168 | }
169 | if e, ok := claim["exp"]; ok {
170 | // make sure not expired
171 | exp, ok := e.(float64)
172 | if !ok {
173 | log.Println("expiration not a number")
174 | return false
175 | }
176 | if int64(exp) < time.Now().Unix() {
177 | log.Println("token expired")
178 | return false
179 | }
180 | }
181 | // ensure uid present
182 | data, ok := claim["d"]
183 | if !ok {
184 | log.Println("missing data in claim")
185 | return false
186 | }
187 |
188 | d, ok := data.(map[string]interface{})
189 | if !ok {
190 | log.Println("claim['data'] is not map")
191 | return false
192 | }
193 |
194 | if _, ok := d["uid"]; !ok {
195 | log.Println("claim['data'] missing uid")
196 | return false
197 | }
198 |
199 | if sig, err := decodeSegment(parts[2]); err == nil {
200 | hasher := hmac.New(sha256.New, []byte(ft.Secret))
201 | signedString := strings.Join(parts[:2], ".")
202 | hasher.Write([]byte(signedString))
203 |
204 | if !hmac.Equal(sig, hasher.Sum(nil)) {
205 | log.Println("invalid jwt signature")
206 | return false
207 | }
208 | }
209 |
210 | return true
211 | }
212 |
213 | func (ft *Firetest) set(w http.ResponseWriter, req *http.Request) {
214 | body, v, ok := unmarshal(w, req.Body)
215 | if !ok {
216 | return
217 | }
218 |
219 | ft.Set(req.URL.Path, v)
220 | w.Write(body)
221 | }
222 |
223 | func (ft *Firetest) update(w http.ResponseWriter, req *http.Request) {
224 | body, v, ok := unmarshal(w, req.Body)
225 | if !ok {
226 | return
227 | }
228 | ft.Update(req.URL.Path, v)
229 | w.Write(body)
230 | }
231 |
232 | func (ft *Firetest) create(w http.ResponseWriter, req *http.Request) {
233 | _, v, ok := unmarshal(w, req.Body)
234 | if !ok {
235 | return
236 | }
237 |
238 | name := ft.Create(req.URL.Path, v)
239 | rtn := map[string]string{"name": name}
240 | if err := json.NewEncoder(w).Encode(rtn); err != nil {
241 | log.Printf("Error encoding json: %s", err)
242 | w.WriteHeader(http.StatusInternalServerError)
243 | }
244 | }
245 |
246 | func (ft *Firetest) del(w http.ResponseWriter, req *http.Request) {
247 | ft.Delete(req.URL.Path)
248 | }
249 |
250 | func (ft *Firetest) get(w http.ResponseWriter, req *http.Request) {
251 | w.Header().Add("Content-Type", "application/json")
252 |
253 | v := ft.Get(req.URL.Path)
254 | if err := json.NewEncoder(w).Encode(v); err != nil {
255 | log.Printf("Error encoding json: %s", err)
256 | w.WriteHeader(http.StatusInternalServerError)
257 | }
258 | }
259 |
260 | func (ft *Firetest) sse(w http.ResponseWriter, req *http.Request) {
261 | f, ok := w.(http.Flusher)
262 | if !ok {
263 | http.Error(w, "Streaming is not supported", http.StatusInternalServerError)
264 | return
265 | }
266 |
267 | w.Header().Set("Content-Type", "text/event-stream")
268 |
269 | path := sanitizePath(req.URL.Path)
270 | c := ft.db.watch(path)
271 | defer ft.db.stopWatching(path, c)
272 |
273 | d := eventData{Path: path, Data: ft.db.get(path)}
274 | s, err := json.Marshal(d)
275 | if err != nil {
276 | fmt.Printf("Error marshaling node %s\n", err)
277 | }
278 | fmt.Fprintf(w, "event: put\ndata: %s\n\n", s)
279 | f.Flush()
280 |
281 | httpCloser := w.(http.CloseNotifier).CloseNotify()
282 | for {
283 | select {
284 | case <-httpCloser:
285 | return
286 | case <-time.After(30 * time.Second):
287 | fmt.Fprintf(w, "event: keep-alive\ndata: null\n\n")
288 | f.Flush()
289 | continue
290 | case n, ok := <-c:
291 | if !ok {
292 | return
293 | }
294 |
295 | s, err := json.Marshal(n.Data)
296 | if err != nil {
297 | fmt.Printf("Error marshaling node %s\n", err)
298 | continue
299 | }
300 |
301 | fmt.Fprintf(w, "event: %s\ndata: %s\n\n", n.Name, s)
302 | f.Flush()
303 | }
304 | }
305 | }
306 |
307 | func sanitizePath(p string) string {
308 | // remove slashes from the front and back
309 | // /foo/.json -> foo/.json
310 | s := strings.Trim(p, "/")
311 |
312 | // remove .json extension
313 | // foo/.json -> foo/
314 | s = strings.TrimSuffix(s, ".json")
315 |
316 | // trim an potential trailing slashes
317 | // foo/ -> foo
318 | return strings.TrimSuffix(s, "/")
319 | }
320 |
321 | func unmarshal(w http.ResponseWriter, r io.Reader) ([]byte, interface{}, bool) {
322 | body, err := ioutil.ReadAll(r)
323 | if err != nil || len(body) == 0 {
324 | w.WriteHeader(http.StatusBadRequest)
325 | w.Write(missingBody)
326 | return nil, nil, false
327 | }
328 |
329 | var v interface{}
330 | if err := json.Unmarshal(body, &v); err != nil {
331 | w.WriteHeader(http.StatusBadRequest)
332 | w.Write(invalidJSON)
333 | return nil, nil, false
334 | }
335 | return body, v, true
336 | }
337 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/mux/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | /*
6 | Package mux implements a request router and dispatcher.
7 |
8 | The name mux stands for "HTTP request multiplexer". Like the standard
9 | http.ServeMux, mux.Router matches incoming requests against a list of
10 | registered routes and calls a handler for the route that matches the URL
11 | or other conditions. The main features are:
12 |
13 | * Requests can be matched based on URL host, path, path prefix, schemes,
14 | header and query values, HTTP methods or using custom matchers.
15 | * URL hosts and paths can have variables with an optional regular
16 | expression.
17 | * Registered URLs can be built, or "reversed", which helps maintaining
18 | references to resources.
19 | * Routes can be used as subrouters: nested routes are only tested if the
20 | parent route matches. This is useful to define groups of routes that
21 | share common conditions like a host, a path prefix or other repeated
22 | attributes. As a bonus, this optimizes request matching.
23 | * It implements the http.Handler interface so it is compatible with the
24 | standard http.ServeMux.
25 |
26 | Let's start registering a couple of URL paths and handlers:
27 |
28 | func main() {
29 | r := mux.NewRouter()
30 | r.HandleFunc("/", HomeHandler)
31 | r.HandleFunc("/products", ProductsHandler)
32 | r.HandleFunc("/articles", ArticlesHandler)
33 | http.Handle("/", r)
34 | }
35 |
36 | Here we register three routes mapping URL paths to handlers. This is
37 | equivalent to how http.HandleFunc() works: if an incoming request URL matches
38 | one of the paths, the corresponding handler is called passing
39 | (http.ResponseWriter, *http.Request) as parameters.
40 |
41 | Paths can have variables. They are defined using the format {name} or
42 | {name:pattern}. If a regular expression pattern is not defined, the matched
43 | variable will be anything until the next slash. For example:
44 |
45 | r := mux.NewRouter()
46 | r.HandleFunc("/products/{key}", ProductHandler)
47 | r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
48 | r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
49 |
50 | Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
51 |
52 | r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
53 |
54 | The names are used to create a map of route variables which can be retrieved
55 | calling mux.Vars():
56 |
57 | vars := mux.Vars(request)
58 | category := vars["category"]
59 |
60 | Note that if any capturing groups are present, mux will panic() during parsing. To prevent
61 | this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
62 | "/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
63 | when capturing groups were present.
64 |
65 | And this is all you need to know about the basic usage. More advanced options
66 | are explained below.
67 |
68 | Routes can also be restricted to a domain or subdomain. Just define a host
69 | pattern to be matched. They can also have variables:
70 |
71 | r := mux.NewRouter()
72 | // Only matches if domain is "www.example.com".
73 | r.Host("www.example.com")
74 | // Matches a dynamic subdomain.
75 | r.Host("{subdomain:[a-z]+}.domain.com")
76 |
77 | There are several other matchers that can be added. To match path prefixes:
78 |
79 | r.PathPrefix("/products/")
80 |
81 | ...or HTTP methods:
82 |
83 | r.Methods("GET", "POST")
84 |
85 | ...or URL schemes:
86 |
87 | r.Schemes("https")
88 |
89 | ...or header values:
90 |
91 | r.Headers("X-Requested-With", "XMLHttpRequest")
92 |
93 | ...or query values:
94 |
95 | r.Queries("key", "value")
96 |
97 | ...or to use a custom matcher function:
98 |
99 | r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
100 | return r.ProtoMajor == 0
101 | })
102 |
103 | ...and finally, it is possible to combine several matchers in a single route:
104 |
105 | r.HandleFunc("/products", ProductsHandler).
106 | Host("www.example.com").
107 | Methods("GET").
108 | Schemes("http")
109 |
110 | Setting the same matching conditions again and again can be boring, so we have
111 | a way to group several routes that share the same requirements.
112 | We call it "subrouting".
113 |
114 | For example, let's say we have several URLs that should only match when the
115 | host is "www.example.com". Create a route for that host and get a "subrouter"
116 | from it:
117 |
118 | r := mux.NewRouter()
119 | s := r.Host("www.example.com").Subrouter()
120 |
121 | Then register routes in the subrouter:
122 |
123 | s.HandleFunc("/products/", ProductsHandler)
124 | s.HandleFunc("/products/{key}", ProductHandler)
125 | s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
126 |
127 | The three URL paths we registered above will only be tested if the domain is
128 | "www.example.com", because the subrouter is tested first. This is not
129 | only convenient, but also optimizes request matching. You can create
130 | subrouters combining any attribute matchers accepted by a route.
131 |
132 | Subrouters can be used to create domain or path "namespaces": you define
133 | subrouters in a central place and then parts of the app can register its
134 | paths relatively to a given subrouter.
135 |
136 | There's one more thing about subroutes. When a subrouter has a path prefix,
137 | the inner routes use it as base for their paths:
138 |
139 | r := mux.NewRouter()
140 | s := r.PathPrefix("/products").Subrouter()
141 | // "/products/"
142 | s.HandleFunc("/", ProductsHandler)
143 | // "/products/{key}/"
144 | s.HandleFunc("/{key}/", ProductHandler)
145 | // "/products/{key}/details"
146 | s.HandleFunc("/{key}/details", ProductDetailsHandler)
147 |
148 | Note that the path provided to PathPrefix() represents a "wildcard": calling
149 | PathPrefix("/static/").Handler(...) means that the handler will be passed any
150 | request that matches "/static/*". This makes it easy to serve static files with mux:
151 |
152 | func main() {
153 | var dir string
154 |
155 | flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
156 | flag.Parse()
157 | r := mux.NewRouter()
158 |
159 | // This will serve files under http://localhost:8000/static/
160 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
161 |
162 | srv := &http.Server{
163 | Handler: r,
164 | Addr: "127.0.0.1:8000",
165 | // Good practice: enforce timeouts for servers you create!
166 | WriteTimeout: 15 * time.Second,
167 | ReadTimeout: 15 * time.Second,
168 | }
169 |
170 | log.Fatal(srv.ListenAndServe())
171 | }
172 |
173 | Now let's see how to build registered URLs.
174 |
175 | Routes can be named. All routes that define a name can have their URLs built,
176 | or "reversed". We define a name calling Name() on a route. For example:
177 |
178 | r := mux.NewRouter()
179 | r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
180 | Name("article")
181 |
182 | To build a URL, get the route and call the URL() method, passing a sequence of
183 | key/value pairs for the route variables. For the previous route, we would do:
184 |
185 | url, err := r.Get("article").URL("category", "technology", "id", "42")
186 |
187 | ...and the result will be a url.URL with the following path:
188 |
189 | "/articles/technology/42"
190 |
191 | This also works for host variables:
192 |
193 | r := mux.NewRouter()
194 | r.Host("{subdomain}.domain.com").
195 | Path("/articles/{category}/{id:[0-9]+}").
196 | HandlerFunc(ArticleHandler).
197 | Name("article")
198 |
199 | // url.String() will be "http://news.domain.com/articles/technology/42"
200 | url, err := r.Get("article").URL("subdomain", "news",
201 | "category", "technology",
202 | "id", "42")
203 |
204 | All variables defined in the route are required, and their values must
205 | conform to the corresponding patterns. These requirements guarantee that a
206 | generated URL will always match a registered route -- the only exception is
207 | for explicitly defined "build-only" routes which never match.
208 |
209 | Regex support also exists for matching Headers within a route. For example, we could do:
210 |
211 | r.HeadersRegexp("Content-Type", "application/(text|json)")
212 |
213 | ...and the route will match both requests with a Content-Type of `application/json` as well as
214 | `application/text`
215 |
216 | There's also a way to build only the URL host or path for a route:
217 | use the methods URLHost() or URLPath() instead. For the previous route,
218 | we would do:
219 |
220 | // "http://news.domain.com/"
221 | host, err := r.Get("article").URLHost("subdomain", "news")
222 |
223 | // "/articles/technology/42"
224 | path, err := r.Get("article").URLPath("category", "technology", "id", "42")
225 |
226 | And if you use subrouters, host and path defined separately can be built
227 | as well:
228 |
229 | r := mux.NewRouter()
230 | s := r.Host("{subdomain}.domain.com").Subrouter()
231 | s.Path("/articles/{category}/{id:[0-9]+}").
232 | HandlerFunc(ArticleHandler).
233 | Name("article")
234 |
235 | // "http://news.domain.com/articles/technology/42"
236 | url, err := r.Get("article").URL("subdomain", "news",
237 | "category", "technology",
238 | "id", "42")
239 | */
240 | package mux
241 |
--------------------------------------------------------------------------------