mirror of
https://github.com/netscrawler/changeAPI.git
synced 2025-05-06 15:29:53 +00:00
v0.0.6
This commit is contained in:
parent
61d2be39f1
commit
c99f477e35
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
10
.idea/changeAPI.iml
generated
Normal file
10
.idea/changeAPI.iml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="protos" />
|
||||
</component>
|
||||
</module>
|
9
.idea/modules.xml
generated
Normal file
9
.idea/modules.xml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/changeAPI.iml" filepath="$PROJECT_DIR$/.idea/changeAPI.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/../protos/.idea/protos.iml" filepath="$PROJECT_DIR$/../protos/.idea/protos.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
7
.idea/vcs.xml
generated
Normal file
7
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/../protos" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
61
cmd/converter/main.go
Normal file
61
cmd/converter/main.go
Normal file
@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"converter/internal/app"
|
||||
"converter/internal/config"
|
||||
"converter/internal/lib/logger/handlers/slogpretty"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
envlocal = "local"
|
||||
envdev = "dev"
|
||||
envprod = "prod"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
cfg := config.MustLoad()
|
||||
|
||||
fmt.Println(cfg)
|
||||
|
||||
log := setupLogger(cfg.Env)
|
||||
log.Info("starting application", slog.Any("cfg", cfg))
|
||||
applicaton := app.New(log, cfg.GRPC.Port, cfg.TokenTTL)
|
||||
applicaton.GRPCSrv.MustRun()
|
||||
// TODO: инициализировать приложение app
|
||||
|
||||
// TODO: запустить gRPC сервер приложения
|
||||
}
|
||||
|
||||
func setupLogger(env string) *slog.Logger {
|
||||
var log *slog.Logger
|
||||
|
||||
switch env {
|
||||
case envlocal:
|
||||
log = setupPrettySlog()
|
||||
case envdev:
|
||||
log = slog.New(
|
||||
slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}),
|
||||
)
|
||||
case envprod:
|
||||
log = slog.New(
|
||||
slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}),
|
||||
)
|
||||
}
|
||||
return log
|
||||
}
|
||||
|
||||
func setupPrettySlog() *slog.Logger {
|
||||
opts := slogpretty.PrettyHandlerOptions{
|
||||
SlogOpts: &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
}
|
||||
|
||||
handler := opts.NewPrettyHandler(os.Stdout)
|
||||
|
||||
return slog.New(handler)
|
||||
}
|
5
config/local.yaml
Normal file
5
config/local.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
env: "local"
|
||||
token_ttl: 1h
|
||||
grpc:
|
||||
port: 44044
|
||||
timeout: 10h
|
25
go.mod
Normal file
25
go.mod
Normal file
@ -0,0 +1,25 @@
|
||||
module converter
|
||||
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/netscrawler/protos v0.0.5
|
||||
google.golang.org/grpc v1.64.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/ilyakaznacheev/cleanenv v1.5.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect
|
||||
)
|
38
go.sum
Normal file
38
go.sum
Normal file
@ -0,0 +1,38 @@
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/ilyakaznacheev/cleanenv v1.5.0 h1:0VNZXggJE2OYdXE87bfSSwGxeiGt9moSR2lOrsHHvr4=
|
||||
github.com/ilyakaznacheev/cleanenv v1.5.0/go.mod h1:a5aDzaJrLCQZsazHol1w8InnDcOX0OColm64SlIi6gk=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/netscrawler/protos v0.0.0-20240629165054-1454eca14db0 h1:YKByh7dtXFBif3xemj/OFyWbAcw3j/M8tD4U4XF229A=
|
||||
github.com/netscrawler/protos v0.0.0-20240629165054-1454eca14db0/go.mod h1:jgfFUikzJpivreejTHY7s1BWvVpM9/rJdvTntTzcPzc=
|
||||
github.com/netscrawler/protos v0.0.4 h1:D+Cb4cELT9YSIyUsyXL233Zb90ClzOR290aE4i+KI8Y=
|
||||
github.com/netscrawler/protos v0.0.4/go.mod h1:jgfFUikzJpivreejTHY7s1BWvVpM9/rJdvTntTzcPzc=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
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=
|
||||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ=
|
||||
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3/go.mod h1:oVgVk4OWVDi43qWBEyGhXgYxt7+ED4iYNpTngSLX2Iw=
|
23
internal/app/app.go
Normal file
23
internal/app/app.go
Normal file
@ -0,0 +1,23 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
grpcapp "converter/internal/app/grpc"
|
||||
"log/slog"
|
||||
"time"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
GRPCSrv *grpcapp.App
|
||||
}
|
||||
|
||||
func New(
|
||||
log *slog.Logger,
|
||||
grpcPort int,
|
||||
tokenTTl time.Duration) *App {
|
||||
//TODO: инициализировать хранилище
|
||||
//TODO: init convert service
|
||||
grpcApp := grpcapp.New(log, grpcPort)
|
||||
return &App{
|
||||
GRPCSrv: grpcApp,
|
||||
}
|
||||
}
|
62
internal/app/grpc/app.go
Normal file
62
internal/app/grpc/app.go
Normal file
@ -0,0 +1,62 @@
|
||||
package grpcapp
|
||||
|
||||
import (
|
||||
convertgrpc "converter/internal/grpc/cnvrt"
|
||||
"fmt"
|
||||
"google.golang.org/grpc"
|
||||
"log/slog"
|
||||
"net"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
log *slog.Logger
|
||||
gRPCServer *grpc.Server
|
||||
port int
|
||||
}
|
||||
|
||||
func New(
|
||||
log *slog.Logger,
|
||||
port int) *App {
|
||||
gRPCServer := grpc.NewServer()
|
||||
|
||||
convertgrpc.Register(gRPCServer)
|
||||
|
||||
return &App{
|
||||
log: log,
|
||||
gRPCServer: gRPCServer,
|
||||
port: port,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (a *App) MustRun() {
|
||||
if err := a.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Run() error {
|
||||
const op = "grpcapp.Run"
|
||||
log := a.log.With(
|
||||
slog.String("op", op),
|
||||
slog.Int("port", a.port))
|
||||
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%d", a.port))
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
log.Info("gRPC server is running", slog.String("addr", l.Addr().String()))
|
||||
|
||||
if err := a.gRPCServer.Serve(l); err != nil {
|
||||
return fmt.Errorf("%s: %w", op, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) Stop() {
|
||||
const op = "grpcapp.Stop"
|
||||
|
||||
a.log.With(slog.String("op", op)).
|
||||
Info("stopping gRPC server", slog.Int("port", a.port))
|
||||
a.gRPCServer.GracefulStop()
|
||||
}
|
52
internal/config/config.go
Normal file
52
internal/config/config.go
Normal file
@ -0,0 +1,52 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/ilyakaznacheev/cleanenv"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Env string `yaml:"env" env-default:"local"`
|
||||
TokenTTL time.Duration `yaml:"token_ttl" env-required:"true"`
|
||||
GRPC GRPCConfig `yaml:"grpc"`
|
||||
}
|
||||
|
||||
type GRPCConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
}
|
||||
|
||||
func MustLoad() *Config {
|
||||
path := fetchConfigPath()
|
||||
if path == "" {
|
||||
panic("config path is empty")
|
||||
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
panic("config file not found" + path)
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
|
||||
if err := cleanenv.ReadConfig(path, &cfg); err != nil {
|
||||
panic("failed to read config" + err.Error())
|
||||
}
|
||||
|
||||
return &cfg
|
||||
}
|
||||
|
||||
func fetchConfigPath() string {
|
||||
var res string
|
||||
|
||||
flag.StringVar(&res, "config", "", "path to config file")
|
||||
flag.Parse()
|
||||
|
||||
if res == "" {
|
||||
res = os.Getenv("CONFIG_PATH")
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
22
internal/grpc/cnvrt/server.go
Normal file
22
internal/grpc/cnvrt/server.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cnvrt
|
||||
|
||||
import (
|
||||
"context"
|
||||
cnvrtv1 "github.com/netscrawler/protos/gen/go/changeAPI"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type serverAPI struct {
|
||||
cnvrtv1.UnimplementedConverterServer
|
||||
}
|
||||
|
||||
func Register(gRPC *grpc.Server) {
|
||||
cnvrtv1.RegisterConverterServer(gRPC, &serverAPI{})
|
||||
}
|
||||
|
||||
func (s serverAPI) Convert(
|
||||
ctx context.Context,
|
||||
req *cnvrtv1.ConvertRequest) (
|
||||
*cnvrtv1.ConvertResponse, error) {
|
||||
panic("implement me")
|
||||
}
|
36
internal/lib/logger/handlers/slogdiscard/slogdiscard.go
Normal file
36
internal/lib/logger/handlers/slogdiscard/slogdiscard.go
Normal file
@ -0,0 +1,36 @@
|
||||
package slogdiscard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
func NewDiscardLogger() *slog.Logger {
|
||||
return slog.New(NewDiscardHandler())
|
||||
}
|
||||
|
||||
type DiscardHandler struct{}
|
||||
|
||||
func NewDiscardHandler() *DiscardHandler {
|
||||
return &DiscardHandler{}
|
||||
}
|
||||
|
||||
func (h *DiscardHandler) Handle(_ context.Context, _ slog.Record) error {
|
||||
// Просто игнорируем запись журнала
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *DiscardHandler) WithAttrs(_ []slog.Attr) slog.Handler {
|
||||
// Возвращает тот же обработчик, так как нет атрибутов для сохранения
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *DiscardHandler) WithGroup(_ string) slog.Handler {
|
||||
// Возвращает тот же обработчик, так как нет группы для сохранения
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *DiscardHandler) Enabled(_ context.Context, _ slog.Level) bool {
|
||||
// Всегда возвращает false, так как запись журнала игнорируется
|
||||
return false
|
||||
}
|
98
internal/lib/logger/handlers/slogpretty/slogpretty.go
Normal file
98
internal/lib/logger/handlers/slogpretty/slogpretty.go
Normal file
@ -0,0 +1,98 @@
|
||||
package slogpretty
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
stdLog "log"
|
||||
"log/slog"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
type PrettyHandlerOptions struct {
|
||||
SlogOpts *slog.HandlerOptions
|
||||
}
|
||||
|
||||
type PrettyHandler struct {
|
||||
opts PrettyHandlerOptions
|
||||
slog.Handler
|
||||
l *stdLog.Logger
|
||||
attrs []slog.Attr
|
||||
}
|
||||
|
||||
func (opts PrettyHandlerOptions) NewPrettyHandler(
|
||||
out io.Writer,
|
||||
) *PrettyHandler {
|
||||
h := &PrettyHandler{
|
||||
Handler: slog.NewJSONHandler(out, opts.SlogOpts),
|
||||
l: stdLog.New(out, "", 0),
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *PrettyHandler) Handle(_ context.Context, r slog.Record) error {
|
||||
level := r.Level.String() + ":"
|
||||
|
||||
switch r.Level {
|
||||
case slog.LevelDebug:
|
||||
level = color.MagentaString(level)
|
||||
case slog.LevelInfo:
|
||||
level = color.BlueString(level)
|
||||
case slog.LevelWarn:
|
||||
level = color.YellowString(level)
|
||||
case slog.LevelError:
|
||||
level = color.RedString(level)
|
||||
}
|
||||
|
||||
fields := make(map[string]interface{}, r.NumAttrs())
|
||||
|
||||
r.Attrs(func(a slog.Attr) bool {
|
||||
fields[a.Key] = a.Value.Any()
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
for _, a := range h.attrs {
|
||||
fields[a.Key] = a.Value.Any()
|
||||
}
|
||||
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
if len(fields) > 0 {
|
||||
b, err = json.MarshalIndent(fields, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
timeStr := r.Time.Format("[15:05:05.000]")
|
||||
msg := color.CyanString(r.Message)
|
||||
|
||||
h.l.Println(
|
||||
timeStr,
|
||||
level,
|
||||
msg,
|
||||
color.WhiteString(string(b)),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *PrettyHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
return &PrettyHandler{
|
||||
Handler: h.Handler,
|
||||
l: h.l,
|
||||
attrs: attrs,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *PrettyHandler) WithGroup(name string) slog.Handler {
|
||||
// TODO: implement
|
||||
return &PrettyHandler{
|
||||
Handler: h.Handler.WithGroup(name),
|
||||
l: h.l,
|
||||
}
|
||||
}
|
12
internal/lib/logger/sl/sl.go
Normal file
12
internal/lib/logger/sl/sl.go
Normal file
@ -0,0 +1,12 @@
|
||||
package sl
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func Err(err error) slog.Attr {
|
||||
return slog.Attr{
|
||||
Key: "error",
|
||||
Value: slog.StringValue(err.Error()),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user