small change

master
serr 2025-04-07 22:17:55 +03:00
parent 341beefd9b
commit c1901320e0
16 changed files with 794 additions and 794 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
config.json config.json
restart.sh restart.sh

View File

@ -1,57 +1,57 @@
/* Design idea from here https://mo.rijndael.cc/ */ /* Design idea from here https://mo.rijndael.cc/ */
body { body {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin: 0; margin: 0;
align-items: flex-start; align-items: flex-start;
padding: 10px; padding: 10px;
} }
header, main, footer { header, main, footer {
margin: 5px; margin: 5px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
} }
header, footer { header, footer {
flex: 2; flex: 2;
} }
main { main {
flex: 3; flex: 3;
} }
header > div, header > div,
footer > div, footer > div,
main > div { main > div {
box-shadow: 5px 5px 0 0 lightgrey; box-shadow: 5px 5px 0 0 lightgrey;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid; border: 1px solid;
width: 100%; width: 100%;
text-align: center; text-align: center;
color: black; color: black;
padding-left: 10px; padding-left: 10px;
padding-right: 10px; padding-right: 10px;
} }
header > div > ul, header > div > ul,
footer > div > ul, footer > div > ul,
main > div > ul { main > div > ul {
text-align: left; text-align: left;
} }
header > div > h1, header > div > h1,
footer > div > h1, footer > div > h1,
main > div > h1 { main > div > h1 {
box-sizing: border-box; box-sizing: border-box;
border-top: 1px solid; border-top: 1px solid;
border-bottom: 1px solid; border-bottom: 1px solid;
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
header, footer, main { header, footer, main {
flex: 1 100%; flex: 1 100%;
} }
} }

146
main.go
View File

@ -1,73 +1,73 @@
package main package main
import ( import (
"fmt" "fmt"
"log" "log"
"main/mvc/controllers" "main/mvc/controllers"
controllers_pages "main/mvc/controllers/pages" controllers_pages "main/mvc/controllers/pages"
"main/mvc/models" "main/mvc/models"
"main/tools" "main/tools"
"net/http" "net/http"
) )
func main() { func main() {
var app *models.App var app *models.App
var err error var err error
// Инициализация приложения // Инициализация приложения
if app, err = models.AppInit("config.json"); err != nil { if app, err = models.AppInit("config.json"); err != nil {
log.Fatal(err) log.Fatal(err)
} }
// Добавление префикса в виде домена сервера к записям в лог // Добавление префикса в виде домена сервера к записям в лог
log.SetPrefix(fmt.Sprintf("%s | ", app.Config.ServerDomain)) log.SetPrefix(fmt.Sprintf("%s | ", app.Config.ServerDomain))
// Настройка маршрутов и запуск // Настройка маршрутов и запуск
if setupRoutesAndRun(app) != nil { if setupRoutesAndRun(app) != nil {
log.Fatal(err) log.Fatal(err)
} }
} }
func setupRoutesAndRun(a *models.App) error { func setupRoutesAndRun(a *models.App) error {
// Настройка маршрутов // Настройка маршрутов
router := setupRoutes(a) router := setupRoutes(a)
// Запуск сервера // Запуск сервера
if ok, err := tools.IsIPInUse(a.Config.ServerIP); err != nil { if ok, err := tools.IsIPInUse(a.Config.ServerIP); err != nil {
return err return err
} else if ok { } else if ok {
runServer(a.Config.ServerIP, a.Config.Port, router) runServer(a.Config.ServerIP, a.Config.Port, router)
} else { } else {
runServer(a.Config.LocalIP, a.Config.Port, router) runServer(a.Config.LocalIP, a.Config.Port, router)
} }
return nil return nil
} }
// Настраивает маршруты // Настраивает маршруты
func setupRoutes(a *models.App) *http.ServeMux { func setupRoutes(a *models.App) *http.ServeMux {
router := http.NewServeMux() router := http.NewServeMux()
// Цепочка обработчиков, которые сработают до отдачи страницы юзеру // Цепочка обработчиков, которые сработают до отдачи страницы юзеру
m := controllers.MiddlewaresChain m := controllers.MiddlewaresChain
// Обработка статических файлов // Обработка статических файлов
router.Handle(a.Config.AssetsPath, m(controllers.StaticHandler())) router.Handle(a.Config.AssetsPath, m(controllers.StaticHandler()))
// Странички // Странички
{ {
// Обработка главной страницы (русская версия) // Обработка главной страницы (русская версия)
router.Handle("/ru/", m(controllers_pages.MainRuPageHandler(a))) router.Handle("/ru/", m(controllers_pages.MainRuPageHandler(a)))
// Обработка главной страницы // Обработка главной страницы
router.Handle("/", m(controllers_pages.MainPageHandler(a))) router.Handle("/", m(controllers_pages.MainPageHandler(a)))
} }
return router return router
} }
// Обертка над ListenAndServe, запускает сервер на указанном IP, PORT // Запускает сервер на указанном IP, PORT
func runServer(ip, port string, router http.Handler) { func runServer(ip, port string, router http.Handler) {
addr := ip + port addr := ip + port
log.Println("Run on", addr) log.Println("Run on", addr)
log.Fatal(http.ListenAndServe(addr, router)) log.Fatal(http.ListenAndServe(addr, router))
} }

View File

@ -1,43 +1,43 @@
package controllers package controllers
import ( import (
"log" "log"
"net/http" "net/http"
"time" "time"
) )
type Middleware func(http.Handler) http.Handler type Middleware func(http.Handler) http.Handler
var ( var (
MiddlewaresChain = CreateMiddlewaresChain( MiddlewaresChain = CreateMiddlewaresChain(
LoggingMiddleware, LoggingMiddleware,
) )
) )
/* /*
Возвращает один middleware, который объединяет все переданные Возвращает один middleware, который объединяет все переданные
CreateMiddlewaresChain(m1, m2, m3) CreateMiddlewaresChain(m1, m2, m3)
= func(next http.Handler) http.Handler { return m1(m2(m3(final))) } = func(next http.Handler) http.Handler { return m1(m2(m3(final))) }
CreateMiddlewaresChain(LoggingMiddleware) CreateMiddlewaresChain(LoggingMiddleware)
= func(next http.Handler) http.Handler { return LoggingMiddleware(final) } = func(next http.Handler) http.Handler { return LoggingMiddleware(final) }
*/ */
func CreateMiddlewaresChain(middlewares ...Middleware) Middleware { func CreateMiddlewaresChain(middlewares ...Middleware) Middleware {
return func(final http.Handler) http.Handler { return func(final http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- { for i := len(middlewares) - 1; i >= 0; i-- {
final = middlewares[i](final) final = middlewares[i](final)
} }
return final return final
} }
} }
func LoggingMiddleware(next http.Handler) http.Handler { func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now() start := time.Now()
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start)) log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
}) })
} }

View File

@ -1,82 +1,82 @@
package controllers package controllers
import ( import (
"log" "log"
"main/mvc/models" "main/mvc/models"
models_pages "main/mvc/models/pages" models_pages "main/mvc/models/pages"
"main/tools" "main/tools"
"net/http" "net/http"
) )
// Обработчик главной страницы // Обработчик главной страницы
func MainPageHandler(a *models.App) http.HandlerFunc { func MainPageHandler(a *models.App) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error var err error
// Количество запросов, обработанных сервером за 24ч // Количество запросов, обработанных сервером за 24ч
if r.Method == "COUNT" { if r.Method == "COUNT" {
var count []byte var count []byte
if count, err = tools.GetJournalctlLogsCount("server", a.Config.ServerDomain, 24); err != nil { if count, err = tools.GetJournalctlLogsCount("server", a.Config.ServerDomain, 24); err != nil {
log.Printf("%s", err.Error()) log.Printf("%s", err.Error())
} }
SendCount(w, count) SendCount(w, count)
return return
} }
// Пасхалка // Пасхалка
if r.Method == "LOVE" { if r.Method == "LOVE" {
SendLove(w) SendLove(w)
return return
} }
// Пасхалка 2 // Пасхалка 2
if r.Method == "LIMINAL" { if r.Method == "LIMINAL" {
SendLiminal(w) SendLiminal(w)
return return
} }
// Страничка рендерится только если ее нет в кэше // Страничка рендерится только если ее нет в кэше
pageData, ok := a.Cache.Get(models_pages.MainPageTmplName) pageData, ok := a.Cache.Get(models_pages.MainPageTmplName)
if !ok { if !ok {
pageData, err = models_pages.RenderMainPage(a.Templates, a.Version) pageData, err = models_pages.RenderMainPage(a.Templates, a.Version)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
a.Cache.Set(models_pages.MainPageTmplName, pageData) a.Cache.Set(models_pages.MainPageTmplName, pageData)
} }
SendMainPage(w, pageData.([]byte)) SendMainPage(w, pageData.([]byte))
}) })
} }
// Отправляет страницу // Отправляет страницу
func SendMainPage(w http.ResponseWriter, data []byte) { func SendMainPage(w http.ResponseWriter, data []byte) {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(data) w.Write(data)
} }
// Ответ на метод COUNT // Ответ на метод COUNT
func SendCount(w http.ResponseWriter, data []byte) { func SendCount(w http.ResponseWriter, data []byte) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(data) w.Write(data)
} }
// Ответ на метод LOVE // Ответ на метод LOVE
func SendLove(w http.ResponseWriter) { func SendLove(w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("13.01.2005\n")) w.Write([]byte("13.01.2005\n"))
} }
// Ответ на метод LIMINAL // Ответ на метод LIMINAL
func SendLiminal(w http.ResponseWriter) { func SendLiminal(w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK) 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" 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)) w.Write([]byte(text))
} }

View File

@ -1,34 +1,34 @@
package controllers package controllers
import ( import (
"main/mvc/models" "main/mvc/models"
models_pages "main/mvc/models/pages" models_pages "main/mvc/models/pages"
"net/http" "net/http"
) )
// Обработчик главной страницы // Обработчик главной страницы
func MainRuPageHandler(a *models.App) http.HandlerFunc { func MainRuPageHandler(a *models.App) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error var err error
// Страничка рендерится только если ее нет в кэше // Страничка рендерится только если ее нет в кэше
pageData, ok := a.Cache.Get(models_pages.MainRuPageTmplName) pageData, ok := a.Cache.Get(models_pages.MainRuPageTmplName)
if !ok { if !ok {
pageData, err = models_pages.RenderMainRuPage(a.Templates, a.Version) pageData, err = models_pages.RenderMainRuPage(a.Templates, a.Version)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
a.Cache.Set(models_pages.MainRuPageTmplName, pageData) a.Cache.Set(models_pages.MainRuPageTmplName, pageData)
} }
SendMainPage(w, pageData.([]byte)) SendMainPage(w, pageData.([]byte))
}) })
} }
// Отправляет страницу // Отправляет страницу
func SendMainRuPage(w http.ResponseWriter, data []byte) { func SendMainRuPage(w http.ResponseWriter, data []byte) {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(data) w.Write(data)
} }

View File

@ -1,14 +1,14 @@
package controllers package controllers
import "net/http" import "net/http"
// Обработчик статических файлов с кэшированием // Обработчик статических файлов с кэшированием
func StaticHandler() http.HandlerFunc { func StaticHandler() http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Здесь используется встроенный файловый сервер Go (http.FileServer), который: // Здесь используется встроенный файловый сервер Go (http.FileServer), который:
// Реализует интерфейс http.Handler (и поэтому имеет метод ServeHTTP) // Реализует интерфейс http.Handler (и поэтому имеет метод ServeHTTP)
// Автоматически обслуживает статические файлы из файловой системы // Автоматически обслуживает статические файлы из файловой системы
// Сам обрабатывает HTTP-запросы, определяет MIME-типы, отправляет правильные заголовки и т.д. // Сам обрабатывает HTTP-запросы, определяет MIME-типы, отправляет правильные заголовки и т.д.
http.FileServer(http.Dir(".")).ServeHTTP(w, r) http.FileServer(http.Dir(".")).ServeHTTP(w, r)
}) })
} }

View File

@ -1,65 +1,65 @@
package models package models
import ( import (
"html/template" "html/template"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
) )
// App хранит информацию о приложении // App хранит информацию о приложении
type App struct { type App struct {
Config *Config // Конфиг Config *Config // Конфиг
Templates *template.Template // Шаблоны страниц Templates *template.Template // Шаблоны страниц
Cache *Cache // Кэш (отрендеренные странички) Cache *Cache // Кэш (отрендеренные странички)
Version int64 // Время запуска Version int64 // Время запуска
} }
// Инициализирует приложение // Инициализирует приложение
func AppInit(configPath string) (*App, error) { func AppInit(configPath string) (*App, error) {
a := &App{ a := &App{
Version: time.Now().Unix(), Version: time.Now().Unix(),
Config: ConfigInit(), Config: ConfigInit(),
Cache: CacheInit(), Cache: CacheInit(),
} }
// Загрузка конфига // Загрузка конфига
if err := a.Config.Load(configPath); err != nil { if err := a.Config.Load(configPath); err != nil {
return nil, err return nil, err
} }
// Загрузка шаблонов // Загрузка шаблонов
if err := a.loadTemplates(a.Config.TemplatesPath, a.Config.TemplatesExt); err != nil { if err := a.loadTemplates(a.Config.TemplatesPath, a.Config.TemplatesExt); err != nil {
log.Fatal(err) log.Fatal(err)
} }
return a, nil return a, nil
} }
// Загрузка шаблонов // Загрузка шаблонов
func (a *App) loadTemplates(templatesPath string, ext string) error { func (a *App) loadTemplates(templatesPath string, ext string) error {
tmpls := template.New("") tmpls := template.New("")
err := filepath.Walk(templatesPath, func(path string, f os.FileInfo, err error) error { err := filepath.Walk(templatesPath, func(path string, f os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if !f.IsDir() && strings.HasSuffix(f.Name(), ext) { if !f.IsDir() && strings.HasSuffix(f.Name(), ext) {
_, err = tmpls.ParseFiles(path) _, err = tmpls.ParseFiles(path)
if err != nil { if err != nil {
return err return err
} }
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return err
} }
a.Templates = tmpls a.Templates = tmpls
return nil return nil
} }

View File

@ -1,25 +1,25 @@
package models package models
import "sync" import "sync"
type Cache struct { type Cache struct {
Data map[string]any Data map[string]any
Mu sync.RWMutex Mu sync.RWMutex
} }
func CacheInit() *Cache { func CacheInit() *Cache {
return &Cache{Data: make(map[string]any)} return &Cache{Data: make(map[string]any)}
} }
func (c *Cache) Get(key string) (any, bool) { func (c *Cache) Get(key string) (any, bool) {
c.Mu.RLock() c.Mu.RLock()
pageData, ok := c.Data[key] pageData, ok := c.Data[key]
c.Mu.RUnlock() c.Mu.RUnlock()
return pageData, ok return pageData, ok
} }
func (c *Cache) Set(key string, data any) { func (c *Cache) Set(key string, data any) {
c.Mu.Lock() c.Mu.Lock()
c.Data[key] = data c.Data[key] = data
c.Mu.Unlock() c.Mu.Unlock()
} }

View File

@ -1,32 +1,32 @@
package models package models
import ( import (
"encoding/json" "encoding/json"
"os" "os"
) )
type Config struct { type Config struct {
AssetsPath string AssetsPath string
TemplatesPath string TemplatesPath string
TemplatesExt string TemplatesExt string
LocalIP string LocalIP string
ServerIP string ServerIP string
ServerDomain string ServerDomain string
Port string Port string
} }
func ConfigInit() *Config { func ConfigInit() *Config {
return &Config{} return &Config{}
} }
func (c *Config) Load(configPath string) error { func (c *Config) Load(configPath string) error {
configFile, err := os.ReadFile(configPath) configFile, err := os.ReadFile(configPath)
if err != nil { if err != nil {
return err return err
} }
err = json.Unmarshal(configFile, c) err = json.Unmarshal(configFile, c)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }

View File

@ -1,27 +1,27 @@
package models package models
import ( import (
"bytes" "bytes"
"html/template" "html/template"
"time" "time"
) )
const ( const (
// Имя соответствующего шаблона // Имя соответствующего шаблона
MainPageTmplName = "main.gohtml" MainPageTmplName = "main.gohtml"
) )
func RenderMainPage(templates *template.Template, version int64) ([]byte, error) { func RenderMainPage(templates *template.Template, version int64) ([]byte, error) {
var pageData bytes.Buffer var pageData bytes.Buffer
context := map[string]any{ context := map[string]any{
"version": version, "version": version,
"renderingTimestamp": time.Now().Unix(), "renderingTimestamp": time.Now().Unix(),
} }
if err := templates.ExecuteTemplate(&pageData, MainPageTmplName, context); err != nil { if err := templates.ExecuteTemplate(&pageData, MainPageTmplName, context); err != nil {
return nil, err return nil, err
} }
return pageData.Bytes(), nil return pageData.Bytes(), nil
} }

View File

@ -1,27 +1,27 @@
package models package models
import ( import (
"bytes" "bytes"
"html/template" "html/template"
"time" "time"
) )
const ( const (
// Имя соответствующего шаблона // Имя соответствующего шаблона
MainRuPageTmplName = "main_ru.gohtml" MainRuPageTmplName = "main_ru.gohtml"
) )
func RenderMainRuPage(templates *template.Template, version int64) ([]byte, error) { func RenderMainRuPage(templates *template.Template, version int64) ([]byte, error) {
var pageData bytes.Buffer var pageData bytes.Buffer
context := map[string]any{ context := map[string]any{
"version": version, "version": version,
"renderingTimestamp": time.Now().Unix(), "renderingTimestamp": time.Now().Unix(),
} }
if err := templates.ExecuteTemplate(&pageData, MainRuPageTmplName, context); err != nil { if err := templates.ExecuteTemplate(&pageData, MainRuPageTmplName, context); err != nil {
return nil, err return nil, err
} }
return pageData.Bytes(), nil return pageData.Bytes(), nil
} }

View File

@ -1,125 +1,125 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>hikan.ru</title> <title>hikan.ru</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <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="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"> <link rel="stylesheet" href="/assets/css/styles.css?v={{ .version }}" type="text/css">
</head> </head>
<body> <body>
<header> <header>
<div> <div>
<img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%"> <img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%">
</div> </div>
<div> <div>
<h1> <h1>
contacts contacts
</h1> </h1>
<p> <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> 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> </p>
</div> </div>
<div> <div>
<ul> <ul>
<li><a href="/ru">switch to ru version (AI translation)</a></li> <li><a href="/ru">switch to ru version (AI translation)</a></li>
</ul> </ul>
</div> </div>
</header> </header>
<main> <main>
<div> <div>
<h1> <h1>
$whoami $whoami
</h1> </h1>
<p> <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 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>
<p> <p>
i was born in 2003, i'm currently a cybersecurity major at university i was born in 2003, i'm currently a cybersecurity major at university
</p> </p>
<p> <p>
<code>pronouns: he/him</code> <code>pronouns: he/him</code>
</p> </p>
</div> </div>
<div> <div>
<h1> <h1>
what do i do? what do i do?
</h1> </h1>
<p> <p>
programming is my everything - my job, my hobby, my lifestyle programming is my everything - my job, my hobby, my lifestyle
</p> </p>
<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! 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>
<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 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> </p>
</div> </div>
<div> <div>
<h1> <h1>
things i love things i love
</h1> </h1>
<ul> <ul>
<li><strong>coffee</strong>. i REALLY love coffee. almost any. and a lot of</li> <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>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>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>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> <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> </ul>
</div> </div>
<div> <div>
<h1> <h1>
projects projects
</h1> </h1>
<ul> <ul>
<li><a href="https://git.hikan.ru/serr" target="_blank">git.hikan.ru/serr</a> - check my repos</li> <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 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> <li><del>telegram bot with schedule for SPMI - <a href="https://t.me/gornischedule_bot" target="_blank">gornischedule_bot</a></del> (closed)</li>
</ul> </ul>
</div> </div>
<div> <div>
<h1> <h1>
nice links nice links
</h1> </h1>
<ul> <ul>
<li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, thx for design idea!</li> <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>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>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> <li>very atmospheric forum about black metal - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li>
</ul> </ul>
</div> </div>
</main> </main>
<footer> <footer>
<div> <div>
<img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%"> <img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%">
</div> </div>
<div> <div>
<p> <p>
and also you can subscribe to my Telegram channel with pictures! and also you can subscribe to my Telegram channel with pictures!
</p> </p>
<p> <p>
<a href="https://t.me/lolistack" target="_blank">digital countryside</a> <a href="https://t.me/lolistack" target="_blank">digital countryside</a>
</p> </p>
</div> </div>
<div> <div>
<p> <p>
_some system information_ _some system information_
</p> </p>
<ul> <ul>
<li>unix timestamp of page rendering - <strong>{{ .renderingTimestamp }}</strong></li> <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 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><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> <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> </ul>
</div> </div>
<div> <div>
<p> <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 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>
<p> <p>
<code>2024 - now</code> <code>2024 - now</code>
</p> </p>
</div> </div>
</footer> </footer>
</body> </body>
</html> </html>

View File

@ -1,132 +1,132 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru"> <html lang="ru">
<head> <head>
<title>hikan.ru</title> <title>hikan.ru</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <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="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"> <link rel="stylesheet" href="/assets/css/styles.css?v={{ .version }}" type="text/css">
</head> </head>
<body> <body>
<header> <header>
<div> <div>
<img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%"> <img src="/assets/pic/header.webp?v={{ .version }}" width="100%" height="100%">
</div> </div>
<div> <div>
<h1> <h1>
контакты контакты
</h1> </h1>
<p> <p>
вы можете написать мне в <a href="https://t.me/semaphoreslover" target="_blank">telegram</a> или <a href="https://mastodon.ml/@serr" target="_blank">mastodon</a> вы можете написать мне в <a href="https://t.me/semaphoreslover" target="_blank">telegram</a> или <a href="https://mastodon.ml/@serr" target="_blank">mastodon</a>
</p> </p>
</div> </div>
<div> <div>
<ul> <ul>
<li><a href="/">английская версия</a></li> <li><a href="/">английская версия</a></li>
</ul> </ul>
</div> </div>
</header> </header>
<main> <main>
<div> <div>
<p> <p>
<code style="color: #0E53FF"> <code style="color: #0E53FF">
эту страничку на русский частично переводил DeepSeek, имейте в виду эту страничку на русский частично переводил DeepSeek, имейте в виду
</code> </code>
</p> </p>
</div> </div>
<div> <div>
<h1> <h1>
$whoami $whoami
</h1> </h1>
<p> <p>
меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть меня зовут serr (мое настоящее имя легко угадать, если вы говорите по-русски :d), и это не я придумал этот никнейм - просто меня стали так называть
</p> </p>
<p> <p>
я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности я родился в 2003 году, сейчас учусь на специалиста по кибербезопасности
</p> </p>
<p> <p>
<code>местоимения: он/его</code> <code>местоимения: он/его</code>
</p> </p>
</div> </div>
<div> <div>
<h1> <h1>
чем я занимаюсь? чем я занимаюсь?
</h1> </h1>
<p> <p>
программирование - это моё всё: работа, хобби, стиль жизни программирование - это моё всё: работа, хобби, стиль жизни
</p> </p>
<p> <p>
мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое! мне нравится развиваться во всех областях программирования - мне буквально интересно всё: кибербезопасность (хаотичный взлом вещей, анализ кода, написание автоматических анализаторов и перекладывание байтов туда-сюда), многопоточность, веб-разработка, низкоуровневое программирование, криптография и многое другое!
</p> </p>
<p> <p>
мне нравится идея <a href="https://en.wikipedia.org/wiki/Symbolic_execution" target="_blank">символьного</a>/конколического выполнения и виртуального выполнения кода в целом мне нравится идея <a href="https://en.wikipedia.org/wiki/Symbolic_execution" target="_blank">символьного</a>/конколического выполнения и виртуального выполнения кода в целом
</p> </p>
</div> </div>
<div> <div>
<h1> <h1>
что я люблю что я люблю
</h1> </h1>
<ul> <ul>
<li><strong>кофе</strong>. я ОЧЕНЬ люблю кофе. почти любой. и много</li> <li><strong>кофе</strong>. я ОЧЕНЬ люблю кофе. почти любой. и много</li>
<li><strong>фильмы и сериалы</strong> (особенно сериалы). я смотрю что-то почти каждый день</li> <li><strong>фильмы и сериалы</strong> (особенно сериалы). я смотрю что-то почти каждый день</li>
<li><strong>true crime</strong>. я одержим делами о серийных убийцах, таинственных исчезновениях, нераскрытых убийствах - всем этим тёмным материалом</li> <li><strong>true crime</strong>. я одержим делами о серийных убийцах, таинственных исчезновениях, нераскрытых убийствах - всем этим тёмным материалом</li>
<li><strong>русский андерграундный рэп</strong> типа Slava KPSS, Zamay, MB Packet, Ovsyankin и т.д.</li> <li><strong>русский андерграундный рэп</strong> типа Slava KPSS, Zamay, MB Packet, Ovsyankin и т.д.</li>
<li><strong>простой и расширяемый код</strong>. я считаю, что если ваш код слишком сложен, значит вы делаете что-то не так. большинство вещей проще, чем кажутся</li> <li><strong>простой и расширяемый код</strong>. я считаю, что если ваш код слишком сложен, значит вы делаете что-то не так. большинство вещей проще, чем кажутся</li>
</ul> </ul>
</div> </div>
<div> <div>
<h1> <h1>
проекты проекты
</h1> </h1>
<ul> <ul>
<li><a href="https://git.hikan.ru/serr" target="_blank">git.hikan.ru/serr</a> - мои репозитории</li> <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/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> <li><del>телеграм-бот с расписанием для Горного - <a href="https://t.me/gornischedule_bot" target="_blank">gornischedule_bot</a></del> (закрыт)</li>
</ul> </ul>
</div> </div>
<div> <div>
<h1> <h1>
интересные ссылки интересные ссылки
</h1> </h1>
<ul> <ul>
<li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, спасибо за идею дизайна!</li> <li><a href="https://mo.rijndael.cc/" target="_blank">Mo</a>, спасибо за идею дизайна!</li>
<li>огромная коллекция номеров Xakep - <a href="https://図書館.きく.コム/" target="_blank">図書館.きく.コム</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>мне нравится этот сайт о Small Web - <a href="https://smallweb.cc/" target="_blank">smallweb</a></li>
<li>очень атмосферный форум о блэк-метале - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li> <li>очень атмосферный форум о блэк-метале - <a href="https://www.lycanthropia.net/" target="_blank">lycanthropia</a></li>
</ul> </ul>
</div> </div>
</main> </main>
<footer> <footer>
<div> <div>
<img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%"> <img src="/assets/pic/footer.webp?v={{ .version }}" width="100%" height="100%">
</div> </div>
<div> <div>
<p> <p>
а ещё можно подписаться на мой телеграм-канал с картинками! а ещё можно подписаться на мой телеграм-канал с картинками!
</p> </p>
<p> <p>
<a href="https://t.me/lolistack" target="_blank">цифровая деревня</a> <a href="https://t.me/lolistack" target="_blank">цифровая деревня</a>
</p> </p>
</div> </div>
<div> <div>
<p> <p>
емного системной информации_ емного системной информации_
</p> </p>
<ul> <ul>
<li>unix-время генерации страницы - <strong>{{ .renderingTimestamp }}</strong></li> <li>unix-время генерации страницы - <strong>{{ .renderingTimestamp }}</strong></li>
<li><code>curl -X COUNT https://hikan.ru</code> - количество завпросов, обработанных сервером за 24ч</li> <li><code>curl -X COUNT https://hikan.ru</code> - количество завпросов, обработанных сервером за 24ч</li>
<li><code>curl -X LIMINAL https://hikan.ru</code> - что ты знаешь о лиминальных пространствах?</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> <li>репозиторий с кодом этого сайта - <a href="https://git.hikan.ru/serr/hikan.ru" target="_blank">git.hikan.ru/serr/hikan.ru</a></li>
</ul> </ul>
</div> </div>
<div> <div>
<p> <p>
этот сайт написан на Go без использования фреймворков, хостинг - <a href="https://htk.ge" target="_blank">hostetski</a>, домен куплен по цене банки пива этот сайт написан на Go без использования фреймворков, хостинг - <a href="https://htk.ge" target="_blank">hostetski</a>, домен куплен по цене банки пива
</p> </p>
<p> <p>
<code>2024 - настоящее время</code> <code>2024 - настоящее время</code>
</p> </p>
</div> </div>
</footer> </footer>
</body> </body>
</html> </html>

View File

@ -1,31 +1,31 @@
package tools package tools
import ( import (
"net" "net"
"strings" "strings"
) )
// Проверяет есть ли айпи-адрес среди адресов сетевых интерфейсов // Проверяет есть ли айпи-адрес среди адресов сетевых интерфейсов
func IsIPInUse(targetIP string) (bool, error) { func IsIPInUse(targetIP string) (bool, error) {
// Получаем список всех сетевых интерфейсов // Получаем список всех сетевых интерфейсов
interfaces, err := net.Interfaces() interfaces, err := net.Interfaces()
if err != nil { if err != nil {
return false, err return false, err
} }
for _, iface := range interfaces { for _, iface := range interfaces {
// Получаем адреса для каждого интерфейса // Получаем адреса для каждого интерфейса
addrs, err := iface.Addrs() addrs, err := iface.Addrs()
if err != nil { if err != nil {
return false, err return false, err
} }
for _, addr := range addrs { for _, addr := range addrs {
if strings.Split(addr.String(), "/")[0] == targetIP { if strings.Split(addr.String(), "/")[0] == targetIP {
return true, nil return true, nil
} }
} }
} }
return false, nil // Адрес не найден return false, nil // Адрес не найден
} }

View File

@ -1,29 +1,29 @@
package tools package tools
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"os/exec" "os/exec"
"runtime" "runtime"
) )
func GetJournalctlLogsCount(serviceName, grepPattern string, hoursAgo int) ([]byte, error) { func GetJournalctlLogsCount(serviceName, grepPattern string, hoursAgo int) ([]byte, error) {
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
return nil, fmt.Errorf("not a linux") return nil, fmt.Errorf("not a linux")
} }
cmd := exec.Command("sh", "-c", cmd := exec.Command("sh", "-c",
fmt.Sprintf("journalctl -u %s --since '%d hours ago' | grep -c '%s'", fmt.Sprintf("journalctl -u %s --since '%d hours ago' | grep -c '%s'",
serviceName, hoursAgo, grepPattern)) serviceName, hoursAgo, grepPattern))
var output bytes.Buffer var output bytes.Buffer
cmd.Stdout = &output cmd.Stdout = &output
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return output.Bytes(), nil return output.Bytes(), nil
} }