рдирд┐рдГрд╢реБрд▓реНрдХ рд╕рд╛рд╣рд┐рддреНрдп рдХреЗ рд▓рд┐рдП рдХреВрдкрди рд╕рдВрдЧреНрд░рд╣ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░реЗрдВ

рдкреГрд╖реНрдарднреВрдорд┐


рд▓реАрдЯрд░ рдореЗрдВ рдмреЛрдирд╕ рдФрд░ рдХреВрдкрди рдХреА рдПрдХ рдкреНрд░рдгрд╛рд▓реА рд╣реЛрддреА рд╣реИ рдЬреЛ рдкрд░реНрдпрд╛рд╡рд░рдгреАрдп рдирд┐рдпрдорд┐рддрддрд╛ рдХреЗ рд╕рд╛рде рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИред рдЕрдкрдиреА рдкрддреНрдиреА рдХреЛ рдЦреБрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╡рд╣ рдЕрдкрдиреЗ рд▓рд┐рдП рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдкреБрд╕реНрддрдХ рдкрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЙрд╕рдиреЗ рдЙрд╕ рд╕рд╛рдЗрдЯ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ рдЬрд┐рд╕рдореЗрдВ рддрд╛рдЬреЗ рдХреВрдкрди рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдореЗрдВ рдЧрд┐рд░рд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдХреБрдЫ рджрд┐рдиреЛрдВ рдмрд╛рдж рдореИрдВ рдЗрд╕ рд╡реНрдпрд╡рд╕рд╛рдп рд╕реЗ рдердХ рдЧрдпрд╛ рдерд╛ рдФрд░ рдореИрдВрдиреЗ рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдпрд╣ рд╣рд░ рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╣реЛ рдЬреЛ рдЗрд╕реЗ рдЪрд╛рд╣рддрд╛ рд╣реИред


рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


рдЪреВрдВрдХрд┐ рдореИрдВрдиреЗ рд▓рдЧрд╛рддрд╛рд░ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдореЗрдВ рдирдП рдХреВрдкрди рдкреЛрд╕реНрдЯ рдХрд┐рдП рд╣реИрдВ, рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рдореБрдЭреЗ рдпрд╣ рдЙрдкрдХрд░рдг рдкрд╕рдВрдж рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рдмреЙрдЯ рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдЬрдм рддрдХ рдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдп рддреИрдпрд╛рд░ рдирд╣реАрдВ рд╣реЛ рдЧрдПред рднрд╛рд╖рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЧреЛрд▓рдВрдЧ рдФрд░ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо-рдмреЙрдЯ- рдПрдк рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓реЗрдВ ред рд╣рдореЗрдВ рдПрдХ рд╕рдВрд╕рд╛рдзрди рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдЦреАрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдореЗрд░реЗ рдорди рдореЗрдВ рдХрдИ рд╕рд╛рдЗрдЯреЗрдВ рдереАрдВ рдФрд░ рдореИрдВрдиреЗ рдПрдХ рд╕рдордЧреНрд░ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦрдиреЗ рдХреА рд╕реЛрдЪреА, рд▓реЗрдХрд┐рди рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░ рдореИрдВ рдЖрд▓рд╕реА рд╣реЛ рдЧрдпрд╛, рдФрд░ рдореИрдВрдиреЗ рдПрдХ рд╕рдВрд╕рд╛рдзрди рдЪреБрдирдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдкреБрдирд░рд╛рд░рдВрдн рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рднреА рдХреВрдкрди рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг sqlite3 рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред рд╣рдо рдЗрд╕рдореЗрдВ рдХреВрдкрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗ, рд╕рд╛рде рд╣реА рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдмреЙрдЯ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рдЬрд╛рдирдХрд╛рд░реА рджреЗрдВрдЧреЗ, рд╕рд╛рде рд╣реА рдпрд╣ рднреА рдЬрд╛рдирдХрд╛рд░реА рджреЗрдВрдЧреЗ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдХреМрди рд╕реЗ рдХреВрдкрди рдкрд╣рд▓реЗ рд╣реА рдорд┐рд▓ рдЪреБрдХреЗ рд╣реИрдВ рдФрд░ рдЬреЛ рдЕрднреА рддрдХ рдирд╣реАрдВ рд╣реИрдВред


рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ


рдЫрд╡рд┐


рд╕рд╛рдЗрдЯ рдкрд╛рд░реНрд╕рд┐рдВрдЧ


рд╕рд╛рдЗрдЯ рдХреА рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдмрдХрд░реА рдХреА рд▓рд╛рдЗрдмреНрд░реЗрд░реА рджреНрд╡рд╛рд░рд╛ рдХреА рдЬрд╛рдПрдЧреА - рдпрд╣ рдмрд╣реБрдд рдХреБрдЫ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬреИрд╕реЗ рдХрд┐ jqueryред Goquery.Document
рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ html . , , . . unixtime, . , , . , , js .


Telegram bot


BotFather , telegram . telegram api , http websocket. , telegram-bot-api updater .


type SNBot struct {
    cfg *Config
    bot *tgbotapi.BotAPI
    upd tgbotapi.UpdatesChannel
}

func New(cfg *Config) (*SNBot, error) {
    bot, err := tgbotapi.NewBotAPI(cfg.Token)
    if err != nil {
        return nil, err
    }
    level.Info(cfg.Logger).Log("msg", "Authorized on account", "bot-name", bot.Self.UserName)
    u := tgbotapi.NewUpdate(0)
    u.Timeout = cfg.UpdateTime
    updates, err := bot.GetUpdatesChan(u)
    if err != nil {
        return nil, err
    }
    return &SNBot{
        cfg: cfg,
        bot: bot,
        upd: updates,
    }, nil
}

, , gocron. task gocron storage storage .


Task function
func task(bot *snbot.SNBot, s *storage.Storage, c *collector.Collector, logger kitlog.Logger) {
    c.Collect(collector.ConditionQuery{
        URI: "https://lovikod.ru/knigi/promokody-litres",
    })
    chats, err := s.GetChat()
    if err != nil {
        level.Error(logger).Log("msg", "failed get chats", "err", err)
    }
    for _, id := range chats {
        records, err := s.GetNotUseCoupon(id)
        if err != nil {
            level.Error(logger).Log("msg", "failed get coupons", "err", err)
            return
        }
        var msg string
        for i, rec := range records {
            msg = fmt.Sprintf("%v%v:\t%s \n--->: %s\n : %v\n: %s\n\n", msg, i+1, rec.Link, rec.Code, time.Unix(rec.Date, 0).Format("02.01.2006"), rec.Description)
        }
        if len(msg) != 0 {
            err = bot.Send(id, msg)
            if err != nil {
                level.Error(logger).Log("msg", "failed send message", "err", err)
                continue
            }
            err = s.MarkAsRead(id, records)
            if err != nil {
                level.Error(logger).Log("msg", "failed marked as read", "err", err)
                continue
            }
        }
    }
    level.Info(logger).Log("msg", "send all chats new coupons")
}

- , , , .

func (s *SNBot) Send(chatID int64, msg string) error {
    level.Error(s.cfg.Logger).Log("msg", "try send", "chatID", chatID)
    var numericKeyboard = tgbotapi.NewReplyKeyboard(
        tgbotapi.NewKeyboardButtonRow(
            tgbotapi.NewKeyboardButton("/print5"),
        ),
    )
    m := tgbotapi.NewMessage(chatID, msg)
    m.ReplyMarkup = numericKeyboard
    _, err := s.bot.Send(m)
    if err != nil {
        if err.Error() == errBlockedByUser {
            s.cfg.Storage.UpdChatActivity(chatID, false)
        }
        return err
    }
    return nil
}

  Dockerfile


,   .


# build binary
FROM golang:1.10.3-alpine3.8 AS build
RUN apk add --no-cache linux-headers gcc g++
ARG VERSION=dev
WORKDIR /go/src/github.com/wenkaler/xfreehack
COPY . /go/src/github.com/wenkaler/xfreehack
RUN CGO_ENABLED=1 go build \
    -o /out/xfree \
    -ldflags "-X main.serviceVersion=$VERSION" \
    github.com/wenkaler/xfreehack/cmd

# copy to alpine image
FROM alpine:3.8
WORKDIR /app
RUN mkdir /db
COPY --from=build /out/xfree /app
RUN apk add --no-cache tzdata
RUN apk --no-cache add ca-certificates
ENV TZ Europe/Moscow
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
CMD ["/app/xfree"]

Systemd


. 2.6, upgrad- systemd. ? тАФ 3.


[Unit]
Description=Xfree service
After=network.target
After=network-online.target

[Service]
ExecStart=/urs/local/bin/xfree
Environment="TELEGRAM_TOKEN=$TELEGRAM_TOKEN" "PATH_DB=/db/xfree.db"
TimeoutSec=30
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target


 рдЕрдм рдореЗрд░реА рдкрддреНрдиреА рдЦреБрд╢ рд╣реИ рдХрд┐ рд╡рд╣ рд▓реАрдЯрд░ рдкрд░ рдореБрдлреНрдд рдХрд┐рддрд╛рдмреЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рд╕рд┐рд░реНрдл рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдЪреНрдЫреБрдХ рдерд╛ред рдЕрднреА рднреА рдХреБрдЫ рдРрд╕рд╛ рд╣реИ рдЬрд┐рд╕реЗ рдмреЗрд╣рддрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдПрдХ рдЪреЗрддрд╛рд╡рдиреА рдкреНрд░рдгрд╛рд▓реА рдЬреЛрдбрд╝реЗрдВ рдпрджрд┐ MarkAsRead рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, (рдЕрдм рддрдХ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдХрднреА рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВред , рд╡рд╣ рдЕрдм рднреА рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЕрдм рдЙрди рд▓реЛрдЧреЛрдВ рдХреЛ рд╕рдВрджреЗрд╢ рдирд╣реАрдВ рднреЗрдЬрддрд╛ рд╣реИ рдЬреЛ рдЙрд╕рд╕реЗ рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░ рдЪреБрдХреЗ рд╣реИрдВ рдФрд░ рдЖрдкрдХреЛ рдлрд┐рд░ рд╕реЗ / рд╕реНрдЯрд╛рд░реНрдЯ рдХрдорд╛рдВрдб рджрдмрд╛рдиреЗ рдХреЗ рдмрд╛рдж рдЙрдиреНрд╣реЗрдВ рд╕рдХреНрд░рд┐рдп рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЦреИрд░, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╡рд┐рддрд░рдг рдХреЗ рд╕рдордп рдФрд░ рдХреВрдкрди рдХреА рдкрд╕рдВрдж рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝реЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╕рд╛рдЗрдЯ рдореЗрдВ рд▓рд╛рдЗрдЯрдСрди рд╕реЗ рдХреВрдкрди рд╣реА рдирд╣реАрдВ рд╣реИрдВред рд▓реЗрдХрд┐рди рдпрд╣ рд╕рдм рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЕрднреА рддрдХ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХреЛрдИ рдЖрд╡реЗрджрди рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рд╣реБрдП рд╣реИрдВред


рд╕рдВрджрд░реНрдн


  1. рдЦреБрдж рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд░реЗрдВ
  2. рдХреВрдкрди рд╡реЗрдмрд╕рд╛рдЗрдЯ
  3. рдмреЙрдЯ рдирд╛рдо @xFreeCouponBot

All Articles