154 lines
3.5 KiB
Go
154 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"git.gm6.ru/icewind/notify"
|
|
)
|
|
|
|
// Config — структура для чтения YAML-файла
|
|
type Config struct {
|
|
ListenAddresses []string `yaml:"listen_addresses"`
|
|
LogDir string `yaml:"log_dir"`
|
|
Telegram *ConfigTelegraam `yaml:"telegram"`
|
|
}
|
|
|
|
type ConfigTelegraam struct {
|
|
Token string `yaml:"token"`
|
|
GroupID int64 `yaml:"group_id"`
|
|
}
|
|
|
|
func GetRemoteAddr(r *http.Request) string {
|
|
// Сначала смотрим X-Forwarded-For
|
|
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
|
// X-Forwarded-For может содержать несколько IP через запятую
|
|
ips := strings.Split(xff, ",")
|
|
if len(ips) > 0 {
|
|
return strings.TrimSpace(ips[0])
|
|
}
|
|
}
|
|
|
|
// Потом X-Real-IP
|
|
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
|
|
return realIP
|
|
}
|
|
|
|
// И в конце RemoteAddr
|
|
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
if err != nil {
|
|
return r.RemoteAddr
|
|
}
|
|
return host
|
|
}
|
|
|
|
func BuildMessage(r *http.Request) string {
|
|
t := time.Now()
|
|
|
|
var body []byte
|
|
|
|
if r.ContentLength > 1024 {
|
|
body = []byte("too long")
|
|
} else {
|
|
// Читаем тело запроса
|
|
body, _ = io.ReadAll(r.Body)
|
|
_ = r.Body.Close()
|
|
}
|
|
|
|
// Формируем содержимое
|
|
entry := fmt.Sprintf("[%s] %s %s%s\n", t.Format(time.RFC3339), r.Method, r.Host, r.URL.String())
|
|
entry += "RemoteAddr: " + GetRemoteAddr(r) + "\n"
|
|
entry += "Headers:\n"
|
|
for name, values := range r.Header {
|
|
for _, v := range values {
|
|
entry += fmt.Sprintf(" %s: %s\n", name, v)
|
|
}
|
|
}
|
|
entry += fmt.Sprintf("Body:\n%s\n", string(body))
|
|
entry += "----\n"
|
|
|
|
entry = "```" + entry + "```"
|
|
return entry
|
|
}
|
|
|
|
func main() {
|
|
log.Println("Запуск приложения")
|
|
// Загружаем конфиг
|
|
cfg, err := loadConfig("config.yaml")
|
|
if err != nil {
|
|
log.Fatalf("Ошибка загрузки конфига: %v", err)
|
|
}
|
|
|
|
if cfg.Telegram == nil {
|
|
log.Fatalf("не указана секция telegram")
|
|
}
|
|
|
|
tg, err := notify.NewTelegram(cfg.Telegram.Token, true)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Общий обработчик
|
|
handler := func(w http.ResponseWriter, r *http.Request) {
|
|
paths := strings.Split(r.URL.Path, "/")
|
|
switch {
|
|
case len(paths) < 2:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
case paths[1] == "telegram":
|
|
default:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
entry := BuildMessage(r)
|
|
_, err = tg.SendTextMessage(cfg.Telegram.GroupID, entry)
|
|
if err != nil {
|
|
log.Println(err)
|
|
w.WriteHeader(http.StatusBadGateway)
|
|
w.Write([]byte(err.Error()))
|
|
} else {
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write([]byte("OK"))
|
|
}
|
|
}
|
|
|
|
// Регистрируем хендлер
|
|
http.HandleFunc("/", handler)
|
|
|
|
// Запускаем серверы для всех адресов
|
|
for _, addr := range cfg.ListenAddresses {
|
|
addr := addr // захватываем в область видимости
|
|
go func() {
|
|
log.Printf("Слушаю %s ...", addr)
|
|
if err := http.ListenAndServe(addr, nil); err != nil {
|
|
log.Printf("Ошибка на %s: %v", addr, err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Блокируем main, чтобы программа не завершилась
|
|
select {}
|
|
}
|
|
|
|
// loadConfig читает YAML-конфиг из файла
|
|
func loadConfig(path string) (*Config, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var cfg Config
|
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
return &cfg, nil
|
|
}
|