mirror of
https://github.com/gmemstr/sliproad.git
synced 2024-09-20 00:21:15 +01:00
Add disk usage statistics to index & API.
Update README.md Add disk usage statistics to index & API.
This commit is contained in:
parent
a2a1e0e573
commit
88e0d6c7b1
|
@ -21,8 +21,10 @@ then navigate to `localhost:3000`
|
|||
|
||||
initially the heavy lifting was done by the server, but the need for a better frontend was clear.
|
||||
|
||||
full documentation coming soon once actual functionality has been nailed down.
|
||||
|
||||
## credits
|
||||
|
||||
svg icons via https://iconsvg.xyz
|
||||
|
||||
raspberry pi svg via https://www.vectorlogo.zone/logos/raspberrypi/index.html
|
||||
raspberry pi svg via https://www.vectorlogo.zone/logos/raspberrypi/index.html
|
||||
|
|
|
@ -3,14 +3,17 @@
|
|||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
<title>Home | PiNas</title>
|
||||
<title>Home | GoNAS</title>
|
||||
<link rel="stylesheet" href="/assets/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div>
|
||||
<img src="/assets/svgs/pi.svg" alt="">
|
||||
<h1 style="display: inline-block">PiNas</h1>
|
||||
<h1 style="display: inline-block">GoNAS</h1>
|
||||
<p>Hot Storage Usage (<span id="hotUsagePercent"></span>%)</p>
|
||||
<progress max="100" id="hotUsage"></progress>
|
||||
<p>Cold Storage Usage (<span id="coldUsagePercent"></span>%)</p>
|
||||
<progress max="100" id="coldUsage"></progress>
|
||||
</div>
|
||||
<div class="content index">
|
||||
<a href="/files/">
|
||||
|
@ -19,5 +22,31 @@
|
|||
<img src="/assets/svgs/coldfiles.svg" alt="">Cold Files</a>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
const $ = selector => document.querySelector(selector);
|
||||
|
||||
const init = event => {
|
||||
getUsages();
|
||||
}
|
||||
|
||||
const getUsages = () => {
|
||||
fetch('/api/diskusage')
|
||||
.then(function (response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function (jsonResult) {
|
||||
console.log(jsonResult);
|
||||
let hot = (jsonResult.HotStorage.Free) / (jsonResult.HotStorage.Total) * 100;
|
||||
let cold = (jsonResult.ColdStorage.Free) / (jsonResult.ColdStorage.Total) * 100;
|
||||
// Flip values to reflect % used rather than % free.
|
||||
$("#hotUsage").value = 100 - hot;
|
||||
$("#hotUsagePercent").innerText = Math.floor(100 - hot);
|
||||
$("#coldUsage").value = 100 - cold;
|
||||
$("#coldUsagePercent").innerText = Math.floor(100 - cold);
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('load', init);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -3,7 +3,7 @@
|
|||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
<title>| PiNas</title>
|
||||
<title>| GoNAS</title>
|
||||
<link rel="stylesheet" href="/assets/styles.css">
|
||||
<script type="text/javascript" src="/assets/app.js"></script>
|
||||
</head>
|
||||
|
@ -16,7 +16,7 @@
|
|||
<a href="/" class="back-button">
|
||||
<img src="/assets/svgs/back.svg" alt="" data-dismiss-context="false">
|
||||
</a>
|
||||
<h1 style="display: inline-block">PiNas</h1>
|
||||
<h1 style="display: inline-block">GoNAS</h1>
|
||||
</header>
|
||||
<main>
|
||||
<div>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<div class="content" id="filelist">
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input id="path" type="value" name="path">
|
||||
<input type="file" data-multiple-caption="{count} files selected" multiple name="file">
|
||||
<input type="file" multiple name="file">
|
||||
<input type="submit" value="Upload">
|
||||
</form>
|
||||
<p class="directory"><a href="#" id="previous-dir">..</a></p>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const $ = element => document.getElementById(element);
|
||||
const $ = selector => document.querySelector(selector);
|
||||
|
||||
const init = event => {
|
||||
var path = window.location.pathname;
|
||||
|
@ -12,9 +12,9 @@ const init = event => {
|
|||
buildList(json);
|
||||
});
|
||||
|
||||
$("path-header").innerText = path;
|
||||
|
||||
document.querySelector("body").addEventListener('contextmenu', function(ev) {
|
||||
$("#path-header").innerText = path;
|
||||
$("#path").value = path;
|
||||
document.querySelector("body").addEventListener('contextmenu', function (ev) {
|
||||
if (ev.target.localName == "a") {
|
||||
ev.preventDefault();
|
||||
|
||||
|
@ -28,13 +28,13 @@ const init = event => {
|
|||
return false;
|
||||
}, false);
|
||||
|
||||
document.querySelector("body").addEventListener('click', function(ev) {
|
||||
$("body").addEventListener('click', function (ev) {
|
||||
let shouldDismiss = ev.target.dataset.dismissContext == undefined && ev.target.parentElement.classList.contains("context-actions") == false && ev.target.localName != 'a';
|
||||
|
||||
if (ev.which == 1 && shouldDismiss) {
|
||||
ev.preventDefault();
|
||||
|
||||
var d = document.getElementById('context');
|
||||
var d = $('#context');
|
||||
d.classList.add("hidden");
|
||||
return false;
|
||||
}
|
||||
|
@ -58,20 +58,19 @@ const buildList = data => {
|
|||
if (data.Files[i].IsDirectory == true) {
|
||||
fileItem.classList.add("directory");
|
||||
fileLink.href = "/" + data.Prefix + "/" + data.Path + "/" + data.Files[i].Name;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fileItem.classList.add("file");
|
||||
fileLink.href = "/" + data.SinglePrefix + "/" + data.Path + "/" + data.Files[i].Name;
|
||||
}
|
||||
|
||||
fileLink.innerText = data.Files[i].Name;
|
||||
fileItem.appendChild(fileLink);
|
||||
document.getElementById("filelist").appendChild(fileItem);
|
||||
$("#filelist").appendChild(fileItem);
|
||||
}
|
||||
}
|
||||
|
||||
const upload = (file, path) => {
|
||||
var formData = new FormData();
|
||||
var formData = new FormData();
|
||||
formData.append("path", path);
|
||||
formData.append("file", file);
|
||||
fetch('/upload', { // Your POST endpoint
|
||||
|
|
|
@ -96,4 +96,8 @@ a.back-button {
|
|||
.context-actions li {
|
||||
border-bottom: 1px solid black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress[value] {
|
||||
height: 20px;
|
||||
}
|
|
@ -44,7 +44,7 @@ func Listing(tier string) common.Handler {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
var config Config;
|
||||
var config Config
|
||||
err = json.Unmarshal(d, &config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/gmemstr/nas/common"
|
||||
"github.com/gmemstr/nas/files"
|
||||
"github.com/gmemstr/nas/system"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
|
@ -61,6 +62,9 @@ func Init() *mux.Router {
|
|||
fileList(),
|
||||
)).Methods("GET")
|
||||
|
||||
r.Handle("/api/diskusage", Handle(
|
||||
system.DiskUsages(),
|
||||
)).Methods("GET")
|
||||
|
||||
r.Handle("/api/files/", Handle(
|
||||
files.Listing("hot"),
|
||||
|
|
72
system/system.go
Normal file
72
system/system.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gmemstr/nas/common"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ColdStorage string
|
||||
HotStorage string
|
||||
}
|
||||
|
||||
type UsageStat struct {
|
||||
Available int64
|
||||
Free int64
|
||||
Total int64
|
||||
}
|
||||
|
||||
type UsageStats struct {
|
||||
ColdStorage UsageStat
|
||||
HotStorage UsageStat
|
||||
}
|
||||
|
||||
func DiskUsages() common.Handler {
|
||||
|
||||
return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError {
|
||||
var statHot syscall.Statfs_t
|
||||
var statCold syscall.Statfs_t
|
||||
|
||||
d, err := ioutil.ReadFile("assets/config/config.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var config Config
|
||||
err = json.Unmarshal(d, &config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Default to hot storage
|
||||
storage := config.HotStorage
|
||||
err = syscall.Statfs(storage, &statHot)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hotStats := UsageStat{
|
||||
Free: statHot.Bsize * int64(statHot.Bfree),
|
||||
Total: statHot.Bsize * int64(statHot.Blocks),
|
||||
}
|
||||
storage = config.ColdStorage
|
||||
err = syscall.Statfs(storage, &statCold)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
coldStats := UsageStat{
|
||||
Free: statCold.Bsize * int64(statCold.Bfree),
|
||||
Total: statCold.Bsize * int64(statCold.Blocks),
|
||||
}
|
||||
usages := UsageStats{
|
||||
HotStorage: hotStats,
|
||||
ColdStorage: coldStats,
|
||||
}
|
||||
// Available blocks * size per block = available space in bytes
|
||||
resultJson, err := json.Marshal(usages)
|
||||
w.Write(resultJson)
|
||||
return nil
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue