mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Updated readme
This commit is contained in:
parent
aafe2c5b98
commit
ef90f1dca6
259
Godeps/_workspace/src/github.com/macaron-contrib/session/file.go
generated
vendored
Normal file
259
Godeps/_workspace/src/github.com/macaron-contrib/session/file.go
generated
vendored
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
// Copyright 2013 Beego Authors
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||||
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
// a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Unknwon/com"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileSessionStore represents a file session store implementation.
|
||||||
|
type FileSessionStore struct {
|
||||||
|
p *FileProvider
|
||||||
|
sid string
|
||||||
|
lock sync.RWMutex
|
||||||
|
data map[interface{}]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFileSessionStore creates and returns a file session store.
|
||||||
|
func NewFileSessionStore(p *FileProvider, sid string, kv map[interface{}]interface{}) *FileSessionStore {
|
||||||
|
return &FileSessionStore{
|
||||||
|
p: p,
|
||||||
|
sid: sid,
|
||||||
|
data: kv,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets value to given key in session.
|
||||||
|
func (s *FileSessionStore) Set(key, val interface{}) error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.data[key] = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets value by given key in session.
|
||||||
|
func (s *FileSessionStore) Get(key interface{}) interface{} {
|
||||||
|
s.lock.RLock()
|
||||||
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
|
return s.data[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete a key from session.
|
||||||
|
func (s *FileSessionStore) Delete(key interface{}) error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
delete(s.data, key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns current session ID.
|
||||||
|
func (s *FileSessionStore) ID() string {
|
||||||
|
return s.sid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release releases resource and save data to provider.
|
||||||
|
func (s *FileSessionStore) Release() error {
|
||||||
|
data, err := EncodeGob(s.data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(s.p.filepath(s.sid), data, os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush deletes all session data.
|
||||||
|
func (s *FileSessionStore) Flush() error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.data = make(map[interface{}]interface{})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileProvider represents a file session provider implementation.
|
||||||
|
type FileProvider struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
maxlifetime int64
|
||||||
|
rootPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes file session provider with given root path.
|
||||||
|
func (p *FileProvider) Init(maxlifetime int64, rootPath string) error {
|
||||||
|
p.maxlifetime = maxlifetime
|
||||||
|
p.rootPath = rootPath
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *FileProvider) filepath(sid string) string {
|
||||||
|
return path.Join(p.rootPath, string(sid[0]), string(sid[1]), sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read returns raw session store by session ID.
|
||||||
|
func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
filename := p.filepath(sid)
|
||||||
|
if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var f *os.File
|
||||||
|
if com.IsFile(filename) {
|
||||||
|
f, err = os.OpenFile(filename, os.O_RDWR, os.ModePerm)
|
||||||
|
} else {
|
||||||
|
f, err = os.Create(filename)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if err = os.Chtimes(filename, time.Now(), time.Now()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var kv map[interface{}]interface{}
|
||||||
|
data, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
kv = make(map[interface{}]interface{})
|
||||||
|
} else {
|
||||||
|
kv, err = DecodeGob(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NewFileSessionStore(p, sid, kv), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist returns true if session with given ID exists.
|
||||||
|
func (p *FileProvider) Exist(sid string) bool {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
return com.IsFile(p.filepath(sid))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destory deletes a session by session ID.
|
||||||
|
func (p *FileProvider) Destory(sid string) error {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
return os.Remove(p.filepath(sid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *FileProvider) regenerate(oldsid, sid string) (err error) {
|
||||||
|
filename := p.filepath(sid)
|
||||||
|
if com.IsExist(filename) {
|
||||||
|
return fmt.Errorf("new sid '%s' already exists", sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldname := p.filepath(oldsid)
|
||||||
|
if !com.IsFile(oldname) {
|
||||||
|
data, err := EncodeGob(make(map[interface{}]interface{}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(path.Dir(oldname), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = ioutil.WriteFile(oldname, data, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.Rename(oldname, filename); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regenerate regenerates a session store from old session ID to new one.
|
||||||
|
func (p *FileProvider) Regenerate(oldsid, sid string) (_ RawStore, err error) {
|
||||||
|
p.lock.Lock()
|
||||||
|
if err := p.regenerate(oldsid, sid); err != nil {
|
||||||
|
p.lock.Unlock()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.lock.Unlock()
|
||||||
|
|
||||||
|
return p.Read(sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count counts and returns number of sessions.
|
||||||
|
func (p *FileProvider) Count() int {
|
||||||
|
count := 0
|
||||||
|
if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fi.IsDir() {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
log.Printf("error counting session files: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// GC calls GC to clean expired sessions.
|
||||||
|
func (p *FileProvider) GC() {
|
||||||
|
if !com.IsExist(p.rootPath) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fi.IsDir() &&
|
||||||
|
(fi.ModTime().Unix()+p.maxlifetime) < time.Now().Unix() {
|
||||||
|
return os.Remove(path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
log.Printf("error garbage collecting session files: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register("file", &FileProvider{})
|
||||||
|
}
|
34
Godeps/_workspace/src/github.com/macaron-contrib/session/file_test.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/macaron-contrib/session/file_test.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||||
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
// a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_FileProvider(t *testing.T) {
|
||||||
|
Convey("Test file session provider", t, func() {
|
||||||
|
dir := path.Join(os.TempDir(), "data/sessions")
|
||||||
|
os.RemoveAll(dir)
|
||||||
|
testProvider(Options{
|
||||||
|
Provider: "file",
|
||||||
|
ProviderConfig: dir,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
212
Godeps/_workspace/src/github.com/macaron-contrib/session/memory.go
generated
vendored
Normal file
212
Godeps/_workspace/src/github.com/macaron-contrib/session/memory.go
generated
vendored
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// Copyright 2013 Beego Authors
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||||
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
// a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MemSessionStore represents a in-memory session store implementation.
|
||||||
|
type MemSessionStore struct {
|
||||||
|
sid string
|
||||||
|
lock sync.RWMutex
|
||||||
|
data map[interface{}]interface{}
|
||||||
|
lastAccess time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemSessionStore creates and returns a memory session store.
|
||||||
|
func NewMemSessionStore(sid string) *MemSessionStore {
|
||||||
|
return &MemSessionStore{
|
||||||
|
sid: sid,
|
||||||
|
data: make(map[interface{}]interface{}),
|
||||||
|
lastAccess: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets value to given key in session.
|
||||||
|
func (s *MemSessionStore) Set(key, val interface{}) error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.data[key] = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets value by given key in session.
|
||||||
|
func (s *MemSessionStore) Get(key interface{}) interface{} {
|
||||||
|
s.lock.RLock()
|
||||||
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
|
return s.data[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete a key from session.
|
||||||
|
func (s *MemSessionStore) Delete(key interface{}) error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
delete(s.data, key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns current session ID.
|
||||||
|
func (s *MemSessionStore) ID() string {
|
||||||
|
return s.sid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release releases resource and save data to provider.
|
||||||
|
func (_ *MemSessionStore) Release() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush deletes all session data.
|
||||||
|
func (s *MemSessionStore) Flush() error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
s.data = make(map[interface{}]interface{})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemProvider represents a in-memory session provider implementation.
|
||||||
|
type MemProvider struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
maxLifetime int64
|
||||||
|
data map[string]*list.Element
|
||||||
|
// A priority list whose lastAccess newer gets higer priority.
|
||||||
|
list *list.List
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes memory session provider.
|
||||||
|
func (p *MemProvider) Init(maxLifetime int64, _ string) error {
|
||||||
|
p.maxLifetime = maxLifetime
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// update expands time of session store by given ID.
|
||||||
|
func (p *MemProvider) update(sid string) error {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
if e, ok := p.data[sid]; ok {
|
||||||
|
e.Value.(*MemSessionStore).lastAccess = time.Now()
|
||||||
|
p.list.MoveToFront(e)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read returns raw session store by session ID.
|
||||||
|
func (p *MemProvider) Read(sid string) (_ RawStore, err error) {
|
||||||
|
p.lock.RLock()
|
||||||
|
e, ok := p.data[sid]
|
||||||
|
p.lock.RUnlock()
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
if err = p.update(sid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.Value.(*MemSessionStore), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new session.
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
s := NewMemSessionStore(sid)
|
||||||
|
p.data[sid] = p.list.PushBack(s)
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist returns true if session with given ID exists.
|
||||||
|
func (p *MemProvider) Exist(sid string) bool {
|
||||||
|
p.lock.RLock()
|
||||||
|
defer p.lock.RUnlock()
|
||||||
|
|
||||||
|
_, ok := p.data[sid]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destory deletes a session by session ID.
|
||||||
|
func (p *MemProvider) Destory(sid string) error {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
e, ok := p.data[sid]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p.list.Remove(e)
|
||||||
|
delete(p.data, sid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regenerate regenerates a session store from old session ID to new one.
|
||||||
|
func (p *MemProvider) Regenerate(oldsid, sid string) (RawStore, error) {
|
||||||
|
if p.Exist(sid) {
|
||||||
|
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := p.Read(oldsid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.Destory(oldsid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.(*MemSessionStore).sid = sid
|
||||||
|
p.data[sid] = p.list.PushBack(s)
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count counts and returns number of sessions.
|
||||||
|
func (p *MemProvider) Count() int {
|
||||||
|
return p.list.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GC calls GC to clean expired sessions.
|
||||||
|
func (p *MemProvider) GC() {
|
||||||
|
p.lock.RLock()
|
||||||
|
for {
|
||||||
|
// No session in the list.
|
||||||
|
e := p.list.Back()
|
||||||
|
if e == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Value.(*MemSessionStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() {
|
||||||
|
p.lock.RUnlock()
|
||||||
|
p.lock.Lock()
|
||||||
|
p.list.Remove(e)
|
||||||
|
delete(p.data, e.Value.(*MemSessionStore).sid)
|
||||||
|
p.lock.Unlock()
|
||||||
|
p.lock.RLock()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.lock.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register("memory", &MemProvider{list: list.New(), data: make(map[string]*list.Element)})
|
||||||
|
}
|
27
Godeps/_workspace/src/github.com/macaron-contrib/session/memory_test.go
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/macaron-contrib/session/memory_test.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||||
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
// a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_MemProvider(t *testing.T) {
|
||||||
|
Convey("Test memory session provider", t, func() {
|
||||||
|
testProvider(Options{})
|
||||||
|
})
|
||||||
|
}
|
200
Godeps/_workspace/src/github.com/macaron-contrib/session/session_test.go
generated
vendored
Normal file
200
Godeps/_workspace/src/github.com/macaron-contrib/session/session_test.go
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||||
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
// a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Unknwon/macaron"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Version(t *testing.T) {
|
||||||
|
Convey("Check package version", t, func() {
|
||||||
|
So(Version(), ShouldEqual, _VERSION)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Sessioner(t *testing.T) {
|
||||||
|
Convey("Use session middleware", t, func() {
|
||||||
|
m := macaron.New()
|
||||||
|
m.Use(Sessioner())
|
||||||
|
m.Get("/", func() {})
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest("GET", "/", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Register invalid provider that", t, func() {
|
||||||
|
Convey("Provider not exists", func() {
|
||||||
|
defer func() {
|
||||||
|
So(recover(), ShouldNotBeNil)
|
||||||
|
}()
|
||||||
|
|
||||||
|
m := macaron.New()
|
||||||
|
m.Use(Sessioner(Options{
|
||||||
|
Provider: "fake",
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Provider value is nil", func() {
|
||||||
|
defer func() {
|
||||||
|
So(recover(), ShouldNotBeNil)
|
||||||
|
}()
|
||||||
|
|
||||||
|
Register("fake", nil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Register twice", func() {
|
||||||
|
defer func() {
|
||||||
|
So(recover(), ShouldNotBeNil)
|
||||||
|
}()
|
||||||
|
|
||||||
|
Register("memory", &MemProvider{})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testProvider(opt Options) {
|
||||||
|
Convey("Basic operation", func() {
|
||||||
|
m := macaron.New()
|
||||||
|
m.Use(Sessioner(opt))
|
||||||
|
|
||||||
|
m.Get("/", func(ctx *macaron.Context, sess Store) {
|
||||||
|
sess.Set("uname", "unknwon")
|
||||||
|
})
|
||||||
|
m.Get("/reg", func(ctx *macaron.Context, sess Store) {
|
||||||
|
raw, err := sess.RegenerateId(ctx)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(raw, ShouldNotBeNil)
|
||||||
|
|
||||||
|
uname := raw.Get("uname")
|
||||||
|
So(uname, ShouldNotBeNil)
|
||||||
|
So(uname, ShouldEqual, "unknwon")
|
||||||
|
})
|
||||||
|
m.Get("/get", func(ctx *macaron.Context, sess Store) {
|
||||||
|
sid := sess.ID()
|
||||||
|
So(sid, ShouldNotBeEmpty)
|
||||||
|
|
||||||
|
raw, err := sess.Read(sid)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(raw, ShouldNotBeNil)
|
||||||
|
|
||||||
|
uname := sess.Get("uname")
|
||||||
|
So(uname, ShouldNotBeNil)
|
||||||
|
So(uname, ShouldEqual, "unknwon")
|
||||||
|
|
||||||
|
So(sess.Delete("uname"), ShouldBeNil)
|
||||||
|
So(sess.Get("uname"), ShouldBeNil)
|
||||||
|
|
||||||
|
So(sess.Destory(ctx), ShouldBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest("GET", "/", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
cookie := resp.Header().Get("Set-Cookie")
|
||||||
|
|
||||||
|
resp = httptest.NewRecorder()
|
||||||
|
req, err = http.NewRequest("GET", "/reg", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
req.Header.Set("Cookie", cookie)
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
cookie = resp.Header().Get("Set-Cookie")
|
||||||
|
|
||||||
|
resp = httptest.NewRecorder()
|
||||||
|
req, err = http.NewRequest("GET", "/get", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
req.Header.Set("Cookie", cookie)
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Regenrate empty session", func() {
|
||||||
|
m := macaron.New()
|
||||||
|
m.Use(Sessioner(opt))
|
||||||
|
m.Get("/", func(ctx *macaron.Context, sess Store) {
|
||||||
|
raw, err := sess.RegenerateId(ctx)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(raw, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest("GET", "/", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
req.Header.Set("Cookie", "MacaronSession=ad2c7e3cbecfcf486; Path=/;")
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("GC session", func() {
|
||||||
|
m := macaron.New()
|
||||||
|
opt2 := opt
|
||||||
|
opt2.Gclifetime = 1
|
||||||
|
m.Use(Sessioner(opt2))
|
||||||
|
|
||||||
|
m.Get("/", func(sess Store) {
|
||||||
|
sess.Set("uname", "unknwon")
|
||||||
|
So(sess.ID(), ShouldNotBeEmpty)
|
||||||
|
uname := sess.Get("uname")
|
||||||
|
So(uname, ShouldNotBeNil)
|
||||||
|
So(uname, ShouldEqual, "unknwon")
|
||||||
|
|
||||||
|
So(sess.Flush(), ShouldBeNil)
|
||||||
|
So(sess.Get("uname"), ShouldBeNil)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
sess.GC()
|
||||||
|
So(sess.Count(), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest("GET", "/", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Flash(t *testing.T) {
|
||||||
|
Convey("Test flash", t, func() {
|
||||||
|
m := macaron.New()
|
||||||
|
m.Use(Sessioner())
|
||||||
|
m.Get("/set", func(f *Flash) string {
|
||||||
|
f.Success("success")
|
||||||
|
f.Error("error")
|
||||||
|
f.Warning("warning")
|
||||||
|
f.Info("info")
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
m.Get("/get", func() {})
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest("GET", "/set", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
resp = httptest.NewRecorder()
|
||||||
|
req, err = http.NewRequest("GET", "/get", nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
req.Header.Set("Cookie", "macaron_flash=error%3Derror%26info%3Dinfo%26success%3Dsuccess%26warning%3Dwarning; Path=/")
|
||||||
|
m.ServeHTTP(resp, req)
|
||||||
|
})
|
||||||
|
}
|
69
Godeps/_workspace/src/github.com/macaron-contrib/session/utils.go
generated
vendored
Normal file
69
Godeps/_workspace/src/github.com/macaron-contrib/session/utils.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2013 Beego Authors
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||||
|
// not use this file except in compliance with the License. You may obtain
|
||||||
|
// a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
// License for the specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/gob"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/Unknwon/com"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register([]interface{}{})
|
||||||
|
gob.Register(map[int]interface{}{})
|
||||||
|
gob.Register(map[string]interface{}{})
|
||||||
|
gob.Register(map[interface{}]interface{}{})
|
||||||
|
gob.Register(map[string]string{})
|
||||||
|
gob.Register(map[int]string{})
|
||||||
|
gob.Register(map[int]int{})
|
||||||
|
gob.Register(map[int]int64{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) {
|
||||||
|
for _, v := range obj {
|
||||||
|
gob.Register(v)
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(obj)
|
||||||
|
if err != nil {
|
||||||
|
return []byte(""), err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeGob(encoded []byte) (map[interface{}]interface{}, error) {
|
||||||
|
buf := bytes.NewBuffer(encoded)
|
||||||
|
dec := gob.NewDecoder(buf)
|
||||||
|
var out map[interface{}]interface{}
|
||||||
|
err := dec.Decode(&out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateRandomKey creates a random key with the given strength.
|
||||||
|
func generateRandomKey(strength int) []byte {
|
||||||
|
k := make([]byte, strength)
|
||||||
|
if n, err := io.ReadFull(rand.Reader, k); n != strength || err != nil {
|
||||||
|
return com.RandomCreateBytes(strength)
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
47
README.md
47
README.md
@ -1,46 +1,3 @@
|
|||||||
grafana-pro
|
Work in progress Grafana 2.0 (with included Grafana backend)
|
||||||
===========
|
|
||||||
|
|
||||||
This is very much a Work in Progess. The architecture and organisation has changed many times and I am not very happy
|
|
||||||
with the current structure and architecture. I started with a lot of unit tests and drove the design though that in
|
|
||||||
the begining, but then having changed the code and structure (and web framework libs, and database) I sort of
|
|
||||||
abandoned them. When the architecture is getting more stable I will write & require more unit & integration tests.
|
|
||||||
|
|
||||||
# Architecture
|
|
||||||
I have researched a lot of go projects, found very few with a nice modular & loosly coupled archictecture. Go projects
|
|
||||||
organize code very differently, some treat packages as global singletons (which reads nicely and is nice to work with
|
|
||||||
but seems like a bad practice). I do miss generics for doing strongly typed but loosley coupled command/query style
|
|
||||||
internal buss messaging.
|
|
||||||
|
|
||||||
The biggest challange for architecture is making Grafana Pro very modular in a way that all/most components can
|
|
||||||
run inproc or in seperate process (usefull when running Grafana Pro in a large scale SaaS setup). Been investigating
|
|
||||||
using ZeroMQ or NanoMsg to handle module communication (Both ZeroMQ and NanoMsg can handle inproc & tcp which a number of
|
|
||||||
different topologies). Running Grafana Pro in a SaaS setup might warrant that the alerting stuff runs out of proc on
|
|
||||||
other servers feeding of a queue for example, but for simple on prem stuff it would be cool if that could be run in the
|
|
||||||
same process. I am also thinking that some stuff might need swapping out/in depending on the setup (plugin model or just
|
|
||||||
interfaces with different implementations).
|
|
||||||
|
|
||||||
# Building
|
|
||||||
* Just added a simple make file (the main binary package is in pkg/cmd/grafana-pro)
|
|
||||||
* Need to change to godep or some go lang dependency management system
|
|
||||||
|
|
||||||
# Data access
|
|
||||||
Data access is very strange right now, instead of an interface I tried using public methods in the models package.
|
|
||||||
These method pointers are assigned in when the sqlstore is initialized in pkg/store/sqlstore. This is probably a
|
|
||||||
bad idea. I am thinking about either moving to simple interfaces. But I do not want a giant interface for all
|
|
||||||
data acess. Would much prefe a simple generic command/query interface but golang lacks generics which makes this
|
|
||||||
painful. But a generic command/query interface could still be good as it would make it easier to have some commands or
|
|
||||||
queries handled buy out of proc components (or inproc if we used someting like ZeroMQ for communication). Or it
|
|
||||||
could be overengineering thinking like this.
|
|
||||||
|
|
||||||
# Grafana frontend
|
|
||||||
The grafana frontend is added as git submodule in order to easily sync with upstream grafana.
|
|
||||||
There should be a symbolic link from ./grafana/src to ./public . Need to add this to the Makefile.
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
* Add symbolik link between ./grafana/src ./public
|
|
||||||
* Hash & Salt password
|
|
||||||
* Unit tests for data access
|
|
||||||
* I switched recently from rethinkdb to sql (using a simple mini ORM lib called xorm, might need to switch to a more
|
|
||||||
popular ORM lib).
|
|
||||||
|
|
||||||
|
[](https://app.wercker.com/project/bykey/0f109051cfaf2a6d94c0eebdc0dcaeae)
|
||||||
|
Loading…
Reference in New Issue
Block a user