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 - - - - - - -
-
- -
-
-

- contacts -

-

- you can message me on telegram or mastodon -

-
-
- -
-
-
-
-

- $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 -

- -
-
-

- projects -

- -
-
-

- nice links -

- -
-
- - + + + + hikan.ru + + + + + + +
+
+ +
+
+

+ contacts +

+

+ you can message me on telegram or mastodon +

+
+
+ +
+
+
+
+

+ $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 +

+ +
+
+

+ projects +

+ +
+
+

+ nice links +

+ +
+
+ + \ 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 - - - - - - -
-
- -
-
-

- контакты -

-

- вы можете написать мне в telegram или mastodon -

-
-
- -
-
-
-
-

- - эту страничку на русский частично переводил DeepSeek, имейте в виду - -

-
-
-

- $whoami -

-

- меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть -

-

- я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности -

-

- местоимения: он/его -

-
-
-

- чем я занимаюсь? -

-

- программирование - это моё всё: работа, хобби, стиль жизни -

-

- мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое! -

-

- мне нравится идея символьного/конколического выполнения и виртуального выполнения кода в целом -

-
-
-

- что я люблю -

- -
-
-

- проекты -

- -
-
-

- интересные ссылки -

- -
-
- - + + + + hikan.ru + + + + + + +
+
+ +
+
+

+ контакты +

+

+ вы можете написать мне в telegram или mastodon +

+
+
+ +
+
+
+
+

+ + эту страничку на русский частично переводил DeepSeek, имейте в виду + +

+
+
+

+ $whoami +

+

+ меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть +

+

+ я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности +

+

+ местоимения: он/его +

+
+
+

+ чем я занимаюсь? +

+

+ программирование - это моё всё: работа, хобби, стиль жизни +

+

+ мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое! +

+

+ мне нравится идея символьного/конколического выполнения и виртуального выполнения кода в целом +

+
+
+

+ что я люблю +

+ +
+
+

+ проекты +

+ +
+
+

+ интересные ссылки +

+ +
+
+ + \ 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 +}