Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
5f0e7cd5
Commit
5f0e7cd5
authored
Mar 23, 2015
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added custom cache control headers for static content
parent
98c02099
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
266 additions
and
37 deletions
+266
-37
conf/defaults.ini
+3
-4
pkg/api/dashboard_snapshot.go
+1
-0
pkg/api/static/static.go
+218
-0
pkg/cmd/web.go
+14
-6
src/app/features/dashboard/shareSnapshotCtrl.js
+29
-27
tasks/options/requirejs.js
+1
-0
No files found.
conf/defaults.ini
View file @
5f0e7cd5
app_name
=
Grafana
app_mode
=
production
# Once every 1 hour Grafana will report anonymous data to
# stats.grafana.org (https). No ip addresses are being tracked.
# only simple counters to track running instances, dashboard
# count and errors. It is very helpful to us.
# Report anonymous usage counters to stats.grafana.org (https).
# No ip addresses are being tracked, only simple counters to track
# running instances, dashboard count and errors. It is very helpful to us.
# Change this option to false to disable reporting.
reporting-enabled
=
true
...
...
pkg/api/dashboard_snapshot.go
View file @
5f0e7cd5
...
...
@@ -35,5 +35,6 @@ func GetDashboardSnapshot(c *middleware.Context) {
Meta
:
dtos
.
DashboardMeta
{
IsSnapshot
:
true
},
}
c
.
Resp
.
Header
()
.
Set
(
"Cache-Control"
,
"public max-age: 31536000"
)
c
.
JSON
(
200
,
dto
)
}
pkg/api/static/static.go
0 → 100644
View file @
5f0e7cd5
// Copyright 2013 Martini 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
httpstatic
import
(
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"sync"
"github.com/Unknwon/macaron"
)
var
Root
string
func
init
()
{
var
err
error
Root
,
err
=
os
.
Getwd
()
if
err
!=
nil
{
panic
(
"error getting work directory: "
+
err
.
Error
())
}
}
// StaticOptions is a struct for specifying configuration options for the macaron.Static middleware.
type
StaticOptions
struct
{
// Prefix is the optional prefix used to serve the static directory content
Prefix
string
// SkipLogging will disable [Static] log messages when a static file is served.
SkipLogging
bool
// IndexFile defines which file to serve as index if it exists.
IndexFile
string
// Expires defines which user-defined function to use for producing a HTTP Expires Header
// https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
AddHeaders
func
(
ctx
*
macaron
.
Context
)
// FileSystem is the interface for supporting any implmentation of file system.
FileSystem
http
.
FileSystem
}
// FIXME: to be deleted.
type
staticMap
struct
{
lock
sync
.
RWMutex
data
map
[
string
]
*
http
.
Dir
}
func
(
sm
*
staticMap
)
Set
(
dir
*
http
.
Dir
)
{
sm
.
lock
.
Lock
()
defer
sm
.
lock
.
Unlock
()
sm
.
data
[
string
(
*
dir
)]
=
dir
}
func
(
sm
*
staticMap
)
Get
(
name
string
)
*
http
.
Dir
{
sm
.
lock
.
RLock
()
defer
sm
.
lock
.
RUnlock
()
return
sm
.
data
[
name
]
}
func
(
sm
*
staticMap
)
Delete
(
name
string
)
{
sm
.
lock
.
Lock
()
defer
sm
.
lock
.
Unlock
()
delete
(
sm
.
data
,
name
)
}
var
statics
=
staticMap
{
sync
.
RWMutex
{},
map
[
string
]
*
http
.
Dir
{}}
// staticFileSystem implements http.FileSystem interface.
type
staticFileSystem
struct
{
dir
*
http
.
Dir
}
func
newStaticFileSystem
(
directory
string
)
staticFileSystem
{
if
!
filepath
.
IsAbs
(
directory
)
{
directory
=
filepath
.
Join
(
Root
,
directory
)
}
dir
:=
http
.
Dir
(
directory
)
statics
.
Set
(
&
dir
)
return
staticFileSystem
{
&
dir
}
}
func
(
fs
staticFileSystem
)
Open
(
name
string
)
(
http
.
File
,
error
)
{
return
fs
.
dir
.
Open
(
name
)
}
func
prepareStaticOption
(
dir
string
,
opt
StaticOptions
)
StaticOptions
{
// Defaults
if
len
(
opt
.
IndexFile
)
==
0
{
opt
.
IndexFile
=
"index.html"
}
// Normalize the prefix if provided
if
opt
.
Prefix
!=
""
{
// Ensure we have a leading '/'
if
opt
.
Prefix
[
0
]
!=
'/'
{
opt
.
Prefix
=
"/"
+
opt
.
Prefix
}
// Remove any trailing '/'
opt
.
Prefix
=
strings
.
TrimRight
(
opt
.
Prefix
,
"/"
)
}
if
opt
.
FileSystem
==
nil
{
opt
.
FileSystem
=
newStaticFileSystem
(
dir
)
}
return
opt
}
func
prepareStaticOptions
(
dir
string
,
options
[]
StaticOptions
)
StaticOptions
{
var
opt
StaticOptions
if
len
(
options
)
>
0
{
opt
=
options
[
0
]
}
return
prepareStaticOption
(
dir
,
opt
)
}
func
staticHandler
(
ctx
*
macaron
.
Context
,
log
*
log
.
Logger
,
opt
StaticOptions
)
bool
{
if
ctx
.
Req
.
Method
!=
"GET"
&&
ctx
.
Req
.
Method
!=
"HEAD"
{
return
false
}
file
:=
ctx
.
Req
.
URL
.
Path
// if we have a prefix, filter requests by stripping the prefix
if
opt
.
Prefix
!=
""
{
if
!
strings
.
HasPrefix
(
file
,
opt
.
Prefix
)
{
return
false
}
file
=
file
[
len
(
opt
.
Prefix
)
:
]
if
file
!=
""
&&
file
[
0
]
!=
'/'
{
return
false
}
}
f
,
err
:=
opt
.
FileSystem
.
Open
(
file
)
if
err
!=
nil
{
return
false
}
defer
f
.
Close
()
fi
,
err
:=
f
.
Stat
()
if
err
!=
nil
{
return
true
// File exists but fail to open.
}
// Try to serve index file
if
fi
.
IsDir
()
{
// Redirect if missing trailing slash.
if
!
strings
.
HasSuffix
(
ctx
.
Req
.
URL
.
Path
,
"/"
)
{
http
.
Redirect
(
ctx
.
Resp
,
ctx
.
Req
.
Request
,
ctx
.
Req
.
URL
.
Path
+
"/"
,
http
.
StatusFound
)
return
true
}
file
=
path
.
Join
(
file
,
opt
.
IndexFile
)
f
,
err
=
opt
.
FileSystem
.
Open
(
file
)
if
err
!=
nil
{
return
false
// Discard error.
}
defer
f
.
Close
()
fi
,
err
=
f
.
Stat
()
if
err
!=
nil
||
fi
.
IsDir
()
{
return
true
}
}
if
!
opt
.
SkipLogging
{
log
.
Println
(
"[Static] Serving "
+
file
)
}
// Add an Expires header to the static content
if
opt
.
AddHeaders
!=
nil
{
opt
.
AddHeaders
(
ctx
)
}
http
.
ServeContent
(
ctx
.
Resp
,
ctx
.
Req
.
Request
,
file
,
fi
.
ModTime
(),
f
)
return
true
}
// Static returns a middleware handler that serves static files in the given directory.
func
Static
(
directory
string
,
staticOpt
...
StaticOptions
)
macaron
.
Handler
{
opt
:=
prepareStaticOptions
(
directory
,
staticOpt
)
return
func
(
ctx
*
macaron
.
Context
,
log
*
log
.
Logger
)
{
staticHandler
(
ctx
,
log
,
opt
)
}
}
// Statics registers multiple static middleware handlers all at once.
func
Statics
(
opt
StaticOptions
,
dirs
...
string
)
macaron
.
Handler
{
if
len
(
dirs
)
==
0
{
panic
(
"no static directory is given"
)
}
opts
:=
make
([]
StaticOptions
,
len
(
dirs
))
for
i
:=
range
dirs
{
opts
[
i
]
=
prepareStaticOption
(
dirs
[
i
],
opt
)
}
return
func
(
ctx
*
macaron
.
Context
,
log
*
log
.
Logger
)
{
for
i
:=
range
opts
{
if
staticHandler
(
ctx
,
log
,
opts
[
i
])
{
return
}
}
}
}
pkg/cmd/web.go
View file @
5f0e7cd5
...
...
@@ -11,7 +11,6 @@ import (
"path"
"path/filepath"
"strconv"
"time"
"github.com/Unknwon/macaron"
"github.com/codegangsta/cli"
...
...
@@ -20,6 +19,7 @@ import (
_
"github.com/macaron-contrib/session/postgres"
"github.com/grafana/grafana/pkg/api"
"github.com/grafana/grafana/pkg/api/static"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
...
...
@@ -65,14 +65,22 @@ func newMacaron() *macaron.Macaron {
}
func
mapStatic
(
m
*
macaron
.
Macaron
,
dir
string
,
prefix
string
)
{
m
.
Use
(
macaron
.
Static
(
headers
:=
func
(
c
*
macaron
.
Context
)
{
c
.
Resp
.
Header
()
.
Set
(
"Cache-Control"
,
"public max-age: 3600"
)
}
if
setting
.
Env
==
setting
.
DEV
{
headers
=
func
(
c
*
macaron
.
Context
)
{
c
.
Resp
.
Header
()
.
Set
(
"Cache-Control"
,
"max-age: 0"
)
}
}
m
.
Use
(
httpstatic
.
Static
(
path
.
Join
(
setting
.
StaticRootPath
,
dir
),
macaron
.
StaticOptions
{
httpstatic
.
StaticOptions
{
SkipLogging
:
true
,
Prefix
:
prefix
,
Expires
:
func
()
string
{
return
time
.
Now
()
.
UTC
()
.
Format
(
http
.
TimeFormat
)
},
AddHeaders
:
headers
,
},
))
}
...
...
src/app/features/dashboard/shareSnapshotCtrl.js
View file @
5f0e7cd5
...
...
@@ -18,42 +18,44 @@ function (angular) {
$rootScope
.
$broadcast
(
'refresh'
);
$timeout
(
function
()
{
var
dash
=
angular
.
copy
(
$scope
.
dashboard
);
dash
.
title
=
$scope
.
snapshot
.
name
;
dash
.
forEachPanel
(
function
(
panel
)
{
panel
.
targets
=
[];
panel
.
links
=
[];
});
$scope
.
saveSnapshot
(
makePublic
);
},
2000
);
};
// cleanup snapshotData
$scope
.
dashboard
.
snapshot
=
false
;
$scope
.
dashboard
.
forEachPanel
(
function
(
panel
)
{
delete
panel
.
snapshotData
;
});
$scope
.
saveSnapshot
=
function
(
makePublic
)
{
var
dash
=
angular
.
copy
(
$scope
.
dashboard
);
dash
.
title
=
$scope
.
snapshot
.
name
;
var
apiUrl
=
'/api/snapshots'
;
dash
.
forEachPanel
(
function
(
panel
)
{
panel
.
targets
=
[];
panel
.
links
=
[];
});
if
(
makePublic
)
{
apiUrl
=
'http://snapshots.raintank.io/api/snapshots'
;
}
// cleanup snapshotData
$scope
.
dashboard
.
snapshot
=
false
;
$scope
.
dashboard
.
forEachPanel
(
function
(
panel
)
{
delete
panel
.
snapshotData
;
});
backendSrv
.
post
(
apiUrl
,
{
dashboard
:
dash
}).
then
(
function
(
results
)
{
$scope
.
loading
=
false
;
var
apiUrl
=
'/api/snapshots'
;
var
baseUrl
=
$location
.
absUrl
().
replace
(
$location
.
url
(),
""
);
if
(
makePublic
)
{
baseUrl
=
'http://snapshots.raintank.io'
;
}
if
(
makePublic
)
{
apiUrl
=
'http://snapshots.raintank.io/api/snapshots'
;
}
$scope
.
snapshotUrl
=
baseUrl
+
'/dashboard/snapshots/'
+
results
.
key
;
backendSrv
.
post
(
apiUrl
,
{
dashboard
:
dash
}).
then
(
function
(
results
)
{
$scope
.
loading
=
false
;
},
function
()
{
$scope
.
loading
=
false
;
});
var
baseUrl
=
$location
.
absUrl
().
replace
(
$location
.
url
(),
""
);
if
(
makePublic
)
{
baseUrl
=
'http://snapshots.raintank.io'
;
}
$scope
.
snapshotUrl
=
baseUrl
+
'/dashboard/snapshots/'
+
results
.
key
;
},
2000
);
},
function
()
{
$scope
.
loading
=
false
;
});
};
});
...
...
tasks/options/requirejs.js
View file @
5f0e7cd5
...
...
@@ -61,6 +61,7 @@ module.exports = function(config,grunt) {
'controllers/all'
,
'routes/all'
,
'components/partials'
,
'plugins/datasource/grafana/datasource'
,
]
}
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment