From c1901320e0c7c4011725e3b42e5631b00119927a Mon Sep 17 00:00:00 2001 From: serr <sc7227484@gmail.com> Date: Mon, 7 Apr 2025 22:17:55 +0300 Subject: [PATCH] small change --- .gitignore | 2 +- assets/css/styles.css | 112 ++++++------- main.go | 146 ++++++++--------- mvc/controllers/middlewares.go | 86 +++++----- mvc/controllers/pages/main.go | 164 +++++++++---------- mvc/controllers/pages/main_ru.go | 68 ++++---- mvc/controllers/static.go | 28 ++-- mvc/models/app.go | 130 +++++++-------- mvc/models/cache.go | 50 +++--- mvc/models/config.go | 64 ++++---- mvc/models/pages/main.go | 54 +++---- mvc/models/pages/main_ru.go | 54 +++---- mvc/views/pages/main.gohtml | 248 ++++++++++++++--------------- mvc/views/pages/main_ru.gohtml | 262 +++++++++++++++---------------- tools/inet.go | 62 ++++---- tools/logs.go | 58 +++---- 16 files changed, 794 insertions(+), 794 deletions(-) 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 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <title>hikan.ru</title> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="shortcut icon" href="/assets/pic/favicon.webp?v={{ .version }}" type="image/x-icon"> - <link rel="stylesheet" href="/assets/css/styles.css?v={{ .version }}" type="text/css"> -</head> -<body> - <header> - <div> - <img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%"> - </div> - <div> - <h1> - contacts - </h1> - <p> - you can message me on <a href="https://t.me/semaphoreslover" target="_blank">telegram</a> or <a href="https://mastodon.ml/@serr" target="_blank">mastodon</a> - </p> - </div> - <div> - <ul> - <li><a href="/ru">switch to ru version (AI translation)</a></li> - </ul> - </div> - </header> - <main> - <div> - <h1> - $whoami - </h1> - <p> - 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 - </p> - <p> - i was born in 2003, i'm currently a cybersecurity major at university - </p> - <p> - <code>pronouns: he/him</code> - </p> - </div> - <div> - <h1> - what do i do? - </h1> - <p> - programming is my everything - my job, my hobby, my lifestyle - </p> - <p> - 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! - </p> - <p> - i like the idea of <a href="https://en.wikipedia.org/wiki/Symbolic_execution" target="_blank">symbolic</a>/concolic execution and virtual code execution in general - </p> - </div> - <div> - <h1> - things i love - </h1> - <ul> - <li><strong>coffee</strong>. i REALLY love coffee. almost any. and a lot of</li> - <li><strong>movies and TV series</strong> (especially TV series). i watch something almost every day</li> - <li><strong>true crime</strong>. i'm obsessed with serial killer cases, mysterious disappearances, unsolved murders - all that dark stuff</li> - <li><strong>russian underground rap</strong> like Slava KPSS, Zamay, MB Packet, Ovsyankin etc.</li> - <li><strong>simple and extensible code</strong>. i think if your code is overly complex, it means you are doing something wrong. most things are simpler than they seem</li> - </ul> - </div> - <div> - <h1> - projects - </h1> - <ul> - <li><a href="https://git.hikan.ru/serr" target="_blank">git.hikan.ru/serr</a> - check my repos</li> - <li><del>telegram bot with schedule for SPBPU - <a href="https://t.me/polysched_bot" target="_blank">polysched_bot</a></del> (transferred to a more proactive owner)</li> - <li><del>telegram bot with schedule for SPMI - <a href="https://t.me/gornischedule_bot" target="_blank">gornischedule_bot</a></del> (closed)</li> - </ul> - </div> - <div> - <h1> - nice links - </h1> - <ul> - <li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, thx for design idea!</li> - <li>huge collection of Xakep issues - <a href="https://図書館.きく.コム/" target="_blank">図書館.きく.コム</a></li> - <li>i love this website highlighting the Small Web - <a href="https://smallweb.cc/" target="_blank">smallweb</a></li> - <li>very atmospheric forum about black metal - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li> - </ul> - </div> - </main> - <footer> - <div> - <img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%"> - </div> - <div> - <p> - and also you can subscribe to my Telegram channel with pictures! - </p> - <p> - <a href="https://t.me/lolistack" target="_blank">digital countryside</a> - </p> - </div> - <div> - <p> - _some system information_ - </p> - <ul> - <li>unix timestamp of page rendering - <strong>{{ .renderingTimestamp }}</strong></li> - <li><code>curl -X COUNT https://hikan.ru</code> - 24-hour server request count</li> - <li><code>curl -X LIMINAL https://hikan.ru</code> - what do you know about liminal spaces?</li> - <li>this site code repository - <a href="https://git.hikan.ru/serr/hikan.ru" target="_blank">git.hikan.ru/serr/hikan.ru</a></li> - </ul> - </div> - <div> - <p> - this site is written in Go without using frameworks, hosting is <a href="https://htk.ge" target="_blank">hostetski</a>, domain bought for the price of a can of beer - </p> - <p> - <code>2024 - now</code> - </p> - </div> - </footer> -</body> +<!DOCTYPE html> +<html lang="en"> +<head> + <title>hikan.ru</title> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="shortcut icon" href="/assets/pic/favicon.webp?v={{ .version }}" type="image/x-icon"> + <link rel="stylesheet" href="/assets/css/styles.css?v={{ .version }}" type="text/css"> +</head> +<body> + <header> + <div> + <img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%"> + </div> + <div> + <h1> + contacts + </h1> + <p> + you can message me on <a href="https://t.me/semaphoreslover" target="_blank">telegram</a> or <a href="https://mastodon.ml/@serr" target="_blank">mastodon</a> + </p> + </div> + <div> + <ul> + <li><a href="/ru">switch to ru version (AI translation)</a></li> + </ul> + </div> + </header> + <main> + <div> + <h1> + $whoami + </h1> + <p> + 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 + </p> + <p> + i was born in 2003, i'm currently a cybersecurity major at university + </p> + <p> + <code>pronouns: he/him</code> + </p> + </div> + <div> + <h1> + what do i do? + </h1> + <p> + programming is my everything - my job, my hobby, my lifestyle + </p> + <p> + 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! + </p> + <p> + i like the idea of <a href="https://en.wikipedia.org/wiki/Symbolic_execution" target="_blank">symbolic</a>/concolic execution and virtual code execution in general + </p> + </div> + <div> + <h1> + things i love + </h1> + <ul> + <li><strong>coffee</strong>. i REALLY love coffee. almost any. and a lot of</li> + <li><strong>movies and TV series</strong> (especially TV series). i watch something almost every day</li> + <li><strong>true crime</strong>. i'm obsessed with serial killer cases, mysterious disappearances, unsolved murders - all that dark stuff</li> + <li><strong>russian underground rap</strong> like Slava KPSS, Zamay, MB Packet, Ovsyankin etc.</li> + <li><strong>simple and extensible code</strong>. i think if your code is overly complex, it means you are doing something wrong. most things are simpler than they seem</li> + </ul> + </div> + <div> + <h1> + projects + </h1> + <ul> + <li><a href="https://git.hikan.ru/serr" target="_blank">git.hikan.ru/serr</a> - check my repos</li> + <li><del>telegram bot with schedule for SPBPU - <a href="https://t.me/polysched_bot" target="_blank">polysched_bot</a></del> (transferred to a more proactive owner)</li> + <li><del>telegram bot with schedule for SPMI - <a href="https://t.me/gornischedule_bot" target="_blank">gornischedule_bot</a></del> (closed)</li> + </ul> + </div> + <div> + <h1> + nice links + </h1> + <ul> + <li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, thx for design idea!</li> + <li>huge collection of Xakep issues - <a href="https://図書館.きく.コム/" target="_blank">図書館.きく.コム</a></li> + <li>i love this website highlighting the Small Web - <a href="https://smallweb.cc/" target="_blank">smallweb</a></li> + <li>very atmospheric forum about black metal - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li> + </ul> + </div> + </main> + <footer> + <div> + <img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%"> + </div> + <div> + <p> + and also you can subscribe to my Telegram channel with pictures! + </p> + <p> + <a href="https://t.me/lolistack" target="_blank">digital countryside</a> + </p> + </div> + <div> + <p> + _some system information_ + </p> + <ul> + <li>unix timestamp of page rendering - <strong>{{ .renderingTimestamp }}</strong></li> + <li><code>curl -X COUNT https://hikan.ru</code> - 24-hour server request count</li> + <li><code>curl -X LIMINAL https://hikan.ru</code> - what do you know about liminal spaces?</li> + <li>this site code repository - <a href="https://git.hikan.ru/serr/hikan.ru" target="_blank">git.hikan.ru/serr/hikan.ru</a></li> + </ul> + </div> + <div> + <p> + this site is written in Go without using frameworks, hosting is <a href="https://htk.ge" target="_blank">hostetski</a>, domain bought for the price of a can of beer + </p> + <p> + <code>2024 - now</code> + </p> + </div> + </footer> +</body> </html> \ 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 @@ -<!DOCTYPE html> -<html lang="ru"> -<head> - <title>hikan.ru</title> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="shortcut icon" href="/assets/pic/favicon.webp?v={{ .version }}" type="image/x-icon"> - <link rel="stylesheet" href="/assets/css/styles.css?v={{ .version }}" type="text/css"> -</head> -<body> - <header> - <div> - <img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%"> - </div> - <div> - <h1> - контакты - </h1> - <p> - вы можете написать мне в <a href="https://t.me/semaphoreslover" target="_blank">telegram</a> или <a href="https://mastodon.ml/@serr" target="_blank">mastodon</a> - </p> - </div> - <div> - <ul> - <li><a href="/">английская версия</a></li> - </ul> - </div> - </header> - <main> - <div> - <p> - <code style="color: #0E53FF"> - эту страничку на русский частично переводил DeepSeek, имейте в виду - </code> - </p> - </div> - <div> - <h1> - $whoami - </h1> - <p> - меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть - </p> - <p> - я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности - </p> - <p> - <code>местоимения: он/его</code> - </p> - </div> - <div> - <h1> - чем я занимаюсь? - </h1> - <p> - программирование - это моё всё: работа, хобби, стиль жизни - </p> - <p> - мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое! - </p> - <p> - мне нравится идея <a href="https://en.wikipedia.org/wiki/Symbolic_execution" target="_blank">символьного</a>/конколического выполнения и виртуального выполнения кода в целом - </p> - </div> - <div> - <h1> - что я люблю - </h1> - <ul> - <li><strong>кофе</strong>. я ОЧЕНЬ люблю кофе. почти любой. и много</li> - <li><strong>фильмы и сериалы</strong> (особенно сериалы). я смотрю что-то почти каждый день</li> - <li><strong>true crime</strong>. я одержим делами о серийных убийцах, таинственных исчезновениях, нераскрытых убийствах - всем этим тёмным материалом</li> - <li><strong>русский андерграундный рэп</strong> типа Slava KPSS, Zamay, MB Packet, Ovsyankin и т.д.</li> - <li><strong>простой и расширяемый код</strong>. я считаю, что если ваш код слишком сложен, значит вы делаете что-то не так. большинство вещей проще, чем кажутся</li> - </ul> - </div> - <div> - <h1> - проекты - </h1> - <ul> - <li><a href="https://git.hikan.ru/serr" target="_blank">git.hikan.ru/serr</a> - мои репозитории</li> - <li><del>телеграм-бот с расписанием для СПбПУ - <a href="https://t.me/polysched_bot" target="_blank">polysched_bot</a></del> (передан более активному владельцу)</li> - <li><del>телеграм-бот с расписанием для Горного - <a href="https://t.me/gornischedule_bot" target="_blank">gornischedule_bot</a></del> (закрыт)</li> - </ul> - </div> - <div> - <h1> - интересные ссылки - </h1> - <ul> - <li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, спасибо за идею дизайна!</li> - <li>огромная коллекция номеров Xakep - <a href="https://図書館.きく.コム/" target="_blank">図書館.きく.コム</a></li> - <li>мне нравится этот сайт о Small Web - <a href="https://smallweb.cc/" target="_blank">smallweb</a></li> - <li>очень атмосферный форум о блэк-метале - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li> - </ul> - </div> - </main> - <footer> - <div> - <img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%"> - </div> - <div> - <p> - а ещё можно подписаться на мой телеграм-канал с картинками! - </p> - <p> - <a href="https://t.me/lolistack" target="_blank">цифровая деревня</a> - </p> - </div> - <div> - <p> - _немного системной информации_ - </p> - <ul> - <li>unix-время генерации страницы - <strong>{{ .renderingTimestamp }}</strong></li> - <li><code>curl -X COUNT https://hikan.ru</code> - количество завпросов, обработанных сервером за 24ч</li> - <li><code>curl -X LIMINAL https://hikan.ru</code> - что ты знаешь о лиминальных пространствах?</li> - <li>репозиторий с кодом этого сайта - <a href="https://git.hikan.ru/serr/hikan.ru" target="_blank">git.hikan.ru/serr/hikan.ru</a></li> - </ul> - </div> - <div> - <p> - этот сайт написан на Go без использования фреймворков, хостинг - <a href="https://htk.ge" target="_blank">hostetski</a>, домен куплен по цене банки пива - </p> - <p> - <code>2024 - настоящее время</code> - </p> - </div> - </footer> -</body> +<!DOCTYPE html> +<html lang="ru"> +<head> + <title>hikan.ru</title> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="shortcut icon" href="/assets/pic/favicon.webp?v={{ .version }}" type="image/x-icon"> + <link rel="stylesheet" href="/assets/css/styles.css?v={{ .version }}" type="text/css"> +</head> +<body> + <header> + <div> + <img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%"> + </div> + <div> + <h1> + контакты + </h1> + <p> + вы можете написать мне в <a href="https://t.me/semaphoreslover" target="_blank">telegram</a> или <a href="https://mastodon.ml/@serr" target="_blank">mastodon</a> + </p> + </div> + <div> + <ul> + <li><a href="/">английская версия</a></li> + </ul> + </div> + </header> + <main> + <div> + <p> + <code style="color: #0E53FF"> + эту страничку на русский частично переводил DeepSeek, имейте в виду + </code> + </p> + </div> + <div> + <h1> + $whoami + </h1> + <p> + меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть + </p> + <p> + я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности + </p> + <p> + <code>местоимения: он/его</code> + </p> + </div> + <div> + <h1> + чем я занимаюсь? + </h1> + <p> + программирование - это моё всё: работа, хобби, стиль жизни + </p> + <p> + мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое! + </p> + <p> + мне нравится идея <a href="https://en.wikipedia.org/wiki/Symbolic_execution" target="_blank">символьного</a>/конколического выполнения и виртуального выполнения кода в целом + </p> + </div> + <div> + <h1> + что я люблю + </h1> + <ul> + <li><strong>кофе</strong>. я ОЧЕНЬ люблю кофе. почти любой. и много</li> + <li><strong>фильмы и сериалы</strong> (особенно сериалы). я смотрю что-то почти каждый день</li> + <li><strong>true crime</strong>. я одержим делами о серийных убийцах, таинственных исчезновениях, нераскрытых убийствах - всем этим тёмным материалом</li> + <li><strong>русский андерграундный рэп</strong> типа Slava KPSS, Zamay, MB Packet, Ovsyankin и т.д.</li> + <li><strong>простой и расширяемый код</strong>. я считаю, что если ваш код слишком сложен, значит вы делаете что-то не так. большинство вещей проще, чем кажутся</li> + </ul> + </div> + <div> + <h1> + проекты + </h1> + <ul> + <li><a href="https://git.hikan.ru/serr" target="_blank">git.hikan.ru/serr</a> - мои репозитории</li> + <li><del>телеграм-бот с расписанием для СПбПУ - <a href="https://t.me/polysched_bot" target="_blank">polysched_bot</a></del> (передан более активному владельцу)</li> + <li><del>телеграм-бот с расписанием для Горного - <a href="https://t.me/gornischedule_bot" target="_blank">gornischedule_bot</a></del> (закрыт)</li> + </ul> + </div> + <div> + <h1> + интересные ссылки + </h1> + <ul> + <li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, спасибо за идею дизайна!</li> + <li>огромная коллекция номеров Xakep - <a href="https://図書館.きく.コム/" target="_blank">図書館.きく.コム</a></li> + <li>мне нравится этот сайт о Small Web - <a href="https://smallweb.cc/" target="_blank">smallweb</a></li> + <li>очень атмосферный форум о блэк-метале - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li> + </ul> + </div> + </main> + <footer> + <div> + <img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%"> + </div> + <div> + <p> + а ещё можно подписаться на мой телеграм-канал с картинками! + </p> + <p> + <a href="https://t.me/lolistack" target="_blank">цифровая деревня</a> + </p> + </div> + <div> + <p> + _немного системной информации_ + </p> + <ul> + <li>unix-время генерации страницы - <strong>{{ .renderingTimestamp }}</strong></li> + <li><code>curl -X COUNT https://hikan.ru</code> - количество завпросов, обработанных сервером за 24ч</li> + <li><code>curl -X LIMINAL https://hikan.ru</code> - что ты знаешь о лиминальных пространствах?</li> + <li>репозиторий с кодом этого сайта - <a href="https://git.hikan.ru/serr/hikan.ru" target="_blank">git.hikan.ru/serr/hikan.ru</a></li> + </ul> + </div> + <div> + <p> + этот сайт написан на Go без использования фреймворков, хостинг - <a href="https://htk.ge" target="_blank">hostetski</a>, домен куплен по цене банки пива + </p> + <p> + <code>2024 - настоящее время</code> + </p> + </div> + </footer> +</body> </html> \ 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 +}