парсер

This commit is contained in:
Artem Tsyrulnikov
2026-01-06 21:04:42 +03:00
parent b77e4fd0b6
commit 2c0ae2dfc3
45 changed files with 2202 additions and 51 deletions

View File

@@ -0,0 +1,36 @@
package logger
import (
"os"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
type Config struct {
Level string `default:"info" envconfig:"LOGGER__LEVEL"`
PrettyConsole bool `default:"false" envconfig:"LOGGER__PRETTY_CONSOLE"`
}
func Init(c Config) {
zerolog.TimeFieldFormat = time.RFC3339
level := zerolog.InfoLevel
if parsedLevel, err := zerolog.ParseLevel(c.Level); err == nil {
level = parsedLevel
}
zerolog.SetGlobalLevel(level)
log.Logger = log.With().
// Caller().
// Str("app_name", c.AppName).
// Str("app_version", c.AppVersion).
Logger()
if c.PrettyConsole {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"})
}
log.Info().Msg("Logger initialized")
}

View File

@@ -0,0 +1,37 @@
package postgres
import (
"context"
"fmt"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/rs/zerolog/log"
)
type Config struct {
URL string `envconfig:"DB__URL" required:"true"`
}
type Pool struct {
*pgxpool.Pool
}
func New(ctx context.Context, c Config) (*Pool, error) {
cfg, err := pgxpool.ParseConfig(c.URL)
if err != nil {
return nil, fmt.Errorf("pgxpool.ParseConfig: %w", err)
}
pool, err := pgxpool.NewWithConfig(ctx, cfg)
if err != nil {
return nil, fmt.Errorf("pgxpool.NewWithConfig: %w", err)
}
return &Pool{Pool: pool}, nil
}
func (p *Pool) Close() {
p.Pool.Close()
log.Info().Msg("Postgres closed")
}

View File

@@ -0,0 +1,76 @@
package telegram
import (
"context"
"fmt"
"github.com/rs/zerolog/log"
"github.com/gotd/td/session"
"github.com/gotd/td/telegram"
)
type Config struct {
ApiID int `envconfig:"TELEGRAM__API_ID" required:"true"`
ApiHash string `envconfig:"TELEGRAM__API_HASH" required:"true"`
SessionFile string `envconfig:"TELEGRAM__SESSION_FILE" required:"true"`
}
type Client struct {
*telegram.Client
cancel context.CancelFunc
done chan struct{}
}
func New(cfg Config) (*Client, error) {
ctx := context.Background()
tg := telegram.NewClient(cfg.ApiID, cfg.ApiHash, telegram.Options{
SessionStorage: &session.FileStorage{Path: cfg.SessionFile},
})
runCtx, cancel := context.WithCancel(ctx)
ready := make(chan struct{})
done := make(chan struct{})
client := &Client{
Client: tg,
cancel: cancel,
done: done,
}
go func() {
err := tg.Run(runCtx, func(ctx context.Context) error {
status, err := tg.Auth().Status(ctx)
if err != nil {
close(ready)
return fmt.Errorf("telegram.Auth error: %w", err)
}
if !status.Authorized {
close(ready)
return fmt.Errorf("session not authorized")
}
close(ready)
<-ctx.Done()
return ctx.Err()
})
if err != nil {
log.Error().Err(err).Msg("telegram client stopped")
}
close(done)
}()
<-ready
return client, nil
}
func (c *Client) Close() {
c.cancel()
<-c.done
}

View File

@@ -0,0 +1,101 @@
package transaction
import (
"context"
"errors"
"fmt"
"github.com/TelegramExchange/tgex-parser/pkg/postgres"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/rs/zerolog/log"
)
var (
errMissingInit = errors.New("missing `transaction.Init' call before `transaction.Begin'")
errMissingBegin = errors.New("missing `transaction.Begin' call before 'transaction.Get'")
)
var (
pool *pgxpool.Pool
IsUnitTest bool
)
type ctxKey struct{}
func Init(p *postgres.Pool) {
pool = p.Pool
}
type Transaction struct {
pgx.Tx
}
func Begin(ctx context.Context) (context.Context, error) {
if IsUnitTest {
return ctx, nil
}
if pool == nil {
return nil, errMissingInit
}
tx, err := pool.Begin(ctx)
if err != nil {
return nil, fmt.Errorf("pool.Begin: %w", err)
}
ctx = context.WithValue(ctx, ctxKey{}, &Transaction{tx})
return ctx, nil
}
func Rollback(ctx context.Context) {
if IsUnitTest {
return
}
tx, ok := ctx.Value(ctxKey{}).(*Transaction)
if !ok {
return
}
err := tx.Rollback(ctx)
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
log.Error().Err(err).Msg("transaction: Rollback")
}
}
func Commit(ctx context.Context) error {
if IsUnitTest {
return nil
}
tx, ok := ctx.Value(ctxKey{}).(*Transaction)
if !ok {
return errMissingBegin
}
err := tx.Commit(ctx)
if err != nil {
return fmt.Errorf("tx.Commit: %w", err)
}
return nil
}
type Executor interface {
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
}
func TryExtractTX(ctx context.Context) Executor {
tx, ok := ctx.Value(ctxKey{}).(*Transaction)
if !ok {
return pool
}
return tx
}

View File

@@ -0,0 +1,38 @@
package transaction
import (
"context"
"errors"
"fmt"
"github.com/jackc/pgx/v5"
"github.com/rs/zerolog/log"
)
func Wrap(ctx context.Context, fn func(context.Context) error) error {
tx, err := pool.Begin(ctx)
if err != nil {
return fmt.Errorf("pool.Begin: %w", err)
}
defer func() {
err = tx.Rollback(ctx)
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
log.Error().Err(err).Msg("transaction: Rollback")
}
}()
ctx = context.WithValue(ctx, ctxKey{}, &Transaction{tx})
err = fn(ctx)
if err != nil {
return fmt.Errorf("fn: %w", err)
}
err = tx.Commit(ctx)
if err != nil {
return fmt.Errorf("tx.Commit: %w", err)
}
return nil
}