Обновлена среда разработки и добавлен новый функционал в сервер
- Улучшена среда разработки, поправлены косяки старта дебагера - Добавлен логер в приложение - Добавлен cli framework
This commit is contained in:
parent
ed623c3236
commit
f6521b9332
1
application/.gitignore
vendored
1
application/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
out.log
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
module pink_fox
|
|
||||||
|
|
||||||
go 1.24.0
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
_, _ = fmt.Fprintf(w, "ok")
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
_, _ = fmt.Fprintf(w, "Hello world!")
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println("Starting server at port 12001...")
|
|
||||||
if err := http.ListenAndServe(":12001", nil); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,8 +9,8 @@ services:
|
|||||||
- "12001:12001"
|
- "12001:12001"
|
||||||
- "12002:2345"
|
- "12002:2345"
|
||||||
volumes:
|
volumes:
|
||||||
- ./application:/app
|
- ./pink_fox_app:/app
|
||||||
- ./dist:/app/dist
|
- ./dist:/dist
|
||||||
- ./environment:/var/environment/pink_fox
|
- ./environment:/var/environment/pink_fox
|
||||||
- ./log:/var/log/pink_fox
|
- ./log:/var/log/pink_fox
|
||||||
- ./.storage/go:/go
|
- ./.storage/go:/go
|
||||||
|
|||||||
2
pink_fox_app/.gitignore
vendored
Normal file
2
pink_fox_app/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
out.log
|
||||||
|
err.log
|
||||||
11
pink_fox_app/go.mod
Normal file
11
pink_fox_app/go.mod
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module pink_fox
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
|
github.com/spf13/cobra v1.9.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
13
pink_fox_app/go.sum
Normal file
13
pink_fox_app/go.sum
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
47
pink_fox_app/internal/app/cmd/cmd.go
Normal file
47
pink_fox_app/internal/app/cmd/cmd.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
port = 12001
|
||||||
|
config = "/var/environment/pink_fox/config.yml"
|
||||||
|
|
||||||
|
rootCmd = &cobra.Command{
|
||||||
|
Use: "pink_fox",
|
||||||
|
Short: "Розовый лис\nСквозь ссылок паутину —\nСвет в ночи горит.",
|
||||||
|
}
|
||||||
|
|
||||||
|
serverCmd = &cobra.Command{
|
||||||
|
Use: "server",
|
||||||
|
Short: "Запуск сервера",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := NewServer().Execute(config, port)
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
serverCmd.Flags().IntVarP(&port, "port", "p", port, "Порт доступ к приложению")
|
||||||
|
serverCmd.Flags().StringVarP(&config, "config", "c", config, "Путь к файлу конфигурации")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(serverCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() error {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
return fmt.Errorf("cmd: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func exit(err error) {
|
||||||
|
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
57
pink_fox_app/internal/app/cmd/server.go
Normal file
57
pink_fox_app/internal/app/cmd/server.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
conf2 "pink_fox/internal/app/config"
|
||||||
|
"pink_fox/internal/app/db"
|
||||||
|
"pink_fox/internal/app/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer() *Server {
|
||||||
|
return &Server{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *Server) Execute(defaultConfig string, defaultPort int) error {
|
||||||
|
conf, err := conf2.LoadConfig(defaultConfig, defaultPort)
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := db.CreateConnection(&conf.Db)
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
defer func(conn *sql.DB) {
|
||||||
|
_ = conn.Close()
|
||||||
|
}(conn)
|
||||||
|
|
||||||
|
logger, err := log.NewLogger(conf.LogFile)
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
defer func(logger *log.Logger) {
|
||||||
|
_ = logger.Close()
|
||||||
|
}(logger)
|
||||||
|
|
||||||
|
// TODO доделать
|
||||||
|
|
||||||
|
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, _ = fmt.Fprintf(w, "ok")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, _ = fmt.Fprintf(w, "Hello world!")
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Printf("Starting server at port %d...", conf.Port)
|
||||||
|
if err = http.ListenAndServe(fmt.Sprintf(":%d", conf.Port), nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
41
pink_fox_app/internal/app/config/config.go
Normal file
41
pink_fox_app/internal/app/config/config.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DB struct {
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
User string `yaml:"user"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
Port string `yaml:"port"`
|
||||||
|
Database string `yaml:"database"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
Db DB `yaml:"db"`
|
||||||
|
LogFile string `yaml:"logFile"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig(defaultConfig string, defaultPort int) (*Config, error) {
|
||||||
|
data, err := os.ReadFile(defaultConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ошибка чтения файла конфига: %s", err)
|
||||||
|
}
|
||||||
|
var config Config
|
||||||
|
err = yaml.Unmarshal(data, &config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("не получилось распарсить конфиг: %s", err)
|
||||||
|
}
|
||||||
|
return setDefaultValue(&config, defaultPort), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefaultValue(config *Config, defaultPort int) *Config {
|
||||||
|
if config.Port == 0 {
|
||||||
|
config.Port = defaultPort
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
30
pink_fox_app/internal/app/db/db.go
Normal file
30
pink_fox_app/internal/app/db/db.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
"pink_fox/internal/app/config"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateConnection(dbConf *config.DB) (*sql.DB, error) {
|
||||||
|
psqlInfo := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
|
||||||
|
dbConf.Host, dbConf.Port, dbConf.User, dbConf.Password, dbConf.Database)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var db *sql.DB
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
db, err = sql.Open("postgres", psqlInfo)
|
||||||
|
if err == nil {
|
||||||
|
err = db.Ping()
|
||||||
|
if err == nil {
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("не удалось подключиться к базе данных: %v", err)
|
||||||
|
}
|
||||||
30
pink_fox_app/internal/app/log/log.go
Normal file
30
pink_fox_app/internal/app/log/log.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
file *os.File
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger(path string) (*Logger, error) {
|
||||||
|
file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("не удалось открыть файл лога: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := slog.New(slog.NewTextHandler(file, nil))
|
||||||
|
|
||||||
|
return &Logger{
|
||||||
|
file: file,
|
||||||
|
Logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *Logger) Close() error {
|
||||||
|
return it.file.Close()
|
||||||
|
}
|
||||||
3
pink_fox_app/internal/app/timer/timer.go
Normal file
3
pink_fox_app/internal/app/timer/timer.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package timer
|
||||||
|
|
||||||
|
// TODO
|
||||||
15
pink_fox_app/main.go
Normal file
15
pink_fox_app/main.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"pink_fox/internal/app/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := cmd.Execute()
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,29 +14,32 @@ if [[ ! -d "/go/bin" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$ARG1" = "debug" ]; then
|
if [ "$ARG1" = "debug" ]; then
|
||||||
# Приложение готовое для дебага
|
# Собираем приложение для дебага
|
||||||
cd /app || exit 1
|
cd /app || exit 1
|
||||||
rm -f "./dist/local_app_name"
|
rm -f "/dist/local_app_name"
|
||||||
echo "" > out.log
|
echo "" > /app/out.log
|
||||||
|
echo "" > /app/err.log
|
||||||
|
echo "" > /app/dlv.log
|
||||||
|
|
||||||
pkill -f /app/dist/local_app_name
|
pkill -f /dist/local_app_name
|
||||||
|
|
||||||
go build -gcflags "all=-N -l" -o ./dist/local_app_name 2> /app/out.log
|
go build -gcflags "all=-N -l" -o /dist/local_app_name > /app/out.log 2> /app/err.log
|
||||||
|
|
||||||
if [ ! -s "/app/out.log" ]; then
|
if [ ! -s "/app/err.log" ]; then
|
||||||
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /app/dist/local_app_name > /app/out.log 2>&1
|
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /dist/local_app_name server > /app/out.log 2> /app/dlv.log
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Простое приложение
|
# Собираем приложение
|
||||||
cd /app || exit 1
|
cd /app || exit 1
|
||||||
rm -f "./dist/local_app_name"
|
rm -f "/dist/local_app_name"
|
||||||
echo "" > out.log
|
echo "" > /app/out.log
|
||||||
|
echo "" > /app/err.log
|
||||||
|
|
||||||
pkill -f /app/dist/local_app_name
|
pkill -f /dist/local_app_name
|
||||||
|
|
||||||
go build -o "./dist/local_app_name" 2> /app/out.log
|
go build -o "/dist/local_app_name" > /app/out.log 2> /app/err.log
|
||||||
|
|
||||||
if [ ! -s "/app/out.log" ]; then
|
if [ ! -s "/app/err.log" ]; then
|
||||||
/app/dist/local_app_name > /app/out.log 2>&1
|
/dist/local_app_name server > /app/out.log 2> /app/err.log
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -6,6 +6,10 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
file_out = "out.log"
|
||||||
|
file_err = "err.log"
|
||||||
|
url_ping = "http://localhost:12001/ping"
|
||||||
|
|
||||||
# Останавливаем контейнер без задержки
|
# Останавливаем контейнер без задержки
|
||||||
subprocess.run(["docker", "compose", "stop", "site", "-t", "0"])
|
subprocess.run(["docker", "compose", "stop", "site", "-t", "0"])
|
||||||
|
|
||||||
@ -22,30 +26,36 @@ attempt_count = 0
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# Отправляем запрос для проверки поднялся ли HTTP сервер
|
# Отправляем запрос для проверки поднялся ли HTTP сервер
|
||||||
response = requests.get("http://localhost:12001/ping", timeout=5)
|
response = requests.get(url_ping, timeout=5)
|
||||||
|
|
||||||
# Проверяем ответ
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
print("Сервер запущен")
|
print("Сервер запущен")
|
||||||
break
|
break
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
|
# смотрим есть ли ошибки в err.log
|
||||||
try:
|
try:
|
||||||
with open("out.log", 'r') as file:
|
with open(file_err, 'r') as ferr:
|
||||||
|
err_content = ferr.read().strip()
|
||||||
|
if err_content:
|
||||||
|
print("Имеется ошибка компиляции или запуска, смотри файл " + file_err)
|
||||||
|
exit(1)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Лог файл" + file_err + " не найден, проверьте путь")
|
||||||
|
print("Текущая директория" + os.getcwd())
|
||||||
|
|
||||||
|
# смотрим есть ли запись о старте дебагера
|
||||||
|
try:
|
||||||
|
with open(file_out, 'r') as file:
|
||||||
content = file.read().strip()
|
content = file.read().strip()
|
||||||
if content:
|
if content:
|
||||||
# Лог файл не пуст, возможно, есть ошибки сборки
|
# Лог файл не пуст, возможно запущен дебагер и ping дожидаться не стоит
|
||||||
if content.startswith("API server listening at: [::]:2345"):
|
if content.startswith("API server listening at: [::]:2345"):
|
||||||
# Лог файл начинается с сообщения о старте дебагера, ошибок нет
|
# Лог файл начинается с сообщения о старте дебагера, ошибок нет
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
print("Имеется ошибка компиляции, смотри файл out.log")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Лог файл не найден, проверьте путь")
|
print("Лог файл " + file_out + " не найден, проверьте путь")
|
||||||
print("Текущая директория" + os.getcwd())
|
print("Текущая директория" + os.getcwd())
|
||||||
|
|
||||||
# Если не удалось подключиться, увеличиваем счетчик попыток
|
# Если не удалось подключиться или не обнаружен старт дебагера то увеличиваем счетчик попыток
|
||||||
attempt_count += 1
|
attempt_count += 1
|
||||||
print(f"Ждем... ({attempt_count})")
|
print(f"Ждем... ({attempt_count})")
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user