Merge branch 'main' of github.com:help-14/magma
This commit is contained in:
commit
1d37fdd9df
11 changed files with 304 additions and 216 deletions
205
src/main.go
205
src/main.go
|
@ -1,130 +1,57 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
docker "github.com/help-14/magma/addons/docker"
|
||||
healthcheckserver "github.com/help-14/magma/addons/health-check-server"
|
||||
"github.com/help-14/magma/modules"
|
||||
)
|
||||
|
||||
var pwd string
|
||||
var themeDir string
|
||||
var clientAddress string
|
||||
var appConfig modules.Config
|
||||
var websiteData = struct {
|
||||
Config modules.WebsiteConfig
|
||||
Language modules.Language
|
||||
Contents []modules.GroupData
|
||||
}{}
|
||||
var webTemplate *template.Template
|
||||
|
||||
func main() {
|
||||
prepare()
|
||||
loadData()
|
||||
go watchChanges()
|
||||
|
||||
commonfs := http.FileServer(http.Dir(filepath.Join(pwd, "data")))
|
||||
http.Handle("/common/", http.StripPrefix("/common/", commonfs))
|
||||
|
||||
languagefs := http.FileServer(http.Dir(filepath.Join(pwd, "languages")))
|
||||
http.Handle("/languages/", http.StripPrefix("/languages/", languagefs))
|
||||
|
||||
th := themeHandler{}
|
||||
http.Handle("/theme/", th)
|
||||
|
||||
http.HandleFunc("/weather", serveWeather)
|
||||
http.HandleFunc("/", serveTemplate)
|
||||
mux := http.NewServeMux()
|
||||
|
||||
modules.SetupLanguage(mux)
|
||||
modules.SetupTemplate(mux)
|
||||
modules.SetupWeather(mux)
|
||||
//loadAddons()
|
||||
|
||||
log.Println("Listening on http://localhost:7001 ...")
|
||||
err := http.ListenAndServe(":7001", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
server := http.Server{
|
||||
Addr: fmt.Sprintf(":%d", 7001),
|
||||
Handler: mux,
|
||||
}
|
||||
log.Println("Listening on http://localhost:7001 ...")
|
||||
if err := server.ListenAndServe(); err != nil {
|
||||
if !errors.Is(err, http.ErrServerClosed) {
|
||||
fmt.Printf("error running http server: %s\n", err)
|
||||
}
|
||||
}
|
||||
// err := http.ListenAndServe(":7001", nil)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
}
|
||||
|
||||
func prepare() {
|
||||
pwd, _ = os.Getwd()
|
||||
|
||||
dataPath := filepath.Join(pwd, "data")
|
||||
dataPath := filepath.Join(modules.CurrentPath(), "data")
|
||||
os.MkdirAll(dataPath, os.ModePerm)
|
||||
|
||||
iconPath := filepath.Join(dataPath, "icon")
|
||||
os.RemoveAll(iconPath)
|
||||
os.MkdirAll(iconPath, os.ModePerm)
|
||||
|
||||
modules.CopyDir(filepath.Join(pwd, "common"), dataPath, false)
|
||||
}
|
||||
|
||||
func RemoveIndex(s []modules.BookmarkData, index int) {
|
||||
copy(s[index:], s[index+1:])
|
||||
s[len(s)-1] = modules.BookmarkData{"", "", "", false}
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
|
||||
func pruneData() {
|
||||
// Remove local ressources access
|
||||
for group := 0; group < len(websiteData.Contents); group++ {
|
||||
for col := 0; col < len(websiteData.Contents[group].Columns); col++ {
|
||||
bookmarks := websiteData.Contents[group].Columns[col].Bookmarks
|
||||
for bookmark := 0; bookmark < len(websiteData.Contents[group].Columns[col].Bookmarks); bookmark++ {
|
||||
bookmarkData := websiteData.Contents[group].Columns[col].Bookmarks[bookmark]
|
||||
if bookmarkData.IsLocal {
|
||||
RemoveIndex(bookmarks, bookmark)
|
||||
bookmark--
|
||||
}
|
||||
}
|
||||
websiteData.Contents[group].Columns[col].Bookmarks = bookmarks
|
||||
}
|
||||
}
|
||||
loadTemplate()
|
||||
}
|
||||
|
||||
func loadData() {
|
||||
appConfig = modules.LoadConfig()
|
||||
websiteData.Config = appConfig.Website
|
||||
websiteData.Language = modules.LoadLanguage(appConfig.Website.Language)
|
||||
websiteData.Contents = modules.LoadContent().Data
|
||||
|
||||
// Download icon to local and remove local ressources access
|
||||
for group := 0; group < len(websiteData.Contents); group++ {
|
||||
for col := 0; col < len(websiteData.Contents[group].Columns); col++ {
|
||||
for bookmark := 0; bookmark < len(websiteData.Contents[group].Columns[col].Bookmarks); bookmark++ {
|
||||
bookmarkData := websiteData.Contents[group].Columns[col].Bookmarks[bookmark]
|
||||
if bookmarkData.IsImage() || bookmarkData.IsSVG() {
|
||||
iconPath := bookmarkData.Icon
|
||||
fileName := path.Base(iconPath)
|
||||
if modules.DownloadFile(iconPath, filepath.Join(pwd, "data", "icon", fileName)) {
|
||||
websiteData.Contents[group].Columns[col].Bookmarks[bookmark].Icon = "/common/icon/" + fileName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loadTemplate()
|
||||
}
|
||||
|
||||
func loadTemplate() {
|
||||
themeDir = filepath.Join(pwd, "themes", appConfig.Website.Theme)
|
||||
tmpl, _ := template.ParseFiles(filepath.Join(themeDir, "index.html"))
|
||||
webTemplate = tmpl
|
||||
modules.CopyDir(filepath.Join(modules.CurrentPath(), "common"), dataPath, false)
|
||||
}
|
||||
|
||||
func loadAddons() {
|
||||
for i := 0; i < len(appConfig.Addons); i++ {
|
||||
switch addonName := appConfig.Addons[i]; addonName {
|
||||
for i := 0; i < len(modules.AppConfig.Addons); i++ {
|
||||
switch addonName := modules.AppConfig.Addons[i]; addonName {
|
||||
case "docker":
|
||||
docker.Setup()
|
||||
case "health-check-server":
|
||||
|
@ -132,89 +59,3 @@ func loadAddons() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func watchChanges() {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Println("Modified file:", event.Name)
|
||||
loadData()
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Println("error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
watcher.Add(filepath.Join(pwd, "data", "data.yaml"))
|
||||
watcher.Add(filepath.Join(pwd, "data", "config.yaml"))
|
||||
watcher.Add(filepath.Join(pwd, "themes", appConfig.Website.Theme, "index.html"))
|
||||
<-done
|
||||
}
|
||||
|
||||
func ClientIsLocal(r *http.Request) bool {
|
||||
IPAddress := net.ParseIP(r.Header.Get("X-Real-Ip"))
|
||||
if IPAddress == nil {
|
||||
IPAddress = net.ParseIP(r.Header.Get("X-Forwarded-For"))
|
||||
}
|
||||
if IPAddress == nil {
|
||||
IPAddress = net.ParseIP(strings.Split(r.RemoteAddr, ":")[0])
|
||||
}
|
||||
return IPAddress.IsPrivate()
|
||||
}
|
||||
|
||||
func serveTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
if ! ClientIsLocal(r) {
|
||||
pruneData()
|
||||
} else {
|
||||
loadData()
|
||||
}
|
||||
webTemplate.Execute(w, websiteData)
|
||||
}
|
||||
|
||||
type themeHandler struct {
|
||||
format string
|
||||
}
|
||||
|
||||
func (th themeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, strings.Replace(r.URL.Path, "/theme", themeDir, 1))
|
||||
}
|
||||
|
||||
var weatherTimeOut int64
|
||||
var weatherCache []byte
|
||||
|
||||
func serveWeather(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if appConfig.OpenWeatherMap.ApiKey == "demo" {
|
||||
w.Write([]byte("{\"coord\":{\"lon\":105.8085,\"lat\":21.0427},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"base\":\"stations\",\"main\":{\"temp\":301.14,\"feels_like\":305.69,\"temp_min\":301.14,\"temp_max\":301.14,\"pressure\":1004,\"humidity\":83},\"visibility\":10000,\"wind\":{\"speed\":6.17,\"deg\":120},\"clouds\":{\"all\":75},\"dt\":1650981392,\"sys\":{\"type\":1,\"id\":9308,\"country\":\"VN\",\"sunrise\":1650925786,\"sunset\":1650971952},\"timezone\":25200,\"id\":1581130,\"name\":\"Hanoi\",\"cod\":200}"))
|
||||
} else {
|
||||
if time.Now().UnixMilli() >= weatherTimeOut {
|
||||
resp, err := http.Get("https://api.openweathermap.org/data/2.5/weather?lat=" + appConfig.OpenWeatherMap.Latitude + "&lon=" + appConfig.OpenWeatherMap.Longitude + "&limit=1&appid=" + appConfig.OpenWeatherMap.ApiKey)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return
|
||||
}
|
||||
weatherCache = body
|
||||
weatherTimeOut = time.Now().UnixMilli() + 1800000
|
||||
}
|
||||
w.Write(weatherCache)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package modules
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
@ -29,7 +28,9 @@ type OpenWeatherMapConfig struct {
|
|||
Latitude string `yaml:"lat"`
|
||||
}
|
||||
|
||||
func LoadConfig() Config {
|
||||
var AppConfig Config
|
||||
|
||||
func LoadConfig() {
|
||||
defaultConfig := Config{
|
||||
Website: WebsiteConfig{
|
||||
Title: "Magma Dashboard",
|
||||
|
@ -41,20 +42,21 @@ func LoadConfig() Config {
|
|||
},
|
||||
Addons: []string{},
|
||||
}
|
||||
AppConfig = defaultConfig
|
||||
|
||||
yamlFile, err := ioutil.ReadFile(filepath.Join("data", "config.yaml"))
|
||||
yamlFile, err := ReadFile(filepath.Join("data", "config.yaml"))
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading YAML file: %s\n", err)
|
||||
return defaultConfig
|
||||
return
|
||||
}
|
||||
|
||||
var yamlConfig Config
|
||||
err = yaml.Unmarshal(yamlFile, &yamlConfig)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing YAML file: %s\n", err)
|
||||
return defaultConfig
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Loaded config:", yamlConfig)
|
||||
return yamlConfig
|
||||
AppConfig = yamlConfig
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package modules
|
|||
import (
|
||||
"fmt"
|
||||
"index/suffixarray"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
@ -28,16 +27,17 @@ type ColumnData struct {
|
|||
}
|
||||
|
||||
type BookmarkData struct {
|
||||
Name string `yaml:"name"`
|
||||
Url string `yaml:"url"`
|
||||
Icon string `yaml:"icon"`
|
||||
IsLocal bool `yaml:"isLocal"`
|
||||
Name string `yaml:"name"`
|
||||
Url string `yaml:"url"`
|
||||
UrlLocal string `yaml:"urlLocal"`
|
||||
Icon string `yaml:"icon"`
|
||||
IsLocal bool `yaml:"isLocal"`
|
||||
}
|
||||
|
||||
func LoadContent() ContentData {
|
||||
emptyData := ContentData{}
|
||||
|
||||
yamlFile, err := ioutil.ReadFile(filepath.Join("data", "data.yaml"))
|
||||
yamlFile, err := ReadFile(filepath.Join("data", "data.yaml"))
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading YAML file: %s\n", err)
|
||||
return emptyData
|
||||
|
|
|
@ -7,6 +7,15 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
var pwd string
|
||||
|
||||
func CurrentPath() string {
|
||||
if len(pwd) <= 0 {
|
||||
pwd, _ = os.Getwd()
|
||||
}
|
||||
return pwd
|
||||
}
|
||||
|
||||
func Exists(path string) bool {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
return true
|
||||
|
@ -14,12 +23,20 @@ func Exists(path string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func ReadFile(path string) ([]byte, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
return io.ReadAll(file)
|
||||
}
|
||||
|
||||
func CopyFile(source string, dest string) (err error) {
|
||||
sourcefile, err := os.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer sourcefile.Close()
|
||||
|
||||
destfile, err := os.Create(dest)
|
||||
|
@ -33,7 +50,7 @@ func CopyFile(source string, dest string) (err error) {
|
|||
if err == nil {
|
||||
sourceinfo, err := os.Stat(source)
|
||||
if err != nil {
|
||||
err = os.Chmod(dest, sourceinfo.Mode())
|
||||
_ = os.Chmod(dest, sourceinfo.Mode())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,12 +2,17 @@ package modules
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func SetupLanguage(mux *http.ServeMux) {
|
||||
languagefs := http.FileServer(http.Dir(filepath.Join(CurrentPath(), "languages")))
|
||||
mux.Handle("/languages/", http.StripPrefix("/languages/", languagefs))
|
||||
}
|
||||
|
||||
type Language struct {
|
||||
Greeting LanguageGreeting `yaml:"greeting"`
|
||||
Weather LanguageWeather `yaml:"weather"`
|
||||
|
@ -36,7 +41,7 @@ type LanguageWeather struct {
|
|||
}
|
||||
|
||||
func LoadLanguage(language string) Language {
|
||||
yamlFile, err := ioutil.ReadFile(filepath.Join("languages", language+".yaml"))
|
||||
yamlFile, err := ReadFile(filepath.Join("languages", language+".yaml"))
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading YAML file: %s\n", err)
|
||||
return LoadLanguage("en")
|
||||
|
|
18
src/modules/network.go
Normal file
18
src/modules/network.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ClientIsLocal(r *http.Request) bool {
|
||||
IPAddress := net.ParseIP(r.Header.Get("X-Real-Ip"))
|
||||
if IPAddress == nil {
|
||||
IPAddress = net.ParseIP(r.Header.Get("X-Forwarded-For"))
|
||||
}
|
||||
if IPAddress == nil {
|
||||
IPAddress = net.ParseIP(strings.Split(r.RemoteAddr, ":")[0])
|
||||
}
|
||||
return IPAddress.IsPrivate()
|
||||
}
|
159
src/modules/template.go
Normal file
159
src/modules/template.go
Normal file
|
@ -0,0 +1,159 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
func SetupTemplate(mux *http.ServeMux) {
|
||||
loadData()
|
||||
go watchChanges()
|
||||
|
||||
commonfs := http.FileServer(http.Dir(filepath.Join(CurrentPath(), "data")))
|
||||
mux.Handle("/common/", http.StripPrefix("/common/", commonfs))
|
||||
|
||||
th := themeHandler{}
|
||||
mux.Handle("/theme/", th)
|
||||
|
||||
mux.HandleFunc("/", serveTemplate)
|
||||
}
|
||||
|
||||
var websiteData = struct {
|
||||
Config WebsiteConfig
|
||||
Language Language
|
||||
Contents []GroupData
|
||||
IsLocal bool
|
||||
}{}
|
||||
var privateContent []GroupData
|
||||
var publicContent []GroupData
|
||||
var webTemplate *template.Template
|
||||
|
||||
func loadData() {
|
||||
LoadConfig()
|
||||
websiteData.Config = AppConfig.Website
|
||||
websiteData.Language = LoadLanguage(AppConfig.Website.Language)
|
||||
websiteData.Contents = LoadContent().Data
|
||||
loadTemplate()
|
||||
|
||||
// Download icon to local and remove local ressources access
|
||||
for groupIndex := 0; groupIndex < len(websiteData.Contents); groupIndex++ {
|
||||
group := websiteData.Contents[groupIndex]
|
||||
groupDataPublic := []ColumnData{}
|
||||
groupDataPrivate := []ColumnData{}
|
||||
|
||||
for colIndex := 0; colIndex < len(group.Columns); colIndex++ {
|
||||
column := group.Columns[colIndex]
|
||||
columnDataPublic := []BookmarkData{}
|
||||
columnDataPrivate := []BookmarkData{}
|
||||
|
||||
for bookmarkIndex := 0; bookmarkIndex < len(column.Bookmarks); bookmarkIndex++ {
|
||||
bookmarkData := column.Bookmarks[bookmarkIndex]
|
||||
iconPath := bookmarkData.Icon
|
||||
|
||||
//download icon
|
||||
if bookmarkData.IsImage() || bookmarkData.IsSVG() {
|
||||
fileName := path.Base(iconPath)
|
||||
if DownloadFile(iconPath, filepath.Join(CurrentPath(), "data", "icon", fileName)) {
|
||||
iconPath = "/common/icon/" + fileName
|
||||
}
|
||||
}
|
||||
|
||||
//add to private array
|
||||
url := bookmarkData.Url
|
||||
if len(bookmarkData.UrlLocal) > 0 {
|
||||
url = bookmarkData.UrlLocal
|
||||
}
|
||||
if len(url) > 0 {
|
||||
columnDataPrivate = append(columnDataPrivate, BookmarkData{bookmarkData.Name, url, bookmarkData.UrlLocal, iconPath, true})
|
||||
}
|
||||
|
||||
//add to public array
|
||||
if !bookmarkData.IsLocal && len(bookmarkData.Url) > 0 {
|
||||
columnDataPublic = append(columnDataPublic, BookmarkData{bookmarkData.Name, bookmarkData.Url, bookmarkData.UrlLocal, iconPath, false})
|
||||
}
|
||||
}
|
||||
|
||||
if len(columnDataPublic) > 0 {
|
||||
groupDataPublic = append(groupDataPublic, ColumnData{column.Title, columnDataPublic, column.Icon})
|
||||
}
|
||||
if len(columnDataPrivate) > 0 {
|
||||
groupDataPrivate = append(groupDataPrivate, ColumnData{column.Title, columnDataPrivate, column.Icon})
|
||||
}
|
||||
}
|
||||
|
||||
if len(groupDataPublic) > 0 {
|
||||
publicContent = append(publicContent, GroupData{group.Title, groupDataPublic, group.Icon})
|
||||
}
|
||||
if len(groupDataPrivate) > 0 {
|
||||
privateContent = append(privateContent, GroupData{group.Title, groupDataPrivate, group.Icon})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var themeDir string
|
||||
|
||||
type themeHandler struct {
|
||||
format string
|
||||
}
|
||||
|
||||
func (th themeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
newPath := strings.Replace(r.URL.Path, "/theme", themeDir, 1)
|
||||
fmt.Println(newPath)
|
||||
http.ServeFile(w, r, newPath)
|
||||
}
|
||||
|
||||
func loadTemplate() {
|
||||
themeDir = filepath.Join(CurrentPath(), "themes", AppConfig.Website.Theme)
|
||||
tmpl, _ := template.ParseFiles(filepath.Join(themeDir, "index.html"))
|
||||
webTemplate = tmpl
|
||||
}
|
||||
|
||||
func serveTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
websiteData.IsLocal = ClientIsLocal(r)
|
||||
if websiteData.IsLocal {
|
||||
websiteData.Contents = privateContent
|
||||
} else {
|
||||
websiteData.Contents = publicContent
|
||||
}
|
||||
webTemplate.Execute(w, websiteData)
|
||||
}
|
||||
|
||||
func watchChanges() {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Println("Modified file:", event.Name)
|
||||
loadData()
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Println("error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
watcher.Add(filepath.Join(CurrentPath(), "data", "data.yaml"))
|
||||
watcher.Add(filepath.Join(CurrentPath(), "data", "config.yaml"))
|
||||
watcher.Add(filepath.Join(CurrentPath(), "themes", AppConfig.Website.Theme, "index.html"))
|
||||
<-done
|
||||
}
|
46
src/modules/weather.go
Normal file
46
src/modules/weather.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SetupWeather(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/weather", serveWeather)
|
||||
}
|
||||
|
||||
func serveWeather(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
data := GetWeather(AppConfig.OpenWeatherMap.ApiKey, AppConfig.OpenWeatherMap.Latitude, AppConfig.OpenWeatherMap.Longitude)
|
||||
if data != nil {
|
||||
w.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
var weatherTimeOut int64
|
||||
var weatherCache []byte
|
||||
var demoData = []byte("{\"coord\":{\"lon\":105.8085,\"lat\":21.0427},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"base\":\"stations\",\"main\":{\"temp\":301.14,\"feels_like\":305.69,\"temp_min\":301.14,\"temp_max\":301.14,\"pressure\":1004,\"humidity\":83},\"visibility\":10000,\"wind\":{\"speed\":6.17,\"deg\":120},\"clouds\":{\"all\":75},\"dt\":1650981392,\"sys\":{\"type\":1,\"id\":9308,\"country\":\"VN\",\"sunrise\":1650925786,\"sunset\":1650971952},\"timezone\":25200,\"id\":1581130,\"name\":\"Hanoi\",\"cod\":200}")
|
||||
|
||||
func GetWeather(apiKey string, latitude string, longitude string) []byte {
|
||||
if apiKey == "demo" {
|
||||
return demoData
|
||||
} else {
|
||||
if time.Now().UnixMilli() >= weatherTimeOut {
|
||||
resp, err := http.Get("https://api.openweathermap.org/data/2.5/weather?lat=" + latitude + "&lon=" + longitude + "&limit=1&appid=" + apiKey)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return nil
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return nil
|
||||
}
|
||||
weatherCache = body
|
||||
weatherTimeOut = time.Now().UnixMilli() + 1800000
|
||||
}
|
||||
return weatherCache
|
||||
}
|
||||
}
|
|
@ -91,8 +91,8 @@
|
|||
<script src="/common/js/core.js"></script>
|
||||
<script>
|
||||
window.config = {
|
||||
localization: {{.Config.Localization}},
|
||||
language: {{.Config.Language}},
|
||||
localization: '{{.Config.Localization}}',
|
||||
language: '{{.Config.Language}}',
|
||||
useMetric: {{.Config.UseMetric}}
|
||||
};
|
||||
|
||||
|
@ -107,16 +107,16 @@
|
|||
const greeting = document.querySelector("#greeting");
|
||||
const hour = new Date().getHours();
|
||||
if (hour >= 5 && hour < 12) {
|
||||
greeting.innerText = {{.Language.Greeting.Morning}};
|
||||
greeting.innerText = '{{.Language.Greeting.Morning}}'
|
||||
}
|
||||
else if (hour >= 12 && hour < 17) {
|
||||
greeting.innerText = {{.Language.Greeting.Afternoon}};
|
||||
greeting.innerText = '{{.Language.Greeting.Afternoon}}'
|
||||
}
|
||||
else if (hour >= 17 && hour < 20) {
|
||||
greeting.innerText = {{.Language.Greeting.Evening}};
|
||||
greeting.innerText = '{{.Language.Greeting.Evening}}'
|
||||
}
|
||||
else {
|
||||
greeting.innerText = {{.Language.Greeting.Night}};
|
||||
greeting.innerText = '{{.Language.Greeting.Night}}'
|
||||
}
|
||||
}) ();
|
||||
|
||||
|
|
|
@ -90,8 +90,8 @@
|
|||
<script src="/common/js/core.js"></script>
|
||||
<script>
|
||||
window.config = {
|
||||
localization: {{.Config.Localization}},
|
||||
language: {{.Config.Language}},
|
||||
localization: '{{.Config.Localization}}',
|
||||
language: '{{.Config.Language}}',
|
||||
useMetric: {{.Config.UseMetric}}
|
||||
};
|
||||
|
||||
|
@ -109,16 +109,16 @@
|
|||
const greeting = document.querySelector("#greeting");
|
||||
const hour = new Date().getHours();
|
||||
if (hour >= 5 && hour < 12) {
|
||||
greeting.innerText = {{.Language.Greeting.Morning}};
|
||||
greeting.innerText = '{{.Language.Greeting.Morning}}'
|
||||
}
|
||||
else if (hour >= 12 && hour < 17) {
|
||||
greeting.innerText = {{.Language.Greeting.Afternoon}};
|
||||
greeting.innerText = '{{.Language.Greeting.Afternoon}}'
|
||||
}
|
||||
else if (hour >= 17 && hour < 20) {
|
||||
greeting.innerText = {{.Language.Greeting.Evening}};
|
||||
greeting.innerText = '{{.Language.Greeting.Evening}}'
|
||||
}
|
||||
else {
|
||||
greeting.innerText = {{.Language.Greeting.Night}};
|
||||
greeting.innerText = '{{.Language.Greeting.Night}}'
|
||||
}
|
||||
}) ();
|
||||
|
||||
|
|
|
@ -44,24 +44,24 @@
|
|||
<script src="/common/js/core.js"></script>
|
||||
<script>
|
||||
window.config = {
|
||||
localization: {{.Config.Localization}},
|
||||
language: {{.Config.Language}},
|
||||
localization: '{{.Config.Localization}}',
|
||||
language: '{{.Config.Language}}',
|
||||
useMetric: {{.Config.UseMetric}}
|
||||
};
|
||||
(function setTimer() {
|
||||
const greeting = document.querySelector("#greeting");
|
||||
const hour = new Date().getHours();
|
||||
if (hour >= 5 && hour < 12) {
|
||||
greeting.innerText = {{.Language.Greeting.Morning}};
|
||||
greeting.innerText = '{{.Language.Greeting.Morning}}'
|
||||
}
|
||||
else if (hour >= 12 && hour < 17) {
|
||||
greeting.innerText = {{.Language.Greeting.Afternoon}};
|
||||
greeting.innerText = '{{.Language.Greeting.Afternoon}}'
|
||||
}
|
||||
else if (hour >= 17 && hour < 20) {
|
||||
greeting.innerText = {{.Language.Greeting.Evening}};
|
||||
greeting.innerText = '{{.Language.Greeting.Evening}}'
|
||||
}
|
||||
else {
|
||||
greeting.innerText = {{.Language.Greeting.Night}};
|
||||
greeting.innerText = '{{.Language.Greeting.Night}}'
|
||||
}
|
||||
}) ();
|
||||
</script>
|
||||
|
|
Loading…
Add table
Reference in a new issue