Compare commits

...

63 Commits
v0.1 ... main

Author SHA1 Message Date
korotkov 78c23227e4 ewq
BOT_open_sesam/pipeline/head This commit looks good Details
2026-04-01 14:49:27 +05:00
korotkov 7b6d298d68 delete id-rsa
BOT_open_sesam/pipeline/head This commit looks good Details
2026-04-01 14:32:43 +05:00
korotkov 1b9649fbc0 q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 14:27:48 +05:00
korotkov 193390ecb8 q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 14:23:12 +05:00
korotkov 55ebed483f q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 14:15:31 +05:00
korotkov 00846331f3 q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 14:14:09 +05:00
korotkov 0adc48209d q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 14:09:47 +05:00
korotkov d7403bb266 q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 13:58:53 +05:00
korotkov 2b43532a8f qa
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 13:37:15 +05:00
korotkov 54afe573c1 zxc
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 13:28:53 +05:00
korotkov b240bc1bad q
BOT_open_sesam/pipeline/head This commit looks good Details
2026-04-01 13:08:56 +05:00
korotkov be996f942b qwe
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 13:00:14 +05:00
korotkov dda0e8ebb7 q
BOT_open_sesam/pipeline/head This commit looks good Details
2026-04-01 12:44:31 +05:00
korotkov dd78a4a55b qq
BOT_open_sesam/pipeline/head This commit looks good Details
2026-04-01 11:39:35 +05:00
korotkov f61e8e1588 qwe
BOT_open_sesam/pipeline/head This commit looks good Details
2026-04-01 11:38:28 +05:00
korotkov 0168036fab qaz
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 11:35:42 +05:00
korotkov 24fdc1014c qwe
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 11:34:39 +05:00
korotkov 5f59c4df92 qw
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 11:26:27 +05:00
korotkov 63ab836f1a q
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 11:20:59 +05:00
korotkov d57a88321e add sock5
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-04-01 11:11:11 +05:00
dl 5b0eafe695 Docker automate in Jenkinsfile (fix 8)
TEST_JD/pipeline/head There was a failure building this commit Details
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:50:00 +05:00
dl 35dca573c9 Docker automate in Jenkinsfile (fix 7)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:44:53 +05:00
dl dc021f6802 Docker automate in Jenkinsfile (fix 6)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:43:05 +05:00
dl 8f8b5d18d1 Docker automate in Jenkinsfile (fix 5)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:34:20 +05:00
dl 7ad9b91a0a Docker automate in Jenkinsfile (fix 4)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:26:33 +05:00
dl 469ab42324 Docker automate in Jenkinsfile (fix 3)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:21:50 +05:00
dl 3547f307b1 Docker automate in Jenkinsfile (fix 2)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:20:25 +05:00
dl 8edd79be72 Docker automate in Jenkinsfile (fix 1)
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:13:28 +05:00
dl e4f596dd82 Docker automate in Jenkinsfile
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2026-02-04 12:06:58 +05:00
korotkov b2363215b8 q
BOT_open_sesam/pipeline/head This commit looks good Details
2026-02-03 16:04:02 +05:00
korotkov 0c060c79cb change .env env variable
BOT_open_sesam/pipeline/head This commit looks good Details
2026-02-03 15:59:00 +05:00
dl 0871c0e251 Python img janged in docker
BOT_open_sesam/pipeline/head This commit looks good Details
TEST_JD/pipeline/head There was a failure building this commit Details
2025-05-30 17:17:29 +05:00
dl acc3c9916c .env return
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-30 15:49:58 +05:00
dl 18629ddffe ...
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-30 15:33:25 +05:00
dl a9f3766d9f ...
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-30 11:29:40 +05:00
dl ae11fb7588 ...
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-30 11:14:19 +05:00
dl 6ac9f59716 ... 2025-05-30 11:11:51 +05:00
dl c49502dff3 New Jenkins Pipline 2025-05-30 10:53:23 +05:00
dl 14ed4ad11f Docker .env should be right one
BOT_open_sesam/pipeline/head There was a failure building this commit Details
#4
2025-05-30 10:42:42 +05:00
dl d263966ded docker .env
BOT_open_sesam/pipeline/head There was a failure building this commit Details
#3
2025-05-30 10:38:30 +05:00
dl d159c0f0e4 docker .env
BOT_open_sesam/pipeline/head There was a failure building this commit Details
Попытка создать .env #2
2025-05-30 10:35:51 +05:00
dl dc5c35906f dockerfile change
BOT_open_sesam/pipeline/head There was a failure building this commit Details
Попытка нормально создать .env #1
2025-05-30 10:28:42 +05:00
dl 73c2f1f440 DEBUG
BOT_open_sesam/pipeline/head This commit looks good Details
Пытаемся поймать передаваемый номер в логах
2025-05-30 10:17:50 +05:00
dl 93e5303ee6 init_config.py was deleted
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-29 17:58:36 +05:00
dl 65e95b8eb2 requests modul was removed
BOT_open_sesam/pipeline/head This commit looks good Details
Удален модуль requests, обновлен README
2025-05-29 17:54:23 +05:00
dl 3b5ac43c30 JSON was remove
BOT_open_sesam/pipeline/head This commit looks good Details
Теперь вся информация получается по запросам к API, локально хранится
только BOT_TOKEN в файле .env
2025-05-29 17:10:51 +05:00
dl e319ea2e73 Human readable locks name
BOT_open_sesam/pipeline/head This commit looks good Details
- Теперь названия замков (дверей) на кнопках, отображаемых
пользователям, человекочитаемы, все соотношения заполняются в
bot_config.json
- Поправлен docker-compose.yml, размер логов ограничен тремя файлами по
10M каждый
2025-05-29 13:28:34 +05:00
dl 8582bdca9e API requests instead of local json
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-29 11:29:48 +05:00
dl a869a07eba Jenkins file was patched #2
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-16 16:52:03 +05:00
dl bc99718123 Jenkins file was patched
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-16 16:48:51 +05:00
dl 83aac7cd51 Jenkins file was added for test branch
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-16 16:44:00 +05:00
dl ca47adf559 First full realization. JSON is main configuration now, .env was deleted 2025-05-16 16:36:28 +05:00
dl 6256351aad Phone number check was added. Project structure was updated 2025-05-16 16:36:28 +05:00
loparev 5e0c098758 Удалить Jenkinsfile 2025-05-14 17:50:55 +05:00
dl f4515aacfb .env now avaible in docker
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-07 17:26:01 +05:00
dl c89f05c1bb STDIN and tty support was added
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-07 16:23:52 +05:00
dl 8a93e955fa CMD was fixed
BOT_open_sesam/pipeline/head This commit looks good Details
2025-05-07 16:16:25 +05:00
dl 38a911e4da python -> python3
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-07 16:12:56 +05:00
dl b8c9fdb291 env_config option was deleted
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-07 16:08:16 +05:00
dl 9359ff2f37 Trying to fix docker-compose
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-07 15:29:01 +05:00
dl 058f47f3c8 Trying to fix docker-compose
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-07 14:53:48 +05:00
dl 5e7134b253 build in docker-compose.yml has been fixed
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-07 14:07:09 +05:00
dl d1096540f8 init_config создан для проверки и создания .env. Jenkinsfile docker-compose.yml dockerfile были добавлены для автоматического развертывания
BOT_open_sesam/pipeline/head There was a failure building this commit Details
2025-05-07 13:38:25 +05:00
17 changed files with 479 additions and 74 deletions

117
Jenkinsfile vendored 100644
View File

@ -0,0 +1,117 @@
pipeline {
environment {
REGISTRY_URL = "https://proxy.docker.dataekb.ru/local_cache"
REGISTRY = "proxy.docker.dataekb.ru/local_cache"
BOT_IMAGE_NAME = "bot_open_sesam"
TUNNEL_IMAGE_NAME = "tunnel_open_sesam"
BOT_IMAGE_TAG = "latest"
TUNNEL_IMAGE_TAG = "latest"
IMAGE_TAG = "${env.BUILD_NUMBER}"
}
agent { label 'agent_smith'}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
disableConcurrentBuilds() // Prevent cleanup conflicts
timeout(time: 30, unit: 'MINUTES')
}
stages {
stage ('build bot image and push') {
steps {
script {
docker.withRegistry("${REGISTRY_URL}", 'jenkins_harbor') {
def BotImage = docker.build(
"${REGISTRY}/${BOT_IMAGE_NAME}:${env.BUILD_NUMBER}",
"--label build_number=${IMAGE_TAG} " +
"--label git_commit=${env.GIT_COMMIT} " +
"."
)
BotImage.push()
}
}
}
}
stage ('build tunnel image and push') {
steps {
dir('tunnel'){
script {
docker.withRegistry("${REGISTRY_URL}", 'jenkins_harbor') {
def TunnelImage = docker.build(
"${REGISTRY}/${TUNNEL_IMAGE_NAME}:${env.BUILD_NUMBER}",
"--label build_number=${IMAGE_TAG} " +
"--label git_commit=${env.GIT_COMMIT} " +
"."
)
TunnelImage.push()
}
}
}
}
}
stage ('clear after build and push') {
steps {
script {
sh "docker image prune --filter label=stage=builder"
}
}
}
stage("Deploy") {
steps {
script {
sh '''
export BOT_IMAGE_TAG=${IMAGE_TAG}
export TUNNEL_IMAGE_TAG=${IMAGE_TAG}
# Pull new images explicitly
docker-compose pull bot_open_sesam tunnel_open_sesam
# Deploy with specific project name
docker-compose up -d --remove-orphans
'''
}
}
}
}
post {
success {
echo "Оба образа собраны и задеплоены успешно"
}
failure {
echo "Ошибка сборки!"
}
}
}
// Old_version
// pipeline {
// agent { label 'agent_smith' }
//
// stages {
// stage('Stop and Remove Existing Container') {
// steps {
// sh '''
// docker stop open_sesam || true
// docker rm open_sesam || true
// docker-compose down || true
// '''
// }
// }
//
// stage('Build and Run Container') {
// steps {
// sh '''
// docker-compose up --build -d
// '''
// }
// }
// }
// }

View File

@ -1,22 +1,23 @@
# Usage # USAGE
Создать файл .env в корневой дирректории проекта, объявить и присвоить значения переменным: Для развертывания бота необходимо внести свой токен в файл
.env, запись должна иметь вид: BOT_TOKEN=your_token.
TOKEN= Для того чтобы пользователь мог пользоваться ботом, ему
LOCK_IP= необходимо поделиться номером телефона нажав на соответствующую
CARD_ID= кнопку (номер не будет виден другим пользователям, используется
AUTH_API= отправляется единожды для сверки с данными в БД).
, где # TODO
TOKEN - токен телеграм для взаимодействия с ботом
LOCK_IP - ip адресс замка
CARD_ID - уникальный номер ключ-карты
AUTH_API - уникальный набор символов, для взаимодействия с API замка
Дополнительные подробности можно найти в instruction_http_api_v5.pdf и исходном коде программы (см. main.py)
## TODO
- [x] Написать базовый функционал - [x] Написать базовый функционал
- [ ] Создать соотношение типа "id_пользователя: досутп_к_замку:" ~~- [ ] Создать соотношение типа "id_пользователя: досутп_к_замку:"~~
- [x] Сделать проверку пользователей по их номеру телефона ...
- [x] Удалить модуль getenv
- [x] Создать и парсить json с информацией о пользователях и их номерах
~~- [ ] Проверять, является ли пользователь администратором, если является, выводить дополнительную кнопку, предлагающую добавить номер в БД~~
- [x] Изменить json хранящийся локально на запросы к API
- [x] Изменить названия комнта в локальном json
- [x] Ограничить логи внутри докера
- [x] Избавиться от json файла, переместить токен в .env файл, информацию от замков получать через запрос по API
- [x] Избавиться от модуля requests

48
auth.py 100644
View File

@ -0,0 +1,48 @@
import re
import aiohttp
AUTHORIZED_USERS = {}
def normalize_phone(phone: str) -> str:
digits = re.sub(r"\D", "", phone)
if len(digits) > 10:
digits = digits[-10:]
return digits
async def authorize_user(user_id: int, phone: str) -> bool:
normalized = normalize_phone(phone)
api_url = "https://papi.dataekb.ru/check_access"
print("DEBUG: phone (var normalized) is ", normalized)
async with aiohttp.ClientSession() as session:
try:
async with session.get(api_url, params={"tel": normalized}) as response:
if response.status != 200:
print(f"Ошибка запроса к API: статус {response.status}")
return False
data = await response.json()
except Exception as e:
print(f"Исключение при запросе к API: {str(e)}")
return False
if data.get("response") != "1":
print(f"Доступ запрещён для номера: {normalized}")
return False
zone_str = data["data"].get("zone", "")
zones = [zone.strip() for zone in zone_str.split(";") if zone.strip()]
card_code = data["data"].get("card-code", "")
if not zones or not card_code:
print("Некорректный ответ API: отсутствуют зоны или код карты.")
return False
AUTHORIZED_USERS[user_id] = {"tel": normalized, "card": card_code, "zones": zones}
print(
f"{user_id} авторизован с номером: {normalized}, карта: {card_code}, зоны: {zones}"
)
return True
def is_user_auth(user_id: int) -> bool:
return user_id in AUTHORIZED_USERS

View File

@ -1,7 +0,0 @@
from aiogram.utils.keyboard import ReplyKeyboardBuilder
def FBI_open_up():
kb = ReplyKeyboardBuilder()
kb.button(text = "Сизам вскройся")
return kb.as_markup(resize_keyboard = True)

20
config.py 100644
View File

@ -0,0 +1,20 @@
def load_env(path=".env") -> dict:
env = {}
try:
with open(path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
# Пропускаем пустые строки и строки-комментарии
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
env[key.strip()] = value.strip()
except FileNotFoundError:
raise Exception(
f"Файл {path} не найден. Проверьте наличие файла .env в корне проекта."
)
return env
config = load_env()

52
docker-compose.yml 100644
View File

@ -0,0 +1,52 @@
version: '3'
services:
bot_open_sesam:
container_name: bot_open_sesam
image: proxy.docker.dataekb.ru/local_cache/bot_open_sesam:${BOT_IMAGE_TAG:-latest}
stdin_open: true
tty: true
env_file:
- ./.env
restart: always
networks:
- bot_open_sesam_network
depends_on:
tunnel_open_sesam:
condition: service_healthy
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
tunnel_open_sesam:
image: proxy.docker.dataekb.ru/local_cache/tunnel_open_sesam:${BOT_IMAGE_TAG:-latest}
container_name: tunnel_open_sesam
env_file:
- ./.env
# environment:
# - SSH_HOST=91.194.84.91
# - SSH_PORT=22
# - SSH_USER=root
volumes:
# SSH ключ
- .ssh/id_rsa:/root/.ssh/id_rsa:ro
networks:
- bot_open_sesam_network
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "nc", "-z", "localhost", "1080"]
interval: 10s
timeout: 5s
retries: 5
networks:
bot_open_sesam_network:
driver: bridge
ipam:
config:
- subnet: 172.30.10.0/29
gateway: 172.30.10.1

10
dockerfile 100644
View File

@ -0,0 +1,10 @@
FROM python:3.11-slim-bookworm
WORKDIR /bot/open_sesam
COPY requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
CMD ["python", "main.py"]

View File

@ -0,0 +1,9 @@
from .start_handler import register_start_handler
from .contact_handler import register_contact_handler
from .doors_handler import register_open_door_handler
def register_all_handlers(dp):
register_start_handler(dp)
register_contact_handler(dp)
register_open_door_handler(dp)

View File

@ -0,0 +1,31 @@
from aiogram import Dispatcher, F
from aiogram.types import Message
from keyboard import get_locks_keyboard, get_contact_keyboard
from auth import authorize_user, AUTHORIZED_USERS
def register_contact_handler(dp: Dispatcher):
@dp.message(F.contact)
async def contact_handler(msg: Message):
user_id = msg.from_user.id
if msg.contact is None:
await msg.answer("Ошибка: номер телефона не получен")
return
phone = msg.contact.phone_number
if not await authorize_user(user_id, phone):
print("DEBUG: phone in contact_handler is ", phone)
await msg.answer("Доступ запрещён, номер не идентифицирован")
return
user_data = AUTHORIZED_USERS.get(user_id)
if not user_data:
await msg.answer("Ошибка авторизации.")
return
allowed_zones = user_data["zones"]
reply_markup = await get_locks_keyboard(allowed_zones)
await msg.answer(
"Номер подтверждён. Выберите дверь для открытия", reply_markup=reply_markup
)

View File

@ -0,0 +1,44 @@
import aiohttp
from aiogram import Dispatcher
from aiogram.types import Message
from auth import AUTHORIZED_USERS, is_user_auth
from locks_api import get_lock_by_label
def register_open_door_handler(dp: Dispatcher):
@dp.message()
async def open_door_handler(msg: Message):
user_id = msg.from_user.id
if not is_user_auth(user_id):
await msg.answer("Доступ запрещён. Предоставьте номер телефона.")
return
user_data = AUTHORIZED_USERS.get(user_id)
if not user_data:
await msg.answer("Ошибка авторизации.")
return
lock_info = await get_lock_by_label(msg.text)
if not lock_info:
await msg.answer("Информация по замку не найдена.")
return
url = f"http://{lock_info['ip']}/cgi-bin/ext"
auth_info = aiohttp.BasicAuth(login="ext", password=lock_info["code"])
payload = f"CARD={user_data['card']}&DIR=0"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
try:
async with aiohttp.ClientSession() as session:
async with session.post(
url, auth=auth_info, data=payload, headers=headers, timeout=5
) as response:
if response.status == 200:
await msg.answer("Открыто")
else:
await msg.answer(
f"Ошибка при открытии замка. Код ошибки: {response.status}"
)
except Exception as e:
await msg.answer(f"Исключение: {str(e)}")

View File

@ -0,0 +1,26 @@
from aiogram import Dispatcher, F
from aiogram.types import Message
from aiogram.filters import CommandStart
from keyboard import get_contact_keyboard, get_locks_keyboard
from auth import is_user_auth, AUTHORIZED_USERS
def register_start_handler(dp: Dispatcher):
@dp.message(CommandStart())
async def command_start_handler(msg: Message):
user_id = msg.from_user.id
if is_user_auth(user_id):
user_data = AUTHORIZED_USERS.get(user_id)
if not user_data:
await msg.answer("Ошибка авторизации.")
return
allowed_zones = user_data["zones"]
reply_markup = await get_locks_keyboard(allowed_zones)
await msg.answer("Авторизация прошла успешно", reply_markup=reply_markup)
else:
reply_markup = get_contact_keyboard()
await msg.answer(
"Для пользования ботом предоставьте номер телефона",
reply_markup=reply_markup,
)

19
keyboard.py 100755
View File

@ -0,0 +1,19 @@
from aiogram.utils.keyboard import ReplyKeyboardBuilder
from aiogram.types import KeyboardButton
from locks_api import fetch_locks
async def get_locks_keyboard(allowed_locks: list):
kb = ReplyKeyboardBuilder()
locks = await fetch_locks()
for zone in allowed_locks:
lock_info = locks.get(zone)
btn_text = lock_info["name"] if lock_info and "name" in lock_info else zone
kb.button(text=btn_text)
return kb.as_markup(resize_keyboard=True)
def get_contact_keyboard():
kb = ReplyKeyboardBuilder()
kb.add(KeyboardButton(text="Поделиться контактом", request_contact=True))
return kb.as_markup(resize_keyboard=True)

35
locks_api.py 100644
View File

@ -0,0 +1,35 @@
import aiohttp
import json
LOCKS_API_URL = "https://papi.dataekb.ru/get_pacs"
async def fetch_locks() -> dict:
async with aiohttp.ClientSession() as session:
try:
async with session.get(LOCKS_API_URL) as response:
if response.status != 200:
print(f"Ошибка при получении данных замков: {response.status}")
return {}
text = await response.text()
except Exception as e:
print(f"Исключение при запросе данных замков: {str(e)}")
return {}
try:
data = json.loads(text)
if not data or not isinstance(data, list):
print("Неверный формат данных о замках, ожидался список.")
return {}
locks_dict = data[0]
return locks_dict
except Exception as e:
print(f"Ошибка при разборе данных замков: {str(e)}")
return {}
async def get_lock_by_label(label: str) -> dict:
locks = await fetch_locks()
for lock_id, details in locks.items():
if label == lock_id or details.get("name") == label:
return details
return {}

62
main.py
View File

@ -1,62 +1,32 @@
import os
import asyncio import asyncio
import logging import logging
import sys import sys
import requests
from aiogram.types import Message
from aiogram.filters import CommandStart
from aiogram import Bot, Dispatcher from aiogram import Bot, Dispatcher
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode from aiogram.enums import ParseMode
from aiogram import F from aiogram.client.default import DefaultBotProperties
from aiogram.client.session.aiohttp import AiohttpSession
from os import getenv from handlers import register_all_handlers
from dotenv import load_dotenv from config import config
from buttons import FBI_open_up # BOT_TOKEN = config["BOT_TOKEN"]
BOT_TOKEN=os.environ.get('BOT_TOKEN')
PROXY_URL = os.environ.get('PROXY_URL')
load_dotenv()
TOKEN = getenv("TOKEN")
dp = Dispatcher() dp = Dispatcher()
register_all_handlers(dp)
session = AiohttpSession(proxy=PROXY_URL)
@dp.message(CommandStart())
async def command_start_handler(msg: Message):
await msg.answer("msg happens", reply_markup=FBI_open_up())
@dp.message(F.text == "Сизам вскройся")
async def handle_open_door(msg: Message):
user_id = msg.from_user.id
# print(msg.__dict__)
print(user_id)
url = f"http://{getenv('LOCK_IP')}/cgi-bin/ext"
auth = ("ext", f"{getenv('AUTH_API')}")
payload = f"CARD={getenv('CARD_ID')}&DIR=0"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
try:
response = await asyncio.to_thread(
requests.post, url, auth=auth, data=payload, headers=headers, timeout=5
)
if response.status_code == 200:
await msg.answer("Открыто")
else:
await msg.answer(
f"Ошибка при открытии замка. Код ошибки: {response.status_code}"
)
except Exception as e:
await msg.answer(f"Исключение: {str(e)}")
async def main() -> None: async def main() -> None:
# Initialize Bot instance with default bot properties which will be passed to all API calls bot = Bot(
bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) token=BOT_TOKEN
, session=session
# And the run events dispatching , default=DefaultBotProperties(parse_mode=ParseMode.HTML)
)
await dp.start_polling(bot) await dp.start_polling(bot)

View File

@ -14,9 +14,8 @@ multidict==6.4.3
propcache==0.3.1 propcache==0.3.1
pydantic==2.11.3 pydantic==2.11.3
pydantic_core==2.33.1 pydantic_core==2.33.1
python-dotenv==1.1.0
requests==2.32.3
typing-inspection==0.4.0 typing-inspection==0.4.0
typing_extensions==4.13.2 typing_extensions==4.13.2
urllib3==2.4.0 urllib3==2.4.0
yarl==1.20.0 yarl==1.20.0
aiohttp-socks

15
tunnel/Dockerfile 100644
View File

@ -0,0 +1,15 @@
# tunnel/Dockerfile
FROM alpine:3.19
RUN apk add --no-cache \
autossh \
openssh-client
# Директория для SSH ключей
RUN mkdir -p /root/.ssh && \
chmod 700 /root/.ssh
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@ -0,0 +1,16 @@
#!/bin/sh
ssh-keyscan -p ${SSH_PORT:-22} ${SSH_HOST} >> /root/.ssh/known_hosts 2>/dev/null
exec autossh \
-M 0 \
-N \
-D 0.0.0.0:1080 \
-o "ServerAliveInterval=30" \
-o "ServerAliveCountMax=3" \
-o "ExitOnForwardFailure=yes" \
-o "StrictHostKeyChecking=no" \
-o "ConnectTimeout=10" \
-p ${SSH_PORT:-22} \
-i /root/.ssh/id_rsa \
${SSH_USER}@${SSH_HOST}