diff --git a/.gitignore b/.gitignore
index 618f0c4..a35805a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-config.json
+config.json
restart.sh
\ No newline at end of file
diff --git a/assets/css/styles.css b/assets/css/styles.css
index 61dada0..da2d645 100644
--- a/assets/css/styles.css
+++ b/assets/css/styles.css
@@ -1,57 +1,57 @@
-/* Design idea from here https://mo.rijndael.cc/ */
-
-body {
- display: flex;
- flex-wrap: wrap;
- margin: 0;
- align-items: flex-start;
- padding: 10px;
-}
-
-header, main, footer {
- margin: 5px;
- display: flex;
- flex-direction: column;
- gap: 10px;
-}
-
-header, footer {
- flex: 2;
-}
-
-main {
- flex: 3;
-}
-
-header > div,
-footer > div,
-main > div {
- box-shadow: 5px 5px 0 0 lightgrey;
- box-sizing: border-box;
- border: 1px solid;
- width: 100%;
- text-align: center;
- color: black;
- padding-left: 10px;
- padding-right: 10px;
-}
-
-header > div > ul,
-footer > div > ul,
-main > div > ul {
- text-align: left;
-}
-
-header > div > h1,
-footer > div > h1,
-main > div > h1 {
- box-sizing: border-box;
- border-top: 1px solid;
- border-bottom: 1px solid;
-}
-
-@media (max-width: 1200px) {
- header, footer, main {
- flex: 1 100%;
- }
+/* Design idea from here https://mo.rijndael.cc/ */
+
+body {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 0;
+ align-items: flex-start;
+ padding: 10px;
+}
+
+header, main, footer {
+ margin: 5px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+header, footer {
+ flex: 2;
+}
+
+main {
+ flex: 3;
+}
+
+header > div,
+footer > div,
+main > div {
+ box-shadow: 5px 5px 0 0 lightgrey;
+ box-sizing: border-box;
+ border: 1px solid;
+ width: 100%;
+ text-align: center;
+ color: black;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+header > div > ul,
+footer > div > ul,
+main > div > ul {
+ text-align: left;
+}
+
+header > div > h1,
+footer > div > h1,
+main > div > h1 {
+ box-sizing: border-box;
+ border-top: 1px solid;
+ border-bottom: 1px solid;
+}
+
+@media (max-width: 1200px) {
+ header, footer, main {
+ flex: 1 100%;
+ }
}
\ No newline at end of file
diff --git a/main.go b/main.go
index 93322a6..88421ad 100644
--- a/main.go
+++ b/main.go
@@ -1,73 +1,73 @@
-package main
-
-import (
- "fmt"
- "log"
- "main/mvc/controllers"
- controllers_pages "main/mvc/controllers/pages"
- "main/mvc/models"
- "main/tools"
- "net/http"
-)
-
-func main() {
- var app *models.App
- var err error
-
- // Инициализация приложения
- if app, err = models.AppInit("config.json"); err != nil {
- log.Fatal(err)
- }
-
- // Добавление префикса в виде домена сервера к записям в лог
- log.SetPrefix(fmt.Sprintf("%s | ", app.Config.ServerDomain))
-
- // Настройка маршрутов и запуск
- if setupRoutesAndRun(app) != nil {
- log.Fatal(err)
- }
-}
-
-func setupRoutesAndRun(a *models.App) error {
- // Настройка маршрутов
- router := setupRoutes(a)
-
- // Запуск сервера
- if ok, err := tools.IsIPInUse(a.Config.ServerIP); err != nil {
- return err
- } else if ok {
- runServer(a.Config.ServerIP, a.Config.Port, router)
- } else {
- runServer(a.Config.LocalIP, a.Config.Port, router)
- }
-
- return nil
-}
-
-// Настраивает маршруты
-func setupRoutes(a *models.App) *http.ServeMux {
- router := http.NewServeMux()
-
- // Цепочка обработчиков, которые сработают до отдачи страницы юзеру
- m := controllers.MiddlewaresChain
-
- // Обработка статических файлов
- router.Handle(a.Config.AssetsPath, m(controllers.StaticHandler()))
-
- // Странички
- {
- // Обработка главной страницы (русская версия)
- router.Handle("/ru/", m(controllers_pages.MainRuPageHandler(a)))
- // Обработка главной страницы
- router.Handle("/", m(controllers_pages.MainPageHandler(a)))
- }
-
- return router
-}
-
-// Обертка над ListenAndServe, запускает сервер на указанном IP, PORT
-func runServer(ip, port string, router http.Handler) {
- addr := ip + port
- log.Println("Run on", addr)
- log.Fatal(http.ListenAndServe(addr, router))
-}
+package main
+
+import (
+ "fmt"
+ "log"
+ "main/mvc/controllers"
+ controllers_pages "main/mvc/controllers/pages"
+ "main/mvc/models"
+ "main/tools"
+ "net/http"
+)
+
+func main() {
+ var app *models.App
+ var err error
+
+ // Инициализация приложения
+ if app, err = models.AppInit("config.json"); err != nil {
+ log.Fatal(err)
+ }
+
+ // Добавление префикса в виде домена сервера к записям в лог
+ log.SetPrefix(fmt.Sprintf("%s | ", app.Config.ServerDomain))
+
+ // Настройка маршрутов и запуск
+ if setupRoutesAndRun(app) != nil {
+ log.Fatal(err)
+ }
+}
+
+func setupRoutesAndRun(a *models.App) error {
+ // Настройка маршрутов
+ router := setupRoutes(a)
+
+ // Запуск сервера
+ if ok, err := tools.IsIPInUse(a.Config.ServerIP); err != nil {
+ return err
+ } else if ok {
+ runServer(a.Config.ServerIP, a.Config.Port, router)
+ } else {
+ runServer(a.Config.LocalIP, a.Config.Port, router)
+ }
+
+ return nil
+}
+
+// Настраивает маршруты
+func setupRoutes(a *models.App) *http.ServeMux {
+ router := http.NewServeMux()
+
+ // Цепочка обработчиков, которые сработают до отдачи страницы юзеру
+ m := controllers.MiddlewaresChain
+
+ // Обработка статических файлов
+ router.Handle(a.Config.AssetsPath, m(controllers.StaticHandler()))
+
+ // Странички
+ {
+ // Обработка главной страницы (русская версия)
+ router.Handle("/ru/", m(controllers_pages.MainRuPageHandler(a)))
+ // Обработка главной страницы
+ router.Handle("/", m(controllers_pages.MainPageHandler(a)))
+ }
+
+ return router
+}
+
+// Запускает сервер на указанном IP, PORT
+func runServer(ip, port string, router http.Handler) {
+ addr := ip + port
+ log.Println("Run on", addr)
+ log.Fatal(http.ListenAndServe(addr, router))
+}
diff --git a/mvc/controllers/middlewares.go b/mvc/controllers/middlewares.go
index 9f52b6f..64c79d3 100644
--- a/mvc/controllers/middlewares.go
+++ b/mvc/controllers/middlewares.go
@@ -1,43 +1,43 @@
-package controllers
-
-import (
- "log"
- "net/http"
- "time"
-)
-
-type Middleware func(http.Handler) http.Handler
-
-var (
- MiddlewaresChain = CreateMiddlewaresChain(
- LoggingMiddleware,
- )
-)
-
-/*
-Возвращает один middleware, который объединяет все переданные
-
-CreateMiddlewaresChain(m1, m2, m3)
-= func(next http.Handler) http.Handler { return m1(m2(m3(final))) }
-
-CreateMiddlewaresChain(LoggingMiddleware)
-= func(next http.Handler) http.Handler { return LoggingMiddleware(final) }
-*/
-func CreateMiddlewaresChain(middlewares ...Middleware) Middleware {
- return func(final http.Handler) http.Handler {
- for i := len(middlewares) - 1; i >= 0; i-- {
- final = middlewares[i](final)
- }
- return final
- }
-}
-
-func LoggingMiddleware(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- start := time.Now()
-
- next.ServeHTTP(w, r)
-
- log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
- })
-}
+package controllers
+
+import (
+ "log"
+ "net/http"
+ "time"
+)
+
+type Middleware func(http.Handler) http.Handler
+
+var (
+ MiddlewaresChain = CreateMiddlewaresChain(
+ LoggingMiddleware,
+ )
+)
+
+/*
+Возвращает один middleware, который объединяет все переданные
+
+CreateMiddlewaresChain(m1, m2, m3)
+= func(next http.Handler) http.Handler { return m1(m2(m3(final))) }
+
+CreateMiddlewaresChain(LoggingMiddleware)
+= func(next http.Handler) http.Handler { return LoggingMiddleware(final) }
+*/
+func CreateMiddlewaresChain(middlewares ...Middleware) Middleware {
+ return func(final http.Handler) http.Handler {
+ for i := len(middlewares) - 1; i >= 0; i-- {
+ final = middlewares[i](final)
+ }
+ return final
+ }
+}
+
+func LoggingMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ start := time.Now()
+
+ next.ServeHTTP(w, r)
+
+ log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
+ })
+}
diff --git a/mvc/controllers/pages/main.go b/mvc/controllers/pages/main.go
index 2a4f757..890a169 100644
--- a/mvc/controllers/pages/main.go
+++ b/mvc/controllers/pages/main.go
@@ -1,82 +1,82 @@
-package controllers
-
-import (
- "log"
- "main/mvc/models"
- models_pages "main/mvc/models/pages"
- "main/tools"
- "net/http"
-)
-
-// Обработчик главной страницы
-func MainPageHandler(a *models.App) http.HandlerFunc {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-
- var err error
-
- // Количество запросов, обработанных сервером за 24ч
- if r.Method == "COUNT" {
- var count []byte
- if count, err = tools.GetJournalctlLogsCount("server", a.Config.ServerDomain, 24); err != nil {
- log.Printf("%s", err.Error())
- }
- SendCount(w, count)
- return
- }
-
- // Пасхалка
- if r.Method == "LOVE" {
- SendLove(w)
- return
- }
-
- // Пасхалка 2
- if r.Method == "LIMINAL" {
- SendLiminal(w)
- return
- }
-
- // Страничка рендерится только если ее нет в кэше
- pageData, ok := a.Cache.Get(models_pages.MainPageTmplName)
- if !ok {
- pageData, err = models_pages.RenderMainPage(a.Templates, a.Version)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- a.Cache.Set(models_pages.MainPageTmplName, pageData)
- }
-
- SendMainPage(w, pageData.([]byte))
- })
-}
-
-// Отправляет страницу
-func SendMainPage(w http.ResponseWriter, data []byte) {
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- w.Write(data)
-}
-
-// Ответ на метод COUNT
-func SendCount(w http.ResponseWriter, data []byte) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- w.Write(data)
-}
-
-// Ответ на метод LOVE
-func SendLove(w http.ResponseWriter) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- w.Write([]byte("13.01.2005\n"))
-}
-
-// Ответ на метод LIMINAL
-func SendLiminal(w http.ResponseWriter) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- text := "If you're not careful and you slip out of reality in the wrong place, you'll end up in the Backstage, where there's nothing but the stench of old damp carpet, yellow-colored madness, the endless unbearable hum of fluorescent lights, and roughly six hundred million square miles of randomly arranged empty rooms.\n"
- w.Write([]byte(text))
-
-}
+package controllers
+
+import (
+ "log"
+ "main/mvc/models"
+ models_pages "main/mvc/models/pages"
+ "main/tools"
+ "net/http"
+)
+
+// Обработчик главной страницы
+func MainPageHandler(a *models.App) http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+
+ // Количество запросов, обработанных сервером за 24ч
+ if r.Method == "COUNT" {
+ var count []byte
+ if count, err = tools.GetJournalctlLogsCount("server", a.Config.ServerDomain, 24); err != nil {
+ log.Printf("%s", err.Error())
+ }
+ SendCount(w, count)
+ return
+ }
+
+ // Пасхалка
+ if r.Method == "LOVE" {
+ SendLove(w)
+ return
+ }
+
+ // Пасхалка 2
+ if r.Method == "LIMINAL" {
+ SendLiminal(w)
+ return
+ }
+
+ // Страничка рендерится только если ее нет в кэше
+ pageData, ok := a.Cache.Get(models_pages.MainPageTmplName)
+ if !ok {
+ pageData, err = models_pages.RenderMainPage(a.Templates, a.Version)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ a.Cache.Set(models_pages.MainPageTmplName, pageData)
+ }
+
+ SendMainPage(w, pageData.([]byte))
+ })
+}
+
+// Отправляет страницу
+func SendMainPage(w http.ResponseWriter, data []byte) {
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ w.Write(data)
+}
+
+// Ответ на метод COUNT
+func SendCount(w http.ResponseWriter, data []byte) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ w.Write(data)
+}
+
+// Ответ на метод LOVE
+func SendLove(w http.ResponseWriter) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte("13.01.2005\n"))
+}
+
+// Ответ на метод LIMINAL
+func SendLiminal(w http.ResponseWriter) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ text := "If you're not careful and you slip out of reality in the wrong place, you'll end up in the Backstage, where there's nothing but the stench of old damp carpet, yellow-colored madness, the endless unbearable hum of fluorescent lights, and roughly six hundred million square miles of randomly arranged empty rooms.\n"
+ w.Write([]byte(text))
+
+}
diff --git a/mvc/controllers/pages/main_ru.go b/mvc/controllers/pages/main_ru.go
index 6f67a13..b2a5da1 100644
--- a/mvc/controllers/pages/main_ru.go
+++ b/mvc/controllers/pages/main_ru.go
@@ -1,34 +1,34 @@
-package controllers
-
-import (
- "main/mvc/models"
- models_pages "main/mvc/models/pages"
- "net/http"
-)
-
-// Обработчик главной страницы
-func MainRuPageHandler(a *models.App) http.HandlerFunc {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- var err error
-
- // Страничка рендерится только если ее нет в кэше
- pageData, ok := a.Cache.Get(models_pages.MainRuPageTmplName)
- if !ok {
- pageData, err = models_pages.RenderMainRuPage(a.Templates, a.Version)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- a.Cache.Set(models_pages.MainRuPageTmplName, pageData)
- }
-
- SendMainPage(w, pageData.([]byte))
- })
-}
-
-// Отправляет страницу
-func SendMainRuPage(w http.ResponseWriter, data []byte) {
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- w.Write(data)
-}
+package controllers
+
+import (
+ "main/mvc/models"
+ models_pages "main/mvc/models/pages"
+ "net/http"
+)
+
+// Обработчик главной страницы
+func MainRuPageHandler(a *models.App) http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ var err error
+
+ // Страничка рендерится только если ее нет в кэше
+ pageData, ok := a.Cache.Get(models_pages.MainRuPageTmplName)
+ if !ok {
+ pageData, err = models_pages.RenderMainRuPage(a.Templates, a.Version)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ a.Cache.Set(models_pages.MainRuPageTmplName, pageData)
+ }
+
+ SendMainPage(w, pageData.([]byte))
+ })
+}
+
+// Отправляет страницу
+func SendMainRuPage(w http.ResponseWriter, data []byte) {
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ w.Write(data)
+}
diff --git a/mvc/controllers/static.go b/mvc/controllers/static.go
index 28f346f..34c34ec 100644
--- a/mvc/controllers/static.go
+++ b/mvc/controllers/static.go
@@ -1,14 +1,14 @@
-package controllers
-
-import "net/http"
-
-// Обработчик статических файлов с кэшированием
-func StaticHandler() http.HandlerFunc {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // Здесь используется встроенный файловый сервер Go (http.FileServer), который:
- // Реализует интерфейс http.Handler (и поэтому имеет метод ServeHTTP)
- // Автоматически обслуживает статические файлы из файловой системы
- // Сам обрабатывает HTTP-запросы, определяет MIME-типы, отправляет правильные заголовки и т.д.
- http.FileServer(http.Dir(".")).ServeHTTP(w, r)
- })
-}
+package controllers
+
+import "net/http"
+
+// Обработчик статических файлов с кэшированием
+func StaticHandler() http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Здесь используется встроенный файловый сервер Go (http.FileServer), который:
+ // Реализует интерфейс http.Handler (и поэтому имеет метод ServeHTTP)
+ // Автоматически обслуживает статические файлы из файловой системы
+ // Сам обрабатывает HTTP-запросы, определяет MIME-типы, отправляет правильные заголовки и т.д.
+ http.FileServer(http.Dir(".")).ServeHTTP(w, r)
+ })
+}
diff --git a/mvc/models/app.go b/mvc/models/app.go
index 7b5515d..6638f97 100644
--- a/mvc/models/app.go
+++ b/mvc/models/app.go
@@ -1,65 +1,65 @@
-package models
-
-import (
- "html/template"
- "log"
- "os"
- "path/filepath"
- "strings"
- "time"
-)
-
-// App хранит информацию о приложении
-type App struct {
- Config *Config // Конфиг
- Templates *template.Template // Шаблоны страниц
- Cache *Cache // Кэш (отрендеренные странички)
- Version int64 // Время запуска
-}
-
-// Инициализирует приложение
-func AppInit(configPath string) (*App, error) {
-
- a := &App{
- Version: time.Now().Unix(),
- Config: ConfigInit(),
- Cache: CacheInit(),
- }
-
- // Загрузка конфига
- if err := a.Config.Load(configPath); err != nil {
- return nil, err
- }
-
- // Загрузка шаблонов
- if err := a.loadTemplates(a.Config.TemplatesPath, a.Config.TemplatesExt); err != nil {
- log.Fatal(err)
- }
-
- return a, nil
-}
-
-// Загрузка шаблонов
-func (a *App) loadTemplates(templatesPath string, ext string) error {
- tmpls := template.New("")
-
- err := filepath.Walk(templatesPath, func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if !f.IsDir() && strings.HasSuffix(f.Name(), ext) {
- _, err = tmpls.ParseFiles(path)
- if err != nil {
- return err
- }
- }
- return nil
- })
-
- if err != nil {
- return err
- }
-
- a.Templates = tmpls
- return nil
-}
+package models
+
+import (
+ "html/template"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+// App хранит информацию о приложении
+type App struct {
+ Config *Config // Конфиг
+ Templates *template.Template // Шаблоны страниц
+ Cache *Cache // Кэш (отрендеренные странички)
+ Version int64 // Время запуска
+}
+
+// Инициализирует приложение
+func AppInit(configPath string) (*App, error) {
+
+ a := &App{
+ Version: time.Now().Unix(),
+ Config: ConfigInit(),
+ Cache: CacheInit(),
+ }
+
+ // Загрузка конфига
+ if err := a.Config.Load(configPath); err != nil {
+ return nil, err
+ }
+
+ // Загрузка шаблонов
+ if err := a.loadTemplates(a.Config.TemplatesPath, a.Config.TemplatesExt); err != nil {
+ log.Fatal(err)
+ }
+
+ return a, nil
+}
+
+// Загрузка шаблонов
+func (a *App) loadTemplates(templatesPath string, ext string) error {
+ tmpls := template.New("")
+
+ err := filepath.Walk(templatesPath, func(path string, f os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !f.IsDir() && strings.HasSuffix(f.Name(), ext) {
+ _, err = tmpls.ParseFiles(path)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+
+ if err != nil {
+ return err
+ }
+
+ a.Templates = tmpls
+ return nil
+}
diff --git a/mvc/models/cache.go b/mvc/models/cache.go
index 5554aa6..585711b 100644
--- a/mvc/models/cache.go
+++ b/mvc/models/cache.go
@@ -1,25 +1,25 @@
-package models
-
-import "sync"
-
-type Cache struct {
- Data map[string]any
- Mu sync.RWMutex
-}
-
-func CacheInit() *Cache {
- return &Cache{Data: make(map[string]any)}
-}
-
-func (c *Cache) Get(key string) (any, bool) {
- c.Mu.RLock()
- pageData, ok := c.Data[key]
- c.Mu.RUnlock()
- return pageData, ok
-}
-
-func (c *Cache) Set(key string, data any) {
- c.Mu.Lock()
- c.Data[key] = data
- c.Mu.Unlock()
-}
+package models
+
+import "sync"
+
+type Cache struct {
+ Data map[string]any
+ Mu sync.RWMutex
+}
+
+func CacheInit() *Cache {
+ return &Cache{Data: make(map[string]any)}
+}
+
+func (c *Cache) Get(key string) (any, bool) {
+ c.Mu.RLock()
+ pageData, ok := c.Data[key]
+ c.Mu.RUnlock()
+ return pageData, ok
+}
+
+func (c *Cache) Set(key string, data any) {
+ c.Mu.Lock()
+ c.Data[key] = data
+ c.Mu.Unlock()
+}
diff --git a/mvc/models/config.go b/mvc/models/config.go
index ebfd160..31f5ba0 100644
--- a/mvc/models/config.go
+++ b/mvc/models/config.go
@@ -1,32 +1,32 @@
-package models
-
-import (
- "encoding/json"
- "os"
-)
-
-type Config struct {
- AssetsPath string
- TemplatesPath string
- TemplatesExt string
- LocalIP string
- ServerIP string
- ServerDomain string
- Port string
-}
-
-func ConfigInit() *Config {
- return &Config{}
-}
-
-func (c *Config) Load(configPath string) error {
- configFile, err := os.ReadFile(configPath)
- if err != nil {
- return err
- }
- err = json.Unmarshal(configFile, c)
- if err != nil {
- return err
- }
- return nil
-}
+package models
+
+import (
+ "encoding/json"
+ "os"
+)
+
+type Config struct {
+ AssetsPath string
+ TemplatesPath string
+ TemplatesExt string
+ LocalIP string
+ ServerIP string
+ ServerDomain string
+ Port string
+}
+
+func ConfigInit() *Config {
+ return &Config{}
+}
+
+func (c *Config) Load(configPath string) error {
+ configFile, err := os.ReadFile(configPath)
+ if err != nil {
+ return err
+ }
+ err = json.Unmarshal(configFile, c)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/mvc/models/pages/main.go b/mvc/models/pages/main.go
index fca61b6..f28ab1b 100644
--- a/mvc/models/pages/main.go
+++ b/mvc/models/pages/main.go
@@ -1,27 +1,27 @@
-package models
-
-import (
- "bytes"
- "html/template"
- "time"
-)
-
-const (
- // Имя соответствующего шаблона
- MainPageTmplName = "main.gohtml"
-)
-
-func RenderMainPage(templates *template.Template, version int64) ([]byte, error) {
- var pageData bytes.Buffer
-
- context := map[string]any{
- "version": version,
- "renderingTimestamp": time.Now().Unix(),
- }
-
- if err := templates.ExecuteTemplate(&pageData, MainPageTmplName, context); err != nil {
- return nil, err
- }
-
- return pageData.Bytes(), nil
-}
+package models
+
+import (
+ "bytes"
+ "html/template"
+ "time"
+)
+
+const (
+ // Имя соответствующего шаблона
+ MainPageTmplName = "main.gohtml"
+)
+
+func RenderMainPage(templates *template.Template, version int64) ([]byte, error) {
+ var pageData bytes.Buffer
+
+ context := map[string]any{
+ "version": version,
+ "renderingTimestamp": time.Now().Unix(),
+ }
+
+ if err := templates.ExecuteTemplate(&pageData, MainPageTmplName, context); err != nil {
+ return nil, err
+ }
+
+ return pageData.Bytes(), nil
+}
diff --git a/mvc/models/pages/main_ru.go b/mvc/models/pages/main_ru.go
index 8650fc5..80866ab 100644
--- a/mvc/models/pages/main_ru.go
+++ b/mvc/models/pages/main_ru.go
@@ -1,27 +1,27 @@
-package models
-
-import (
- "bytes"
- "html/template"
- "time"
-)
-
-const (
- // Имя соответствующего шаблона
- MainRuPageTmplName = "main_ru.gohtml"
-)
-
-func RenderMainRuPage(templates *template.Template, version int64) ([]byte, error) {
- var pageData bytes.Buffer
-
- context := map[string]any{
- "version": version,
- "renderingTimestamp": time.Now().Unix(),
- }
-
- if err := templates.ExecuteTemplate(&pageData, MainRuPageTmplName, context); err != nil {
- return nil, err
- }
-
- return pageData.Bytes(), nil
-}
+package models
+
+import (
+ "bytes"
+ "html/template"
+ "time"
+)
+
+const (
+ // Имя соответствующего шаблона
+ MainRuPageTmplName = "main_ru.gohtml"
+)
+
+func RenderMainRuPage(templates *template.Template, version int64) ([]byte, error) {
+ var pageData bytes.Buffer
+
+ context := map[string]any{
+ "version": version,
+ "renderingTimestamp": time.Now().Unix(),
+ }
+
+ if err := templates.ExecuteTemplate(&pageData, MainRuPageTmplName, context); err != nil {
+ return nil, err
+ }
+
+ return pageData.Bytes(), nil
+}
diff --git a/mvc/views/pages/main.gohtml b/mvc/views/pages/main.gohtml
index 1602c04..1eb6684 100644
--- a/mvc/views/pages/main.gohtml
+++ b/mvc/views/pages/main.gohtml
@@ -1,125 +1,125 @@
-
-
-
- hikan.ru
-
-
-
-
-
-
-
-
-
-
- $whoami
-
-
- my name is serr (you can easily guess my real name if you speak Russian :d), and i didn't come up with that nickname, i just started being called it
-
-
- i was born in 2003, i'm currently a cybersecurity major at university
-
-
- pronouns: he/him
-
-
-
-
- what do i do?
-
-
- programming is my everything - my job, my hobby, my lifestyle
-
-
- i love growing in all areas of programming - i am literally interested in everything: cybersecurity (chaotically breaking things, analyzing code, writing automated analyzers, and moving bytes back and forth), concurrency/multithreading, web development, low-level programming, cryptography and a lot more!
-
-
- i like the idea of symbolic /concolic execution and virtual code execution in general
-
-
-
-
- things i love
-
-
- coffee . i REALLY love coffee. almost any. and a lot of
- movies and TV series (especially TV series). i watch something almost every day
- true crime . i'm obsessed with serial killer cases, mysterious disappearances, unsolved murders - all that dark stuff
- russian underground rap like Slava KPSS, Zamay, MB Packet, Ovsyankin etc.
- simple and extensible code . i think if your code is overly complex, it means you are doing something wrong. most things are simpler than they seem
-
-
-
-
-
- nice links
-
-
- Mo , thx for design idea!
- huge collection of Xakep issues - 図書館.きく.コム
- i love this website highlighting the Small Web - smallweb
- very atmospheric forum about black metal - lycanthropia
-
-
-
-
-
-
-
-
-
- and also you can subscribe to my Telegram channel with pictures!
-
-
- digital countryside
-
-
-
-
- _some system information_
-
-
- unix timestamp of page rendering - {{ .renderingTimestamp }}
- curl -X COUNT https://hikan.ru
- 24-hour server request count
- curl -X LIMINAL https://hikan.ru
- what do you know about liminal spaces?
- this site code repository - git.hikan.ru/serr/hikan.ru
-
-
-
-
- this site is written in Go without using frameworks, hosting is hostetski , domain bought for the price of a can of beer
-
-
- 2024 - now
-
-
-
-
+
+
+
+ hikan.ru
+
+
+
+
+
+
+
+
+
+
+ $whoami
+
+
+ my name is serr (you can easily guess my real name if you speak Russian :d), and i didn't come up with that nickname, i just started being called it
+
+
+ i was born in 2003, i'm currently a cybersecurity major at university
+
+
+ pronouns: he/him
+
+
+
+
+ what do i do?
+
+
+ programming is my everything - my job, my hobby, my lifestyle
+
+
+ i love growing in all areas of programming - i am literally interested in everything: cybersecurity (chaotically breaking things, analyzing code, writing automated analyzers, and moving bytes back and forth), concurrency/multithreading, web development, low-level programming, cryptography and a lot more!
+
+
+ i like the idea of symbolic /concolic execution and virtual code execution in general
+
+
+
+
+ things i love
+
+
+ coffee . i REALLY love coffee. almost any. and a lot of
+ movies and TV series (especially TV series). i watch something almost every day
+ true crime . i'm obsessed with serial killer cases, mysterious disappearances, unsolved murders - all that dark stuff
+ russian underground rap like Slava KPSS, Zamay, MB Packet, Ovsyankin etc.
+ simple and extensible code . i think if your code is overly complex, it means you are doing something wrong. most things are simpler than they seem
+
+
+
+
+
+ nice links
+
+
+ Mo , thx for design idea!
+ huge collection of Xakep issues - 図書館.きく.コム
+ i love this website highlighting the Small Web - smallweb
+ very atmospheric forum about black metal - lycanthropia
+
+
+
+
+
+
+
+
+
+ and also you can subscribe to my Telegram channel with pictures!
+
+
+ digital countryside
+
+
+
+
+ _some system information_
+
+
+ unix timestamp of page rendering - {{ .renderingTimestamp }}
+ curl -X COUNT https://hikan.ru
- 24-hour server request count
+ curl -X LIMINAL https://hikan.ru
- what do you know about liminal spaces?
+ this site code repository - git.hikan.ru/serr/hikan.ru
+
+
+
+
+ this site is written in Go without using frameworks, hosting is hostetski , domain bought for the price of a can of beer
+
+
+ 2024 - now
+
+
+
+
\ No newline at end of file
diff --git a/mvc/views/pages/main_ru.gohtml b/mvc/views/pages/main_ru.gohtml
index ea0f0dd..b36985e 100644
--- a/mvc/views/pages/main_ru.gohtml
+++ b/mvc/views/pages/main_ru.gohtml
@@ -1,132 +1,132 @@
-
-
-
- hikan.ru
-
-
-
-
-
-
-
-
-
-
-
- эту страничку на русский частично переводил DeepSeek, имейте в виду
-
-
-
-
-
- $whoami
-
-
- меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть
-
-
- я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности
-
-
- местоимения: он/его
-
-
-
-
- чем я занимаюсь?
-
-
- программирование - это моё всё: работа, хобби, стиль жизни
-
-
- мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое!
-
-
- мне нравится идея символьного /конколического выполнения и виртуального выполнения кода в целом
-
-
-
-
- что я люблю
-
-
- кофе . я ОЧЕНЬ люблю кофе. почти любой. и много
- фильмы и сериалы (особенно сериалы). я смотрю что-то почти каждый день
- true crime . я одержим делами о серийных убийцах, таинственных исчезновениях, нераскрытых убийствах - всем этим тёмным материалом
- русский андерграундный рэп типа Slava KPSS, Zamay, MB Packet, Ovsyankin и т.д.
- простой и расширяемый код . я считаю, что если ваш код слишком сложен, значит вы делаете что-то не так. большинство вещей проще, чем кажутся
-
-
-
-
-
- интересные ссылки
-
-
- Mo , спасибо за идею дизайна!
- огромная коллекция номеров Xakep - 図書館.きく.コム
- мне нравится этот сайт о Small Web - smallweb
- очень атмосферный форум о блэк-метале - lycanthropia
-
-
-
-
-
-
-
-
-
- а ещё можно подписаться на мой телеграм-канал с картинками!
-
-
- цифровая деревня
-
-
-
-
- _немного системной информации_
-
-
- unix-время генерации страницы - {{ .renderingTimestamp }}
- curl -X COUNT https://hikan.ru
- количество завпросов, обработанных сервером за 24ч
- curl -X LIMINAL https://hikan.ru
- что ты знаешь о лиминальных пространствах?
- репозиторий с кодом этого сайта - git.hikan.ru/serr/hikan.ru
-
-
-
-
- этот сайт написан на Go без использования фреймворков, хостинг - hostetski , домен куплен по цене банки пива
-
-
- 2024 - настоящее время
-
-
-
-
+
+
+
+ hikan.ru
+
+
+
+
+
+
+
+
+
+
+
+ эту страничку на русский частично переводил DeepSeek, имейте в виду
+
+
+
+
+
+ $whoami
+
+
+ меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть
+
+
+ я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности
+
+
+ местоимения: он/его
+
+
+
+
+ чем я занимаюсь?
+
+
+ программирование - это моё всё: работа, хобби, стиль жизни
+
+
+ мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое!
+
+
+ мне нравится идея символьного /конколического выполнения и виртуального выполнения кода в целом
+
+
+
+
+ что я люблю
+
+
+ кофе . я ОЧЕНЬ люблю кофе. почти любой. и много
+ фильмы и сериалы (особенно сериалы). я смотрю что-то почти каждый день
+ true crime . я одержим делами о серийных убийцах, таинственных исчезновениях, нераскрытых убийствах - всем этим тёмным материалом
+ русский андерграундный рэп типа Slava KPSS, Zamay, MB Packet, Ovsyankin и т.д.
+ простой и расширяемый код . я считаю, что если ваш код слишком сложен, значит вы делаете что-то не так. большинство вещей проще, чем кажутся
+
+
+
+
+
+ интересные ссылки
+
+
+ Mo , спасибо за идею дизайна!
+ огромная коллекция номеров Xakep - 図書館.きく.コム
+ мне нравится этот сайт о Small Web - smallweb
+ очень атмосферный форум о блэк-метале - lycanthropia
+
+
+
+
+
+
+
+
+
+ а ещё можно подписаться на мой телеграм-канал с картинками!
+
+
+ цифровая деревня
+
+
+
+
+ _немного системной информации_
+
+
+ unix-время генерации страницы - {{ .renderingTimestamp }}
+ curl -X COUNT https://hikan.ru
- количество завпросов, обработанных сервером за 24ч
+ curl -X LIMINAL https://hikan.ru
- что ты знаешь о лиминальных пространствах?
+ репозиторий с кодом этого сайта - git.hikan.ru/serr/hikan.ru
+
+
+
+
+ этот сайт написан на Go без использования фреймворков, хостинг - hostetski , домен куплен по цене банки пива
+
+
+ 2024 - настоящее время
+
+
+
+
\ No newline at end of file
diff --git a/tools/inet.go b/tools/inet.go
index 9832117..0db43b3 100644
--- a/tools/inet.go
+++ b/tools/inet.go
@@ -1,31 +1,31 @@
-package tools
-
-import (
- "net"
- "strings"
-)
-
-// Проверяет есть ли айпи-адрес среди адресов сетевых интерфейсов
-func IsIPInUse(targetIP string) (bool, error) {
- // Получаем список всех сетевых интерфейсов
- interfaces, err := net.Interfaces()
- if err != nil {
- return false, err
- }
-
- for _, iface := range interfaces {
- // Получаем адреса для каждого интерфейса
- addrs, err := iface.Addrs()
- if err != nil {
- return false, err
- }
-
- for _, addr := range addrs {
- if strings.Split(addr.String(), "/")[0] == targetIP {
- return true, nil
- }
- }
- }
-
- return false, nil // Адрес не найден
-}
+package tools
+
+import (
+ "net"
+ "strings"
+)
+
+// Проверяет есть ли айпи-адрес среди адресов сетевых интерфейсов
+func IsIPInUse(targetIP string) (bool, error) {
+ // Получаем список всех сетевых интерфейсов
+ interfaces, err := net.Interfaces()
+ if err != nil {
+ return false, err
+ }
+
+ for _, iface := range interfaces {
+ // Получаем адреса для каждого интерфейса
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return false, err
+ }
+
+ for _, addr := range addrs {
+ if strings.Split(addr.String(), "/")[0] == targetIP {
+ return true, nil
+ }
+ }
+ }
+
+ return false, nil // Адрес не найден
+}
diff --git a/tools/logs.go b/tools/logs.go
index e2b7276..378cd5c 100644
--- a/tools/logs.go
+++ b/tools/logs.go
@@ -1,29 +1,29 @@
-package tools
-
-import (
- "bytes"
- "fmt"
- "os/exec"
- "runtime"
-)
-
-func GetJournalctlLogsCount(serviceName, grepPattern string, hoursAgo int) ([]byte, error) {
-
- if runtime.GOOS != "linux" {
- return nil, fmt.Errorf("not a linux")
- }
-
- cmd := exec.Command("sh", "-c",
- fmt.Sprintf("journalctl -u %s --since '%d hours ago' | grep -c '%s'",
- serviceName, hoursAgo, grepPattern))
-
- var output bytes.Buffer
- cmd.Stdout = &output
-
- err := cmd.Run()
- if err != nil {
- return nil, err
- }
-
- return output.Bytes(), nil
-}
+package tools
+
+import (
+ "bytes"
+ "fmt"
+ "os/exec"
+ "runtime"
+)
+
+func GetJournalctlLogsCount(serviceName, grepPattern string, hoursAgo int) ([]byte, error) {
+
+ if runtime.GOOS != "linux" {
+ return nil, fmt.Errorf("not a linux")
+ }
+
+ cmd := exec.Command("sh", "-c",
+ fmt.Sprintf("journalctl -u %s --since '%d hours ago' | grep -c '%s'",
+ serviceName, hoursAgo, grepPattern))
+
+ var output bytes.Buffer
+ cmd.Stdout = &output
+
+ err := cmd.Run()
+ if err != nil {
+ return nil, err
+ }
+
+ return output.Bytes(), nil
+}