mirror of https://github.com/statping/statping
http caching - designs
parent
3e4234f2e3
commit
e9354e8e6c
|
@ -0,0 +1,87 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var storage Cacher
|
||||
|
||||
type Cacher interface {
|
||||
Get(key string) []byte
|
||||
Set(key string, content []byte, duration time.Duration)
|
||||
}
|
||||
|
||||
// Item is a cached reference
|
||||
type Item struct {
|
||||
Content []byte
|
||||
Expiration int64
|
||||
}
|
||||
|
||||
// Expired returns true if the item has expired.
|
||||
func (item Item) Expired() bool {
|
||||
if item.Expiration == 0 {
|
||||
return false
|
||||
}
|
||||
return time.Now().UnixNano() > item.Expiration
|
||||
}
|
||||
|
||||
//Storage mecanism for caching strings in memory
|
||||
type Storage struct {
|
||||
items map[string]Item
|
||||
mu *sync.RWMutex
|
||||
}
|
||||
|
||||
//NewStorage creates a new in memory storage
|
||||
func NewStorage() *Storage {
|
||||
return &Storage{
|
||||
items: make(map[string]Item),
|
||||
mu: &sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
//Get a cached content by key
|
||||
func (s Storage) Get(key string) []byte {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
item := s.items[key]
|
||||
if item.Expired() {
|
||||
delete(s.items, key)
|
||||
return nil
|
||||
}
|
||||
return item.Content
|
||||
}
|
||||
|
||||
//Set a cached content by key
|
||||
func (s Storage) Set(key string, content []byte, duration time.Duration) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.items[key] = Item{
|
||||
Content: content,
|
||||
Expiration: time.Now().Add(duration).UnixNano(),
|
||||
}
|
||||
}
|
||||
|
||||
func cached(duration string, handler func(w http.ResponseWriter, r *http.Request)) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
content := storage.Get(r.RequestURI)
|
||||
if content != nil {
|
||||
w.Write(content)
|
||||
} else {
|
||||
c := httptest.NewRecorder()
|
||||
handler(c, r)
|
||||
for k, v := range c.HeaderMap {
|
||||
w.Header()[k] = v
|
||||
}
|
||||
w.WriteHeader(c.Code)
|
||||
content := c.Body.Bytes()
|
||||
if d, err := time.ParseDuration(duration); err == nil {
|
||||
storage.Set(r.RequestURI, content, d)
|
||||
}
|
||||
w.Write(content)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -33,6 +33,7 @@ var (
|
|||
// Router returns all of the routes used in Statup
|
||||
func Router() *mux.Router {
|
||||
dir := utils.Directory
|
||||
storage = NewStorage()
|
||||
r := mux.NewRouter()
|
||||
r.Handle("/", http.HandlerFunc(indexHandler))
|
||||
if source.UsingAssets(dir) {
|
||||
|
@ -96,7 +97,7 @@ func Router() *mux.Router {
|
|||
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
|
||||
r.Handle("/api/services", http.HandlerFunc(apiCreateServiceHandler)).Methods("POST")
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceHandler)).Methods("GET")
|
||||
r.Handle("/api/services/{id}/data", http.HandlerFunc(apiServiceDataHandler)).Methods("GET")
|
||||
r.Handle("/api/services/{id}/data", cached("10s", http.HandlerFunc(apiServiceDataHandler))).Methods("GET")
|
||||
r.Handle("/api/services/{id}/ping", http.HandlerFunc(apiServicePingDataHandler)).Methods("GET")
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceUpdateHandler)).Methods("POST")
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceDeleteHandler)).Methods("DELETE")
|
||||
|
|
|
@ -198,8 +198,8 @@ HTML, BODY {
|
|||
.nav-pills A {
|
||||
color: #424242; }
|
||||
|
||||
.nav-pills > i {
|
||||
margin-right: 5px; }
|
||||
.nav-pills I {
|
||||
margin-right: 10px; }
|
||||
|
||||
.CodeMirror {
|
||||
/* Bootstrap Settings */
|
||||
|
|
|
@ -30,7 +30,10 @@ $('.test_notifier').on('click', function(e) {
|
|||
var notifier = form.find('input[name=notifier]').val();
|
||||
var success = $('#'+notifier+'-success');
|
||||
var error = $('#'+notifier+'-error');
|
||||
var spinner = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
var btnHtml = btn.html();
|
||||
btn.prop("disabled", true);
|
||||
btn.html(spinner);
|
||||
$.ajax({
|
||||
url: form.attr("action")+"/test",
|
||||
type: 'POST',
|
||||
|
@ -49,13 +52,16 @@ $('.test_notifier').on('click', function(e) {
|
|||
}, 8000)
|
||||
}
|
||||
btn.prop("disabled", false);
|
||||
btn.html(btnHtml);
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$('form').submit(function() {
|
||||
var spinner = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
$(this).find('button[type=submit]').prop('disabled', true);
|
||||
$(this).find('button[type=submit]').html(spinner);
|
||||
});
|
||||
|
||||
$('select#service_type').on('change', function() {
|
||||
|
|
|
@ -232,8 +232,8 @@ HTML,BODY {
|
|||
color: #424242;
|
||||
}
|
||||
|
||||
.nav-pills > i {
|
||||
margin-right: 5px;
|
||||
.nav-pills I {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
|
|
|
@ -41,12 +41,12 @@
|
|||
<input type="hidden" name="notifier" value="{{underscore $n.Method }}">
|
||||
|
||||
<div class="col-12 col-sm-4 mb-2 mb-sm-0 mt-2 mt-sm-0">
|
||||
<button type="submit" class="btn btn-primary btn-block text-capitalize"><i class="fa fa-check"></i> Save</button>
|
||||
<button type="submit" class="btn btn-primary btn-block text-capitalize"><i class="fa fa-check-circle"></i> Save</button>
|
||||
</div>
|
||||
|
||||
{{if $n.CanTest}}
|
||||
<div class="col-12 col-sm-12">
|
||||
<button class="test_notifier btn btn-secondary btn-block text-capitalize col-12 float-right"><i class="fa fa-times"></i> Test</button>
|
||||
<button class="test_notifier btn btn-secondary btn-block text-capitalize col-12 float-right"><i class="fa fa-vial"></i> Test Notifier</button>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-12 mt-2">
|
||||
|
|
|
@ -155,7 +155,7 @@
|
|||
|
||||
{{ range .Notifications }}
|
||||
{{$n := .Select}}
|
||||
<div class="tab-pane" id="v-pills-{{underscore $n.Method}}" role="tabpanel" aria-labelledby="v-pills-{{underscore $n.Method }}-tab">
|
||||
<div class="tab-pane fade" id="v-pills-{{underscore $n.Method}}" role="tabpanel" aria-labelledby="v-pills-{{underscore $n.Method }}-tab">
|
||||
|
||||
{{template "form_notifier" .}}
|
||||
|
||||
|
|
Loading…
Reference in New Issue