init app
This commit is contained in:
commit
077437d33c
|
@ -0,0 +1,2 @@
|
||||||
|
BOT_TOKEN=PLEASE_ADD_YOU_TOKEN_TO_DOT_ENV_FILE
|
||||||
|
POSTGRES_URL_CONNECT=postgresql://user:password@hos:port/db?sslmode=disable
|
|
@ -0,0 +1,4 @@
|
||||||
|
.env
|
||||||
|
/Dockerfile
|
||||||
|
/docker-compose.yml
|
||||||
|
__debug*
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch smm-tg",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${workspaceFolder}/cmd/smm_tg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
LOCAL_BIN := $(CURDIR)/bin
|
||||||
|
PATH := $(LOCAL_BIN):$(PATH)
|
||||||
|
GO_IMAGE_VER := 1.23.3
|
||||||
|
|
||||||
|
ifeq (local-migrations-create,$(firstword $(MAKECMDGOALS)))
|
||||||
|
migrationName := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
|
||||||
|
$(eval $(migrationName):;@:)
|
||||||
|
endif
|
||||||
|
|
||||||
|
local-migrate-up:
|
||||||
|
@goose -allow-missing -dir ./migrations postgres "user=crab dbname=smm-core host=localhost port=5432 sslmode=disable" up
|
||||||
|
|
||||||
|
local-migrations-create:
|
||||||
|
@goose -dir ./migrations postgres "user=crab dbname=smm-core host=localhost port=5432 sslmode=disable" create "${migrationName}" sql
|
||||||
|
|
||||||
|
|
||||||
|
local-init-arm: local-init-common
|
||||||
|
@if [ ! -f Dockerfile ]; then \
|
||||||
|
echo "Creating Dockerfile file..."; \
|
||||||
|
echo "FROM golang:1.23.3-alpine3.19 as builder" >> Dockerfile; \
|
||||||
|
echo "WORKDIR /app" >> Dockerfile; \
|
||||||
|
echo "COPY . ." >> Dockerfile; \
|
||||||
|
echo "ENV GOOS=linux" >> Dockerfile; \
|
||||||
|
echo "ENV GOARCH=arm" >> Dockerfile; \
|
||||||
|
echo "RUN go build -o smm_tg cmd/smm_tg/main.go" >> Dockerfile; \
|
||||||
|
echo "FROM alpine:3.19" >> Dockerfile; \
|
||||||
|
echo "COPY --from=builder /app/smm_tg /usr/local/bin/smm_tg" >> Dockerfile; \
|
||||||
|
echo "RUN chmod +x /usr/local/bin/smm_tg" >> Dockerfile; \
|
||||||
|
echo "CMD [\"smm_tg\"]" >> Dockerfile; \
|
||||||
|
echo "Dockerfile file created"; \
|
||||||
|
else \
|
||||||
|
echo "Dockerfile file already exists"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
local-init-amd64: local-init-common
|
||||||
|
|
||||||
|
local-init-common:
|
||||||
|
@if [ ! -f .env ]; then \
|
||||||
|
echo "Creating .env file..."; \
|
||||||
|
echo "BOT_TOKEN=" >> .env; \
|
||||||
|
echo "POSTGRES_URL_CONNECT=" >> .env; \
|
||||||
|
echo ".env file created"; \
|
||||||
|
else \
|
||||||
|
echo ".env file already exists"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
@if [ ! -f docker-compose.yml ]; then \
|
||||||
|
echo "Creating docker-compose.yml file..."; \
|
||||||
|
cp build/ci/docker-compose.yml .; \
|
||||||
|
echo "docker-compose.yml file created"; \
|
||||||
|
else \
|
||||||
|
echo "docker-compose.yml file already exists"; \
|
||||||
|
fi
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Save My Money Telegram Bot
|
||||||
|
телеграм бот сервиса-помощника, создающегося для контроля за расходами и накоплениями
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- кто мы?
|
||||||
|
- работяги
|
||||||
|
- чего мы хотим?
|
||||||
|
- меньше тратить денег на хуйню!
|
||||||
|
```
|
||||||
|
|
||||||
|
# Для пользователей
|
||||||
|
1. Найти бота __@samymoney_bot__
|
||||||
|
2. Начать контролировать денежные потоки и дыхание вселенной
|
||||||
|
|
||||||
|
# Для девелоперов
|
||||||
|
1. Выполнить
|
||||||
|
```bash
|
||||||
|
make local-init
|
||||||
|
```
|
||||||
|
2. Создать себе тестового бота и положить его токен в __.env__ под ключ __BOT_TOKEN__
|
||||||
|
3. Писать только хороший код
|
||||||
|
4. Плохой код не писать
|
|
@ -0,0 +1,79 @@
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
pull: if-not-exists
|
||||||
|
image: golang:1.23
|
||||||
|
environment:
|
||||||
|
TELEGRAM_TOKEN:
|
||||||
|
from_secret: bot_token
|
||||||
|
POSTGRES_URL_CONNECT:
|
||||||
|
from_secret: postgres_url_connect
|
||||||
|
settings:
|
||||||
|
envs: [ TELEGRAM_TOKEN,POSTGRES_URL_CONNECT ]
|
||||||
|
commands:
|
||||||
|
- CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o smm_tg cmd/smm_tg/main.go
|
||||||
|
- touch .env
|
||||||
|
- echo TELEGRAM_TOKEN=$${TELEGRAM_TOKEN} >> .env
|
||||||
|
- echo POSTGRES_URL_CONNECT=$${POSTGRES_URL_CONNECT} >> .env
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
pull: if-not-exists
|
||||||
|
image: golang:1.23
|
||||||
|
commands:
|
||||||
|
- go test ./...
|
||||||
|
|
||||||
|
- name: copy to server
|
||||||
|
pull: if-not-exists
|
||||||
|
image: appleboy/drone-scp
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
from_secret: ssh_ip
|
||||||
|
username:
|
||||||
|
from_secret: ssh_user
|
||||||
|
key:
|
||||||
|
from_secret: ssh_key
|
||||||
|
port:
|
||||||
|
from_secret: ssh_port
|
||||||
|
target: /home/crab/deploys/butler_bot
|
||||||
|
source:
|
||||||
|
- .env
|
||||||
|
- build/ci/Dockerfile
|
||||||
|
- deploy/docker-compose.yml
|
||||||
|
- migrations
|
||||||
|
- smm_tg
|
||||||
|
rm: true
|
||||||
|
|
||||||
|
- name: deploy
|
||||||
|
pull: if-not-exists
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
environment:
|
||||||
|
DB_PASS:
|
||||||
|
from_secret: db_pass
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
from_secret: ssh_ip
|
||||||
|
username:
|
||||||
|
from_secret: ssh_user
|
||||||
|
key:
|
||||||
|
from_secret: ssh_key
|
||||||
|
port:
|
||||||
|
from_secret: ssh_port
|
||||||
|
envs: [ DB_PASS ]
|
||||||
|
script:
|
||||||
|
- cd /home/crab/deploys/smm_tg
|
||||||
|
- cp /etc/ssl/certs/ca-certificates.crt .
|
||||||
|
- mv build/ci/Dockerfile .
|
||||||
|
- mv deploy/docker-compose.yml .
|
||||||
|
- rm -r build deploy
|
||||||
|
- export PATH=$PATH:/usr/local/go/bin:/$HOME/go/bin
|
||||||
|
- goose -allow-missing -dir ./migrations postgres "user=crab password=$${DB_PASS} dbname=smm_tg host=localhost port=5432 sslmode=disable" up
|
||||||
|
- docker-compose up -d --force-recreate
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- master
|
||||||
|
event:
|
||||||
|
- push
|
|
@ -0,0 +1,4 @@
|
||||||
|
FROM golang:1.23.3-alpine3.19
|
||||||
|
COPY smm_tg /usr/local/bin/smm_tg
|
||||||
|
RUN chmod +x /usr/local/bin/smm_tg
|
||||||
|
CMD ["smm_tg"]
|
|
@ -0,0 +1,15 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
smm_tg:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8185:8090"
|
||||||
|
networks:
|
||||||
|
- common-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
common-network:
|
||||||
|
external: true
|
|
@ -0,0 +1,40 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/modules/messenger/telegram"
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/services/bot"
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/services/bot/bot_ping"
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/services/listener"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// try get sysenv
|
||||||
|
telegarmToken := os.Getenv("BOT_TOKEN")
|
||||||
|
if len(telegarmToken) == 0 {
|
||||||
|
if err := godotenv.Load("../../.env"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
telegarmToken = os.Getenv("BOT_TOKEN")
|
||||||
|
}
|
||||||
|
if len(telegarmToken) == 0 {
|
||||||
|
panic("empty bot token")
|
||||||
|
}
|
||||||
|
|
||||||
|
messengerTelegram, err := telegram.NewMessengerTelegram(telegarmToken)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
listenerService := listener.ListenerService{
|
||||||
|
Messenger: messengerTelegram,
|
||||||
|
Bots: []bot.IBot{
|
||||||
|
bot_ping.NewBotPing(messengerTelegram),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
listenerService.Run(ctx)
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
module git.3crabs.ru/save_my_money/smm_tg
|
||||||
|
|
||||||
|
go 1.23.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/lib/pq v1.10.9
|
||||||
|
github.com/samber/lo v1.47.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
go.uber.org/mock v0.5.0 // indirect
|
||||||
|
golang.org/x/text v0.16.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
|
||||||
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
|
||||||
|
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
|
||||||
|
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||||
|
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||||
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
|
@ -0,0 +1,6 @@
|
||||||
|
package entities
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ChatID string `sql:"chat_id"`
|
||||||
|
UserID string `sql:"user_id"`
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package messenger
|
||||||
|
|
||||||
|
//go:generate mockgen -source=$GOFILE -destination=mocks/$GOFILE -package=mocks
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
ChatID string
|
||||||
|
UserID string
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
type IMessenger interface {
|
||||||
|
GetMessage(ctx context.Context) (*Message, error)
|
||||||
|
SendMessage(ctx context.Context, msg *Message) error
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/modules/messenger"
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type messengerTelegram struct {
|
||||||
|
bot *tgbotapi.BotAPI
|
||||||
|
updates tgbotapi.UpdatesChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMessengerTelegram(token string) (messenger.IMessenger, error) {
|
||||||
|
bot, err := tgbotapi.NewBotAPI(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Printf("Authorized on account %s", bot.Self.UserName)
|
||||||
|
u := tgbotapi.NewUpdate(0)
|
||||||
|
u.Timeout = 60
|
||||||
|
|
||||||
|
updates := bot.GetUpdatesChan(u)
|
||||||
|
return &messengerTelegram{
|
||||||
|
bot: bot,
|
||||||
|
updates: updates,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *messengerTelegram) GetMessage(ctx context.Context) (*messenger.Message, error) {
|
||||||
|
tgMsg := <-m.updates
|
||||||
|
log.Printf("get grom tg: %+v", tgMsg)
|
||||||
|
chatID := int64(0)
|
||||||
|
if tgMsg.Message != nil && tgMsg.Message.Chat != nil {
|
||||||
|
chatID = tgMsg.Message.Chat.ID
|
||||||
|
}
|
||||||
|
if chatID == 0 {
|
||||||
|
return nil, fmt.Errorf("get chat id error %+v", tgMsg)
|
||||||
|
}
|
||||||
|
msg := &messenger.Message{
|
||||||
|
ChatID: fmt.Sprintf("%d", chatID),
|
||||||
|
UserID: tgMsg.Message.From.UserName,
|
||||||
|
Text: tgMsg.Message.Text,
|
||||||
|
}
|
||||||
|
log.Println("get:", msg)
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *messengerTelegram) SendMessage(ctx context.Context, msg *messenger.Message) error {
|
||||||
|
chatID, err := strconv.ParseInt(msg.ChatID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tgMsg := tgbotapi.NewMessage(chatID, msg.Text)
|
||||||
|
if _, err = m.bot.Send(tgMsg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Println("send:", msg)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package bot_ping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/modules/messenger"
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/services/bot"
|
||||||
|
)
|
||||||
|
|
||||||
|
type botPing struct {
|
||||||
|
messenger messenger.IMessenger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBotPing(
|
||||||
|
messenger messenger.IMessenger,
|
||||||
|
) bot.IBot {
|
||||||
|
return &botPing{
|
||||||
|
messenger: messenger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bot *botPing) Process(ctx context.Context, msg *messenger.Message) error {
|
||||||
|
if !strings.Contains(msg.Text, "/ping") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bot.messenger.SendMessage(
|
||||||
|
ctx,
|
||||||
|
&messenger.Message{
|
||||||
|
ChatID: msg.ChatID,
|
||||||
|
Text: "pong",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package bot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/modules/messenger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IBot interface {
|
||||||
|
Process(ctx context.Context, msg *messenger.Message) error
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package listener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/modules/messenger"
|
||||||
|
"git.3crabs.ru/save_my_money/smm_tg/internal/services/bot"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListenerService struct {
|
||||||
|
Messenger messenger.IMessenger
|
||||||
|
Bots []bot.IBot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ListenerService) Run(ctx context.Context) error {
|
||||||
|
for {
|
||||||
|
msg, err := s.Messenger.GetMessage(ctx)
|
||||||
|
if err != nil {
|
||||||
|
if err == context.Canceled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, b := range s.Bots {
|
||||||
|
if err := b.Process(ctx, msg); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
CREATE TABLE IF NOT EXISTS "user" (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
chat_id TEXT NOT NULL
|
||||||
|
);
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
DROP TABLE IF EXISTS "user";
|
||||||
|
-- +goose StatementEnd
|
Loading…
Reference in New Issue