Обновлена среда разработки и добавлен новый функционал в сервер
- Улучшена среда разработки, поправлены косяки старта дебагера - Добавлен логер в приложение - Добавлен 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"
|
||||
- "12002:2345"
|
||||
volumes:
|
||||
- ./application:/app
|
||||
- ./dist:/app/dist
|
||||
- ./pink_fox_app:/app
|
||||
- ./dist:/dist
|
||||
- ./environment:/var/environment/pink_fox
|
||||
- ./log:/var/log/pink_fox
|
||||
- ./.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
|
||||
|
||||
if [ "$ARG1" = "debug" ]; then
|
||||
# Приложение готовое для дебага
|
||||
# Собираем приложение для дебага
|
||||
cd /app || exit 1
|
||||
rm -f "./dist/local_app_name"
|
||||
echo "" > out.log
|
||||
rm -f "/dist/local_app_name"
|
||||
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
|
||||
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /app/dist/local_app_name > /app/out.log 2>&1
|
||||
if [ ! -s "/app/err.log" ]; then
|
||||
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec /dist/local_app_name server > /app/out.log 2> /app/dlv.log
|
||||
fi
|
||||
else
|
||||
# Простое приложение
|
||||
# Собираем приложение
|
||||
cd /app || exit 1
|
||||
rm -f "./dist/local_app_name"
|
||||
echo "" > out.log
|
||||
rm -f "/dist/local_app_name"
|
||||
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
|
||||
/app/dist/local_app_name > /app/out.log 2>&1
|
||||
if [ ! -s "/app/err.log" ]; then
|
||||
/dist/local_app_name server > /app/out.log 2> /app/err.log
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -6,6 +6,10 @@ import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
file_out = "out.log"
|
||||
file_err = "err.log"
|
||||
url_ping = "http://localhost:12001/ping"
|
||||
|
||||
# Останавливаем контейнер без задержки
|
||||
subprocess.run(["docker", "compose", "stop", "site", "-t", "0"])
|
||||
|
||||
@ -22,30 +26,36 @@ attempt_count = 0
|
||||
while True:
|
||||
try:
|
||||
# Отправляем запрос для проверки поднялся ли HTTP сервер
|
||||
response = requests.get("http://localhost:12001/ping", timeout=5)
|
||||
|
||||
# Проверяем ответ
|
||||
response = requests.get(url_ping, timeout=5)
|
||||
if response.status_code == 200:
|
||||
print("Сервер запущен")
|
||||
break
|
||||
except requests.ConnectionError:
|
||||
# смотрим есть ли ошибки в err.log
|
||||
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()
|
||||
if content:
|
||||
# Лог файл не пуст, возможно, есть ошибки сборки
|
||||
# Лог файл не пуст, возможно запущен дебагер и ping дожидаться не стоит
|
||||
if content.startswith("API server listening at: [::]:2345"):
|
||||
# Лог файл начинается с сообщения о старте дебагера, ошибок нет
|
||||
break
|
||||
else:
|
||||
print("Имеется ошибка компиляции, смотри файл out.log")
|
||||
exit(1)
|
||||
|
||||
except FileNotFoundError:
|
||||
print("Лог файл не найден, проверьте путь")
|
||||
print("Лог файл " + file_out + " не найден, проверьте путь")
|
||||
print("Текущая директория" + os.getcwd())
|
||||
|
||||
# Если не удалось подключиться, увеличиваем счетчик попыток
|
||||
# Если не удалось подключиться или не обнаружен старт дебагера то увеличиваем счетчик попыток
|
||||
attempt_count += 1
|
||||
print(f"Ждем... ({attempt_count})")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user