рдкреГрд╖реНрдарднреВрдорд┐
рд▓реАрдЯрд░ рдореЗрдВ рдмреЛрдирд╕ рдФрд░ рдХреВрдкрди рдХреА рдПрдХ рдкреНрд░рдгрд╛рд▓реА рд╣реЛрддреА рд╣реИ рдЬреЛ рдкрд░реНрдпрд╛рд╡рд░рдгреАрдп рдирд┐рдпрдорд┐рддрддрд╛ рдХреЗ рд╕рд╛рде рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИред рдЕрдкрдиреА рдкрддреНрдиреА рдХреЛ рдЦреБрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╡рд╣ рдЕрдкрдиреЗ рд▓рд┐рдП рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдкреБрд╕реНрддрдХ рдкрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЙрд╕рдиреЗ рдЙрд╕ рд╕рд╛рдЗрдЯ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ рдЬрд┐рд╕рдореЗрдВ рддрд╛рдЬреЗ рдХреВрдкрди рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдореЗрдВ рдЧрд┐рд░рд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдХреБрдЫ рджрд┐рдиреЛрдВ рдмрд╛рдж рдореИрдВ рдЗрд╕ рд╡реНрдпрд╡рд╕рд╛рдп рд╕реЗ рдердХ рдЧрдпрд╛ рдерд╛ рдФрд░ рдореИрдВрдиреЗ рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдпрд╣ рд╣рд░ рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╣реЛ рдЬреЛ рдЗрд╕реЗ рдЪрд╛рд╣рддрд╛ рд╣реИред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдЪреВрдВрдХрд┐ рдореИрдВрдиреЗ рд▓рдЧрд╛рддрд╛рд░ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдореЗрдВ рдирдП рдХреВрдкрди рдкреЛрд╕реНрдЯ рдХрд┐рдП рд╣реИрдВ, рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рдореБрдЭреЗ рдпрд╣ рдЙрдкрдХрд░рдг рдкрд╕рдВрдж рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рдмреЙрдЯ рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдЬрдм рддрдХ рдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдп рддреИрдпрд╛рд░ рдирд╣реАрдВ рд╣реЛ рдЧрдПред рднрд╛рд╖рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЧреЛрд▓рдВрдЧ рдФрд░ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо-рдмреЙрдЯ- рдПрдк рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓реЗрдВ ред рд╣рдореЗрдВ рдПрдХ рд╕рдВрд╕рд╛рдзрди рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдЦреАрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдореЗрд░реЗ рдорди рдореЗрдВ рдХрдИ рд╕рд╛рдЗрдЯреЗрдВ рдереАрдВ рдФрд░ рдореИрдВрдиреЗ рдПрдХ рд╕рдордЧреНрд░ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦрдиреЗ рдХреА рд╕реЛрдЪреА, рд▓реЗрдХрд┐рди рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░ рдореИрдВ рдЖрд▓рд╕реА рд╣реЛ рдЧрдпрд╛, рдФрд░ рдореИрдВрдиреЗ рдПрдХ рд╕рдВрд╕рд╛рдзрди рдЪреБрдирдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдкреБрдирд░рд╛рд░рдВрдн рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рднреА рдХреВрдкрди рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг 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 functionfunc 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 рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, (рдЕрдм рддрдХ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдк рдХрднреА рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВред , рд╡рд╣ рдЕрдм рднреА рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЕрдм рдЙрди рд▓реЛрдЧреЛрдВ рдХреЛ рд╕рдВрджреЗрд╢ рдирд╣реАрдВ рднреЗрдЬрддрд╛ рд╣реИ рдЬреЛ рдЙрд╕рд╕реЗ рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░ рдЪреБрдХреЗ рд╣реИрдВ рдФрд░ рдЖрдкрдХреЛ рдлрд┐рд░ рд╕реЗ / рд╕реНрдЯрд╛рд░реНрдЯ рдХрдорд╛рдВрдб рджрдмрд╛рдиреЗ рдХреЗ рдмрд╛рдж рдЙрдиреНрд╣реЗрдВ рд╕рдХреНрд░рд┐рдп рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЦреИрд░, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╡рд┐рддрд░рдг рдХреЗ рд╕рдордп рдФрд░ рдХреВрдкрди рдХреА рдкрд╕рдВрдж рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝реЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╕рд╛рдЗрдЯ рдореЗрдВ рд▓рд╛рдЗрдЯрдСрди рд╕реЗ рдХреВрдкрди рд╣реА рдирд╣реАрдВ рд╣реИрдВред рд▓реЗрдХрд┐рди рдпрд╣ рд╕рдм рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЕрднреА рддрдХ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХреЛрдИ рдЖрд╡реЗрджрди рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рд╣реБрдП рд╣реИрдВред
рд╕рдВрджрд░реНрдн
- рдЦреБрдж рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд░реЗрдВ
- рдХреВрдкрди рд╡реЗрдмрд╕рд╛рдЗрдЯ
- рдмреЙрдЯ рдирд╛рдо @xFreeCouponBot