hw12_13_14_15_calendar
Andrey Ivanov 2020-11-27 17:20:41 +03:00 committed by tiburon
parent cdf7bf9441
commit b7db72ceb4
14 changed files with 109 additions and 60 deletions

View File

@ -34,11 +34,9 @@ func main() {
if err != nil {
oslog.Fatal("can't get config:", err.Error())
}
oslog.Printf("Переменная APP_GRPC_PORT: %#v", os.Getenv("APP_GRPC_PORT"))
oslog.Printf("Конфиг приложения: %#v", conf)
log, err := logger.New(logger.Config(conf.Logger))
if err != nil {
oslog.Fatal("не удалось запустить логер:", err.Error())
oslog.Fatal("can't start logger:", err.Error())
}
st := store.NewStore(store.Config(conf.Storage))

View File

@ -1,6 +1,8 @@
package private
import (
"fmt"
"github.com/golang/protobuf/ptypes"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/storage/event"
)
@ -13,7 +15,7 @@ func (s Service) buildEventList(evtMap map[event.ID]event.Event) ([]*Event, erro
evt := Event{ID: int64(k), Title: v.Title, UserID: v.UserID}
evt.Date, err = ptypes.TimestampProto(v.Date)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't convert date: %w", err)
}
events[i] = &evt
i++

View File

@ -1,6 +1,7 @@
package private
import (
"fmt"
"net"
"google.golang.org/grpc"
@ -9,7 +10,7 @@ import (
func NewClient(addr, port string) (GrpcClient, error) {
conn, err := grpc.Dial(net.JoinHostPort(addr, port), grpc.WithInsecure())
if err != nil {
return nil, err
return nil, fmt.Errorf("can't dial GRPC server: %w", err)
}
client := NewGrpcClient(conn)
return client, nil

View File

@ -2,6 +2,7 @@ package private
import (
"context"
"fmt"
"net"
"github.com/golang/protobuf/ptypes/empty"
@ -43,10 +44,12 @@ func (s *Service) Stop() {
func (s Service) GetNotifications(ctx context.Context, e *empty.Empty) (*GetRsp, error) {
tmp, err := s.App.Storage.GetNotifications()
if err != nil {
s.App.Logger.Errorf("storage error: can't get list of events: %w", err)
return nil, status.Errorf(codes.Internal, "storage error: can't get list of events")
}
l, err := s.buildEventList(tmp)
if err != nil {
s.App.Logger.Errorf("inconvertible: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
return &GetRsp{Events: l}, nil
@ -58,5 +61,8 @@ func (s Service) SetNotified(ctx context.Context, r *SetReq) (*empty.Empty, erro
func (s Service) PurgeOldEvents(ctx context.Context, r *PurgeReq) (*PurgeResp, error) {
q, err := s.App.Storage.PurgeOldEvents(r.OlderThenDays)
return &PurgeResp{Qty: q}, err
if err != nil {
return &PurgeResp{}, fmt.Errorf("can't purge old events from storage: %w", err)
}
return &PurgeResp{Qty: q}, nil
}

View File

@ -3,6 +3,7 @@ package sender
import (
"context"
"encoding/json"
"fmt"
oslog "log"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/api/private"
@ -26,7 +27,7 @@ type Config struct {
func New(conf Config) Sender {
log, err := logger.New(logger.Config(conf.Logger))
if err != nil {
oslog.Fatal("не удалось запустить логер:", err.Error())
oslog.Fatal("can't start logger:", err.Error())
}
rb, err := rabbit.Attach(rabbit.Config(conf.Rabbitmq))
if err != nil {
@ -40,7 +41,7 @@ func (s *Sender) Start() error {
s.Stop = cancel
msg, err := s.Rabbit.Consume(ctx, s.Queue)
if err != nil {
return err
return fmt.Errorf("can't consume RabbitMQ queue: %w", err)
}
go func() {
@ -50,7 +51,7 @@ func (s *Sender) Start() error {
var data []private.Event
err := json.Unmarshal(m.Data, &data)
if err != nil {
s.Logger.Errorf("can`t unmarshal data", err)
s.Logger.Errorf("can`t unmarshal data %w", err)
}
for _, v := range data {
s.Logger.Infof("User %s notified about event %s", v.UserID, v.ID)

View File

@ -27,7 +27,7 @@ type Config struct {
func New(conf Config) Scheduler {
log, err := logger.New(logger.Config(conf.Logger))
if err != nil {
oslog.Fatal("не удалось запустить логер:", err.Error())
oslog.Fatal("can't start logger:", err.Error())
}
rb, err := rabbit.New(rabbit.Config(conf.Rabbitmq))
if err != nil {

View File

@ -1,6 +1,7 @@
package public
import (
"fmt"
"time"
"github.com/golang/protobuf/ptypes"
@ -11,15 +12,15 @@ func (s Service) buildStorageEvent(pbe *CreateReq) (res event.Event, err error)
res = event.Event{Title: pbe.Title, Note: pbe.Note, UserID: pbe.UserID}
res.Date, err = ptypes.Timestamp(pbe.Date)
if err != nil {
return event.Event{}, err
return event.Event{}, fmt.Errorf("can't convert date: %w", err)
}
res.Latency, err = ptypes.Duration(pbe.Latency)
if err != nil {
return event.Event{}, err
return event.Event{}, fmt.Errorf("can't convert duration: %w", err)
}
res.NotifyTime, err = ptypes.Duration(pbe.NotifyTime)
if err != nil {
return event.Event{}, err
return event.Event{}, fmt.Errorf("can't convert duration: %w", err)
}
return res, nil
}
@ -28,15 +29,15 @@ func (s Service) buildStorageEventAndID(pbe *UpdateReq) (id event.ID, evt event.
evt = event.Event{Title: pbe.Event.Title, Note: pbe.Event.Note, UserID: pbe.Event.UserID}
evt.Date, err = ptypes.Timestamp(pbe.Event.Date)
if err != nil {
return 0, event.Event{}, err
return 0, event.Event{}, fmt.Errorf("can't convert time: %w", err)
}
evt.Latency, err = ptypes.Duration(pbe.Event.Latency)
if err != nil {
return 0, event.Event{}, err
return 0, event.Event{}, fmt.Errorf("can't convert duration: %w", err)
}
evt.NotifyTime, err = ptypes.Duration(pbe.Event.NotifyTime)
if err != nil {
return 0, event.Event{}, err
return 0, event.Event{}, fmt.Errorf("can't convert duration: %w", err)
}
return event.ID(pbe.ID), evt, nil
}
@ -49,7 +50,7 @@ func (s Service) buildEventList(evtMap map[event.ID]event.Event) ([]*Event, erro
evt := Event{ID: int64(k), Title: v.Title, Latency: ptypes.DurationProto(v.Latency), Note: v.Note, UserID: v.UserID, NotifyTime: ptypes.DurationProto(v.NotifyTime)}
evt.Date, err = ptypes.TimestampProto(v.Date)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't convert date: %w", err)
}
events[i] = &evt
i++
@ -59,5 +60,8 @@ func (s Service) buildEventList(evtMap map[event.ID]event.Event) ([]*Event, erro
func (s Service) buildTimeAndRange(e *GetByDateReq) (start time.Time, qrange string, err error) {
date, err := ptypes.Timestamp(e.Date)
return date, e.Range.String(), err
if err != nil {
return time.Time{}, "", fmt.Errorf("can't convert date: %w", err)
}
return date, e.Range.String(), nil
}

View File

@ -1,6 +1,7 @@
package public
import (
"fmt"
"net"
"google.golang.org/grpc"
@ -9,7 +10,7 @@ import (
func NewClient(addr, port string) (GrpcClient, error) {
conn, err := grpc.Dial(net.JoinHostPort(addr, port), grpc.WithInsecure())
if err != nil {
return nil, err
return nil, fmt.Errorf("can't dial GRPC server: %w", err)
}
client := NewGrpcClient(conn)
return client, nil

View File

@ -40,10 +40,12 @@ func (s Service) Create(ctx context.Context, e *CreateReq) (*CreateRsp, error) {
var res CreateRsp
ce, err := s.buildStorageEvent(e)
if err != nil {
s.App.Logger.Errorf("inconvertible event: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
t, err := s.App.Storage.Create(ce)
if err != nil {
s.App.Logger.Errorf("can't create event in storage: %w", err)
return nil, status.Errorf(codes.Internal, "storage error: can't create event")
}
res.ID = int64(t)
@ -53,16 +55,19 @@ func (s Service) Create(ctx context.Context, e *CreateReq) (*CreateRsp, error) {
func (s Service) Update(ctx context.Context, e *UpdateReq) (*empty.Empty, error) {
cid, ce, err := s.buildStorageEventAndID(e)
if err != nil {
s.App.Logger.Errorf("inconvertible event: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
if s.App.Storage.Update(cid, ce) != nil {
s.App.Logger.Errorf("can't update event in storage: %w", err)
return nil, status.Errorf(codes.Internal, "storage error: can't update event")
}
return nil, nil
}
func (s Service) Delete(ctx context.Context, e *DeleteReq) (*empty.Empty, error) {
if s.App.Storage.Delete(event.ID(e.ID)) != nil {
if err := s.App.Storage.Delete(event.ID(e.ID)); err != nil {
s.App.Logger.Errorf("can't update event in storage: %w", err)
return nil, status.Errorf(codes.Internal, "storage error: can't update event")
}
return nil, nil
@ -71,10 +76,12 @@ func (s Service) Delete(ctx context.Context, e *DeleteReq) (*empty.Empty, error)
func (s Service) List(ctx context.Context, e *empty.Empty) (*ListResp, error) {
tmp, err := s.App.Storage.List()
if err != nil {
s.App.Logger.Errorf("can't get list of events from storage: %w", err)
return nil, status.Errorf(codes.Internal, "storage error: can't get list of events")
}
l, err := s.buildEventList(tmp)
if err != nil {
s.App.Logger.Errorf("inconvertible list of events: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
return &ListResp{Events: l}, nil
@ -83,10 +90,12 @@ func (s Service) List(ctx context.Context, e *empty.Empty) (*ListResp, error) {
func (s Service) GetByID(ctx context.Context, e *GetByIDReq) (*GetByIDResp, error) {
tmp, ok := s.App.Storage.GetByID(event.ID(e.ID))
if !ok {
s.App.Logger.Errorf("event with ID %s not found in storage", e.ID)
return nil, status.Errorf(codes.NotFound, "event not found")
}
l, err := s.buildEventList(map[event.ID]event.Event{event.ID(e.ID): tmp})
if err != nil {
s.App.Logger.Errorf("inconvertible list of events: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
return &GetByIDResp{Events: l}, nil
@ -95,14 +104,17 @@ func (s Service) GetByID(ctx context.Context, e *GetByIDReq) (*GetByIDResp, erro
func (s Service) GetByDate(ctx context.Context, e *GetByDateReq) (*GetByDateResp, error) {
d, r, err := s.buildTimeAndRange(e)
if err != nil {
s.App.Logger.Errorf("inconvertible time range: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
tmp, err := s.App.Storage.GetByDate(d, r)
if err != nil {
s.App.Logger.Errorf("can't get list of events from storage: %w", err)
return nil, status.Errorf(codes.Internal, "storage error: can't get list of events")
}
l, err := s.buildEventList(tmp)
if err != nil {
s.App.Logger.Errorf("inconvertible list of events: %w", err)
return nil, status.Errorf(codes.Internal, "inconvertible")
}
return &GetByDateResp{Events: l}, nil

View File

@ -1,6 +1,7 @@
package config
import (
"fmt"
"io/ioutil"
"os"
"reflect"
@ -8,25 +9,28 @@ import (
"strings"
"github.com/BurntSushi/toml"
"github.com/pkg/errors"
)
func New(configFile string, str interface{}) error {
if configFile == "" {
return ApplyEnvVars(str, "APP")
err := ApplyEnvVars(str, "APP")
if err != nil {
return fmt.Errorf("can't apply envvars to config :%w", err)
}
return nil
}
f, err := os.Open(configFile)
if err != nil {
return err
return fmt.Errorf("can't open config file: %w", err)
}
defer f.Close()
s, err := ioutil.ReadAll(f)
if err != nil {
return err
return fmt.Errorf("can't read content of the config file : %w", err)
}
_, err = toml.Decode(string(s), str)
if err != nil {
return err
return fmt.Errorf("can't parce config file : %w", err)
}
return nil
}
@ -39,7 +43,7 @@ func ApplyEnvVars(c interface{}, prefix string) error {
func applyEnvVar(v reflect.Value, t reflect.Type, counter int, prefix string) error {
if v.Kind() != reflect.Ptr {
return errors.New("not a pointer value")
return fmt.Errorf("not a pointer value")
}
f := reflect.StructField{}
if counter != -1 {
@ -53,7 +57,7 @@ func applyEnvVar(v reflect.Value, t reflect.Type, counter int, prefix string) er
case reflect.Int:
envI, err := strconv.Atoi(env)
if err != nil {
return errors.Wrap(err, "could not parse to int")
return fmt.Errorf("could not parse to int: %w", err)
}
v.SetInt(int64(envI))
case reflect.String:
@ -61,7 +65,7 @@ func applyEnvVar(v reflect.Value, t reflect.Type, counter int, prefix string) er
case reflect.Bool:
envB, err := strconv.ParseBool(env)
if err != nil {
return errors.Wrap(err, "could not parse bool")
return fmt.Errorf("could not parse bool: %w", err)
}
v.SetBool(envB)
}
@ -69,7 +73,7 @@ func applyEnvVar(v reflect.Value, t reflect.Type, counter int, prefix string) er
if v.Kind() == reflect.Struct {
for i := 0; i < v.NumField(); i++ {
if err := applyEnvVar(v.Field(i).Addr(), v.Type(), i, prefix+fName+"_"); err != nil {
return errors.Wrap(err, "could not apply env var")
return fmt.Errorf("could not apply env var: %w", err)
}
}
}

View File

@ -47,7 +47,7 @@ func New(conf Config) (Interface, error) {
if err := amitralog.NewLogger(c, amitralog.InstanceZapLogger); err != nil {
log.Fatalf("Could not instantiate log %s", err.Error())
}
l := amitralog.WithFields(amitralog.Fields{"hw": "12"})
l := amitralog.WithFields(amitralog.Fields{"hw": "15"})
l.Infof("logger start successful")
return l, nil
}

View File

@ -2,6 +2,7 @@ package rabbit
import (
"encoding/json"
"fmt"
"github.com/streadway/amqp"
)
@ -9,7 +10,7 @@ import (
func (r *Rabbit) Publish(body string) error {
b, err := json.Marshal([]byte(body))
if err != nil {
return err
return fmt.Errorf("can't marshal message body into JSON: %w", err)
}
err = r.Channel.Publish(
r.Exchange, // exchange
@ -21,7 +22,7 @@ func (r *Rabbit) Publish(body string) error {
Body: b,
})
if err != nil {
return err
return fmt.Errorf("can't publish message into RabbitMQ exchange: %w", err)
}
return nil
}

View File

@ -1,6 +1,8 @@
package rabbit
import (
"fmt"
"github.com/streadway/amqp"
)
@ -25,11 +27,11 @@ type Config struct {
func New(conf Config) (*Rabbit, error) {
conn, err := amqp.Dial("amqp://" + conf.Login + ":" + conf.Pass + "@" + conf.Address + ":" + conf.Port + "/")
if err != nil {
return nil, err
return nil, fmt.Errorf("can't dial RabbitMQ over AMQP: %w", err)
}
ch, err := conn.Channel()
if err != nil {
return nil, err
return nil, fmt.Errorf("can't get channel from AMQP connection: %w", err)
}
err = ch.ExchangeDeclare(
conf.Exchange, // name
@ -41,7 +43,7 @@ func New(conf Config) (*Rabbit, error) {
nil, // arguments
)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't (re)declare exchange in RabbitMQ: %w", err)
}
q, err := ch.QueueDeclare(
conf.Queue,
@ -52,11 +54,11 @@ func New(conf Config) (*Rabbit, error) {
nil,
)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't (re)create queue in RabbitMQ: %w", err)
}
err = ch.QueueBind(q.Name, conf.Key, conf.Exchange, false, nil)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't bind Queue on Exchange in RabbitMQ: %w", err)
}
return &Rabbit{Connection: conn, Channel: ch}, nil
}
@ -64,21 +66,21 @@ func New(conf Config) (*Rabbit, error) {
func Attach(conf Config) (*Rabbit, error) {
conn, err := amqp.Dial("amqp://" + conf.Login + ":" + conf.Pass + "@" + conf.Address + ":" + conf.Port + "/")
if err != nil {
return nil, err
return nil, fmt.Errorf("can't dial RabbitMQ over AMQP: %w", err)
}
ch, err := conn.Channel()
if err != nil {
return nil, err
return nil, fmt.Errorf("can't get channel from AMQP connection: %w", err)
}
return &Rabbit{Connection: conn, Channel: ch, Exchange: conf.Exchange, Queue: conf.Queue, Key: conf.Key}, nil
}
func (r *Rabbit) Close() error {
if err := r.Channel.Close(); err != nil {
return err
return fmt.Errorf("can't close connection channel: %w", err)
}
if err := r.Connection.Close(); err != nil {
return err
return fmt.Errorf("can't close connection: %w", err)
}
return nil
}

View File

@ -2,6 +2,7 @@ package sql
import (
"database/sql"
"fmt"
"time"
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/pkg/storage/event"
@ -29,7 +30,7 @@ func (s *Storage) Connect(config Config) error {
var err error
s.db, err = sql.Open("mysql", config.User+":"+config.Pass+"@tcp("+config.Host+":"+config.Port+")/"+config.Dbase)
if err != nil {
return err
return fmt.Errorf("can't connect to SQL server: %w", err)
}
return nil
}
@ -51,9 +52,12 @@ func (s *Storage) Create(ev event.Event) (event.ID, error) {
ev.NotifyTime,
)
if err != nil {
return -1, err
return -1, fmt.Errorf("can't create event in SQL DB: %w", err)
}
idint64, err := res.LastInsertId()
if err != nil {
return -1, fmt.Errorf("can't get LastInsertId from SQL DB: %w", err)
}
return event.ID(idint64), err
}
@ -70,7 +74,10 @@ func (s *Storage) Update(id event.ID, event event.Event) error {
event.NotifyTime,
id,
)
return err
if err != nil {
return fmt.Errorf("can't update event in SQL DB: %w", err)
}
return nil
}
func (s *Storage) Delete(id event.ID) error {
@ -78,14 +85,17 @@ func (s *Storage) Delete(id event.ID) error {
`DELETE from events where id=$1`,
id,
)
return err
if err != nil {
return fmt.Errorf("can't delete event from SQL DB: %w", err)
}
return nil
}
func (s *Storage) List() (map[event.ID]event.Event, error) {
res := make(map[event.ID]event.Event)
results, err := s.db.Query(`SELECT (id,title,date,latency,note,userID,notifyTime) from events ORDER BY id`)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err)
}
defer results.Close()
for results.Next() {
@ -94,16 +104,16 @@ func (s *Storage) List() (map[event.ID]event.Event, error) {
var dateRaw string
err = results.Scan(&id, &evt.Title, &dateRaw, &evt.Latency, &evt.Note, &evt.UserID, &evt.NotifyTime)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't parce list of events getted from SQL DB: %w", err)
}
evt.Date, err = time.Parse(dateTimeLayout, dateRaw)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't parce Date getted from SQL DB: %w", err)
}
res[id] = evt
}
if results.Err() != nil {
return nil, results.Err()
return nil, fmt.Errorf("something happens while we try to parce lines getted from SQL DB: %w", results.Err())
}
return res, nil
}
@ -136,7 +146,7 @@ func (s *Storage) GetByDate(startDate time.Time, rng string) (map[event.ID]event
startDate,
getEndDate(startDate, rng))
if err != nil {
return nil, err
return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err)
}
defer results.Close()
for results.Next() {
@ -145,16 +155,16 @@ func (s *Storage) GetByDate(startDate time.Time, rng string) (map[event.ID]event
var dateRaw string
err = results.Scan(&id, &evt.Title, &dateRaw, &evt.Latency, &evt.Note, &evt.UserID, &evt.NotifyTime)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't parce list of events getted from SQL DB: %w", err)
}
evt.Date, err = time.Parse(dateTimeLayout, dateRaw)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't parce Date getted from SQL DB: %w", err)
}
res[id] = evt
}
if results.Err() != nil {
return nil, results.Err()
return nil, fmt.Errorf("something happens while we try to parce lines getted from SQL DB: %w", results.Err())
}
return res, nil
}
@ -168,7 +178,7 @@ func (s *Storage) GetNotifications() (map[event.ID]event.Event, error) {
ORDER BY id`,
time.Now())
if err != nil {
return nil, err
return nil, fmt.Errorf("can't get list of events from SQL DB: %w", err)
}
defer results.Close()
for results.Next() {
@ -177,16 +187,16 @@ func (s *Storage) GetNotifications() (map[event.ID]event.Event, error) {
var dateRaw string
err = results.Scan(&id, &evt.Title, &dateRaw, &evt.Latency, &evt.Note, &evt.UserID, &evt.NotifyTime)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't parce list of events getted from SQL DB: %w", err)
}
evt.Date, err = time.Parse(dateTimeLayout, dateRaw)
if err != nil {
return nil, err
return nil, fmt.Errorf("can't parce Date getted from SQL DB: %w", err)
}
res[id] = evt
}
if results.Err() != nil {
return nil, results.Err()
return nil, fmt.Errorf("something happens while we try to parce lines getted from SQL DB: %w", results.Err())
}
return res, nil
}
@ -198,7 +208,10 @@ func (s *Storage) SetNotified(id event.ID) error {
where id=$1`,
id,
)
return err
if err != nil {
return fmt.Errorf("can't set event as notified in SQL DB: %w", err)
}
return nil
}
func (s *Storage) PurgeOldEvents(days int64) (int64, error) {
@ -207,9 +220,13 @@ func (s *Storage) PurgeOldEvents(days int64) (int64, error) {
time.Now().Add(-time.Duration(days*24*60*60)),
)
if err != nil {
return 0, err
return 0, fmt.Errorf("can't delete old events from SQL DB: %w", err)
}
return r.RowsAffected()
l, err := r.RowsAffected()
if err != nil {
return 0, fmt.Errorf("can't run RowAffected on SQL DB query: %w", err)
}
return l, nil
}
func getEndDate(startDate time.Time, rng string) time.Time {