Split into multiple files
This commit is contained in:
parent
f25e48d084
commit
8aa255b91a
92
functions.go
Normal file
92
functions.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readWebsitesFromFile(filepath string) ([]WebsiteStatus, error) {
|
||||||
|
file, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var websites []WebsiteStatus
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
fields := strings.Split(line, ",")
|
||||||
|
if len(fields) != 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hasIcon, _ := strconv.ParseBool(fields[2])
|
||||||
|
|
||||||
|
website := WebsiteStatus{
|
||||||
|
WebsiteURL: fields[0],
|
||||||
|
Description: fields[1],
|
||||||
|
HasIcon: hasIcon,
|
||||||
|
IconURL: fields[3],
|
||||||
|
}
|
||||||
|
|
||||||
|
websites = append(websites, website)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return websites, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkWebsite(website string) error {
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 5 * time.Second, // Set a timeout for the request
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.Head(website)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if response.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("status code: %d", response.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleCheck(w http.ResponseWriter, r *http.Request) {
|
||||||
|
url := r.URL.Query().Get("url")
|
||||||
|
isUp := checkWebsite(url) == nil
|
||||||
|
response := struct {
|
||||||
|
IsUp bool `json:"isUp"`
|
||||||
|
}{
|
||||||
|
IsUp: isUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderTemplate(w http.ResponseWriter, statuses []WebsiteStatus) {
|
||||||
|
t, err := template.ParseFiles("template.html")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Execute(w, statuses)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
188
main.go
188
main.go
@ -1,29 +1,22 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"text/template"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebsiteStatus struct {
|
type WebsiteStatus struct {
|
||||||
WebsiteUrl string
|
WebsiteURL string
|
||||||
Description string
|
Description string
|
||||||
HasIcon bool
|
HasIcon bool
|
||||||
IconUrl string
|
IconURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
websites := []WebsiteStatus{
|
websites, err := readWebsitesFromFile("websites.conf")
|
||||||
{WebsiteUrl: "https://media.woubery.com", Description: "Jellyfin Server", HasIcon: true, IconUrl: "jellyfin.webp"},
|
if err != nil {
|
||||||
{WebsiteUrl: "https://printing.woubery.com", Description: "OctoPrint", HasIcon: true, IconUrl: "octoprint.png"},
|
log.Fatal(err)
|
||||||
{WebsiteUrl: "https://code.woubery.com", Description: "Gitea Server", HasIcon: true, IconUrl: "gitea.png"},
|
|
||||||
{WebsiteUrl: "https://stream.woubery.com", Description: "Owncast Server", HasIcon: true, IconUrl: "owncast.png"},
|
|
||||||
{WebsiteUrl: "https://julia.woubery.com", Description: "Julia JupyterHub Notebook", HasIcon: true, IconUrl: "julia.png"},
|
|
||||||
{WebsiteUrl: "https://cloud.woubery.com", Description: "Cloud Server", HasIcon: false, IconUrl: ""},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -36,174 +29,3 @@ func main() {
|
|||||||
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkWebsite(website string) error {
|
|
||||||
client := &http.Client{
|
|
||||||
Timeout: 5 * time.Second, // Set a timeout for the request
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := client.Head(website)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
|
|
||||||
if response.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("status code: %d", response.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleCheck(w http.ResponseWriter, r *http.Request) {
|
|
||||||
url := r.URL.Query().Get("url")
|
|
||||||
isUp := checkWebsite(url) == nil
|
|
||||||
response := struct {
|
|
||||||
IsUp bool `json:"isUp"`
|
|
||||||
}{
|
|
||||||
IsUp: isUp,
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderTemplate(w http.ResponseWriter, statuses []WebsiteStatus) {
|
|
||||||
tmpl := `
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Website Status</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
background-color: #f3f3f3;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.website {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
display: inline-block;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
border-radius: 2px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-green {
|
|
||||||
background-color: #27ae60;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-red {
|
|
||||||
background-color: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.website-text {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.website-description {
|
|
||||||
margin-left: 10px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.website-url {
|
|
||||||
margin-left: 10px;
|
|
||||||
color: #333;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.website-url:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
$(".website").each(function() {
|
|
||||||
var website = $(this);
|
|
||||||
var url = website.find(".website-url").attr("href");
|
|
||||||
$.ajax({
|
|
||||||
url: "/check?url=" + encodeURIComponent(url),
|
|
||||||
success: function(response) {
|
|
||||||
var isUp = response.isUp;
|
|
||||||
var statusElement = website.find(".status");
|
|
||||||
statusElement.removeClass("status-green status-red");
|
|
||||||
statusElement.addClass(isUp ? "status-green" : "status-red");
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
var statusElement = website.find(".status");
|
|
||||||
statusElement.removeClass("status-green");
|
|
||||||
statusElement.addClass("status-red");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h1>Ruby's Home Server Status</h1>
|
|
||||||
{{range .}}
|
|
||||||
<div class="website">
|
|
||||||
<div class="website-text">
|
|
||||||
<div class="status"></div>
|
|
||||||
<div class="website-description" href="{{.WebsiteUrl}}">
|
|
||||||
{{.Description}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a class="website-url" href="{{.WebsiteUrl}}" target="_blank">
|
|
||||||
{{.WebsiteUrl}}
|
|
||||||
{{if .HasIcon}}
|
|
||||||
<img class="icon" src="/static/{{.IconUrl}}" alt="Icon">
|
|
||||||
{{end}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>`
|
|
||||||
|
|
||||||
t, err := template.New("webpage").Parse(tmpl)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = t.Execute(w, statuses)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
125
template.html
Normal file
125
template.html
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Website Status</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.website {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-green {
|
||||||
|
background-color: #27ae60;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-red {
|
||||||
|
background-color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.website-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.website-description {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.website-url {
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.website-url:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$(".website").each(function() {
|
||||||
|
var website = $(this);
|
||||||
|
var url = website.find(".website-url").attr("href");
|
||||||
|
$.ajax({
|
||||||
|
url: "/check?url=" + encodeURIComponent(url),
|
||||||
|
success: function(response) {
|
||||||
|
var isUp = response.isUp;
|
||||||
|
var statusElement = website.find(".status");
|
||||||
|
statusElement.removeClass("status-green status-red");
|
||||||
|
statusElement.addClass(isUp ? "status-green" : "status-red");
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
var statusElement = website.find(".status");
|
||||||
|
statusElement.removeClass("status-green");
|
||||||
|
statusElement.addClass("status-red");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Ruby's Home Server Status</h1>
|
||||||
|
{{range .}}
|
||||||
|
<div class="website">
|
||||||
|
<div class="website-text">
|
||||||
|
<div class="status"></div>
|
||||||
|
<div class="website-description" href="{{.WebsiteURL}}">
|
||||||
|
{{.Description}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="website-url" href="{{.WebsiteURL}}" target="_blank">
|
||||||
|
{{.WebsiteURL}}
|
||||||
|
{{if .HasIcon}}
|
||||||
|
<img class="icon" src="/static/{{.IconURL}}" alt="Icon">
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
6
websites.conf
Normal file
6
websites.conf
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
https://media.woubery.com,Jellyfin Server,true,jellyfin.webp
|
||||||
|
https://printing.woubery.com,OctoPrint,true,octoprint.png
|
||||||
|
https://code.woubery.com,Gitea Server,true,gitea.png
|
||||||
|
https://stream.woubery.com,Owncast Server,true,owncast.png
|
||||||
|
https://julia.woubery.com,Julia JupyterHub Notebook,true,julia.png
|
||||||
|
https://cloud.woubery.com,Cloud Server,false,
|
Loading…
x
Reference in New Issue
Block a user