Init project
This commit is contained in:
18
.env.example
Normal file
18
.env.example
Normal file
@@ -0,0 +1,18 @@
|
||||
# 環境変数設定ファイル(例)
|
||||
# このファイルをコピーして.envファイルを作成し、実際の値を設定してください
|
||||
|
||||
# メールサーバー設定
|
||||
IMAP_SERVER=imap.gmail.com
|
||||
IMAP_PORT=993
|
||||
USE_SSL=true
|
||||
MAILBOX=INBOX
|
||||
|
||||
# メール認証情報
|
||||
EMAIL_USER=your-email@gmail.com
|
||||
EMAIL_PASSWORD=your-app-password
|
||||
|
||||
# Discord Webhook URL
|
||||
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
||||
|
||||
# 監視設定
|
||||
CHECK_INTERVAL=60
|
||||
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
# 作業ディレクトリを設定
|
||||
WORKDIR /app
|
||||
|
||||
# システムパッケージを更新
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Pythonの依存関係をコピーしてインストール
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# アプリケーションファイルをコピー
|
||||
COPY app.py .
|
||||
|
||||
# 非rootユーザーを作成
|
||||
RUN useradd --create-home --shell /bin/bash appuser
|
||||
RUN chown -R appuser:appuser /app
|
||||
USER appuser
|
||||
|
||||
# ヘルスチェックを追加
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD python -c "import sys; sys.exit(0)"
|
||||
|
||||
# アプリケーションを実行
|
||||
CMD ["python", "app.py"]
|
||||
315
README.md
Normal file
315
README.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# Email to Discord Webhook Forwarder
|
||||
|
||||
メールサーバーを監視して、新しいメールが到着したときにDiscordのWebhookを使用して通知を送信するPythonアプリケーションです。
|
||||
|
||||
## 🚀 機能
|
||||
|
||||
- **メールサーバー監視**: IMAP/IMAPS プロトコルでメールサーバーを監視
|
||||
- **Discord通知**: 新しいメールが到着したときにDiscordに通知
|
||||
- **環境変数設定**: 設定は全て環境変数で管理
|
||||
- **Dockerサポート**: コンテナとして簡単にデプロイ可能
|
||||
- **SSL/TLS対応**: セキュアな接続をサポート
|
||||
- **エラーハンドリング**: 堅牢なエラー処理とログ出力
|
||||
|
||||
## 📋 必要な環境変数
|
||||
|
||||
| 変数名 | 説明 | 必須 | デフォルト値 |
|
||||
|--------|------|------|-------------|
|
||||
| `EMAIL_USER` | メールアドレス | ✅ | - |
|
||||
| `EMAIL_PASSWORD` | メールパスワード/アプリパスワード | ✅ | - |
|
||||
| `DISCORD_WEBHOOK_URL` | Discord Webhook URL | ✅ | - |
|
||||
| `IMAP_SERVER` | IMAPサーバーアドレス | ❌ | `imap.gmail.com` |
|
||||
| `IMAP_PORT` | IMAPポート番号 | ❌ | `993` |
|
||||
| `USE_SSL` | SSL/TLS使用の有無 | ❌ | `true` |
|
||||
| `MAILBOX` | 監視するメールボックス | ❌ | `INBOX` |
|
||||
| `CHECK_INTERVAL` | チェック間隔(秒) | ❌ | `60` |
|
||||
|
||||
## 🔧 セットアップ
|
||||
|
||||
### 1. Discord Webhook URLの取得
|
||||
|
||||
1. Discordでメッセージを送信したいチャンネルを選択
|
||||
2. チャンネル設定 → 連携サービス → ウェブフック
|
||||
3. 新しいウェブフックを作成してURLをコピー
|
||||
|
||||
### 2. Gmail用アプリパスワードの作成(Gmailを使用する場合)
|
||||
|
||||
1. Googleアカウントの2段階認証を有効にする
|
||||
2. Googleアカウント設定 → セキュリティ → アプリパスワード
|
||||
3. メール用のアプリパスワードを生成
|
||||
|
||||
### 3. 環境変数の設定
|
||||
|
||||
```bash
|
||||
# .env.exampleをコピーして.envファイルを作成
|
||||
cp .env.example .env
|
||||
|
||||
# .envファイルを編集して実際の値を設定
|
||||
```
|
||||
|
||||
## 🐳 Docker Composeでの実行
|
||||
|
||||
### 1. docker-compose.ymlの設定
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- EMAIL_USER=your-email@gmail.com
|
||||
- EMAIL_PASSWORD=your-app-password
|
||||
- DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
||||
```
|
||||
|
||||
### 2. コンテナの起動
|
||||
|
||||
```bash
|
||||
# コンテナをビルドして起動
|
||||
docker-compose up -d
|
||||
|
||||
# ログの確認
|
||||
docker-compose logs -f
|
||||
|
||||
# コンテナの停止
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
## 🚀 Linux用シェルスクリプトでの実行
|
||||
|
||||
Linux環境では便利なシェルスクリプトを使用できます:
|
||||
|
||||
### 1. スクリプトに実行権限を付与
|
||||
|
||||
```bash
|
||||
chmod +x start.sh
|
||||
```
|
||||
|
||||
### 2. 初期セットアップ
|
||||
|
||||
```bash
|
||||
# .envファイルを作成
|
||||
./start.sh setup
|
||||
|
||||
# .envファイルを編集して実際の値を設定
|
||||
nano .env
|
||||
```
|
||||
|
||||
### 3. よく使用するコマンド
|
||||
|
||||
```bash
|
||||
# Dockerイメージをビルド
|
||||
./start.sh build
|
||||
|
||||
# コンテナを起動
|
||||
./start.sh start
|
||||
|
||||
# リアルタイムでログを表示
|
||||
./start.sh logs-f
|
||||
|
||||
# コンテナの状態を確認
|
||||
./start.sh status
|
||||
|
||||
# コンテナを停止
|
||||
./start.sh stop
|
||||
|
||||
# コンテナを再起動
|
||||
./start.sh restart
|
||||
|
||||
# docker-compose で起動
|
||||
./start.sh compose-up
|
||||
|
||||
# Python直接実行
|
||||
./start.sh python
|
||||
|
||||
# ヘルプを表示
|
||||
./start.sh help
|
||||
```
|
||||
|
||||
### 4. 利用可能なコマンド一覧
|
||||
|
||||
| コマンド | 説明 |
|
||||
|----------|------|
|
||||
| `setup` | 初期セットアップ(.envファイル作成) |
|
||||
| `build` | Dockerイメージをビルド |
|
||||
| `start` | コンテナを起動 |
|
||||
| `stop` | コンテナを停止 |
|
||||
| `restart` | コンテナを再起動 |
|
||||
| `logs` | ログを表示 |
|
||||
| `logs-f` | ログをリアルタイム表示 |
|
||||
| `status` | コンテナの状態を確認 |
|
||||
| `clean` | 停止済みコンテナとイメージを削除 |
|
||||
| `compose-up` | docker-compose で起動 |
|
||||
| `compose-down` | docker-compose で停止 |
|
||||
| `python` | Python直接実行 |
|
||||
| `help` | ヘルプを表示 |
|
||||
|
||||
## 🪟 Windows用PowerShellスクリプトでの実行
|
||||
|
||||
Windows環境では PowerShell スクリプトを使用できます:
|
||||
|
||||
### 1. 初期セットアップ
|
||||
|
||||
```powershell
|
||||
# .envファイルを作成
|
||||
.\start.ps1 setup
|
||||
|
||||
# .envファイルを編集して実際の値を設定
|
||||
notepad .env
|
||||
```
|
||||
|
||||
### 2. よく使用するコマンド
|
||||
|
||||
```powershell
|
||||
# Dockerイメージをビルド
|
||||
.\start.ps1 build
|
||||
|
||||
# コンテナを起動
|
||||
.\start.ps1 start
|
||||
|
||||
# リアルタイムでログを表示
|
||||
.\start.ps1 logs-f
|
||||
|
||||
# コンテナの状態を確認
|
||||
.\start.ps1 status
|
||||
|
||||
# コンテナを停止
|
||||
.\start.ps1 stop
|
||||
|
||||
# ヘルプを表示
|
||||
.\start.ps1 help
|
||||
```
|
||||
|
||||
## 🔨 Dockerでの直接実行
|
||||
|
||||
### 1. イメージのビルド
|
||||
|
||||
```bash
|
||||
docker build -t email-to-discord .
|
||||
```
|
||||
|
||||
### 2. コンテナの実行
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name email-monitor \
|
||||
--restart unless-stopped \
|
||||
-e EMAIL_USER=your-email@gmail.com \
|
||||
-e EMAIL_PASSWORD=your-app-password \
|
||||
-e DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL \
|
||||
-e CHECK_INTERVAL=60 \
|
||||
email-to-discord
|
||||
```
|
||||
|
||||
## 🐍 Python直接実行
|
||||
|
||||
### 1. 依存関係のインストール
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 2. 環境変数の設定
|
||||
|
||||
```bash
|
||||
# Windowsの場合
|
||||
set EMAIL_USER=your-email@gmail.com
|
||||
set EMAIL_PASSWORD=your-app-password
|
||||
set DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
||||
|
||||
# Linux/macOSの場合
|
||||
export EMAIL_USER=your-email@gmail.com
|
||||
export EMAIL_PASSWORD=your-app-password
|
||||
export DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
||||
```
|
||||
|
||||
### 3. アプリケーションの実行
|
||||
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
|
||||
## 📧 対応メールプロバイダー
|
||||
|
||||
### Gmail
|
||||
|
||||
```env
|
||||
IMAP_SERVER=imap.gmail.com
|
||||
IMAP_PORT=993
|
||||
USE_SSL=true
|
||||
```
|
||||
|
||||
### Outlook/Hotmail
|
||||
|
||||
```env
|
||||
IMAP_SERVER=outlook.office365.com
|
||||
IMAP_PORT=993
|
||||
USE_SSL=true
|
||||
```
|
||||
|
||||
### Yahoo Mail
|
||||
|
||||
```env
|
||||
IMAP_SERVER=imap.mail.yahoo.com
|
||||
IMAP_PORT=993
|
||||
USE_SSL=true
|
||||
```
|
||||
|
||||
### その他のプロバイダー
|
||||
|
||||
各プロバイダーのIMAP設定を確認して適切な値を設定してください。
|
||||
|
||||
## 📊 ログとモニタリング
|
||||
|
||||
アプリケーションは以下の情報をログ出力します:
|
||||
|
||||
- 起動/停止メッセージ
|
||||
- メールサーバー接続状況
|
||||
- 新しいメールの検出
|
||||
- Discord送信の成功/失敗
|
||||
- エラー情報
|
||||
|
||||
```bash
|
||||
# Dockerコンテナのログを確認
|
||||
docker logs email-to-discord-monitor
|
||||
|
||||
# リアルタイムでログを監視
|
||||
docker logs -f email-to-discord-monitor
|
||||
```
|
||||
|
||||
## 🔒 セキュリティ考慮事項
|
||||
|
||||
1. **アプリパスワードの使用**: 通常のパスワードではなくアプリ専用パスワードを使用
|
||||
2. **環境変数での機密情報管理**: パスワードやWebhook URLは環境変数で管理
|
||||
3. **SSL/TLS接続**: メールサーバーとの通信は暗号化
|
||||
4. **非rootユーザー**: Dockerコンテナは非rootユーザーで実行
|
||||
|
||||
## 🛠️ トラブルシューティング
|
||||
|
||||
### メールサーバーに接続できない場合
|
||||
|
||||
1. IMAP設定が正しいか確認
|
||||
2. アプリパスワードが正しく設定されているか確認
|
||||
3. 2段階認証が有効になっているか確認(Gmail)
|
||||
4. ファイアウォールの設定を確認
|
||||
|
||||
### Discord通知が送信されない場合
|
||||
|
||||
1. Webhook URLが正しいか確認
|
||||
2. Discordサーバーの権限を確認
|
||||
3. ネットワーク接続を確認
|
||||
|
||||
### ログの確認方法
|
||||
|
||||
```bash
|
||||
# アプリケーションのログレベルを変更(開発時)
|
||||
# app.py内のlogging.basicConfig levelをDEBUGに変更
|
||||
```
|
||||
|
||||
## 📝 ライセンス
|
||||
|
||||
このプロジェクトはMITライセンスの下で公開されています。
|
||||
|
||||
## 🤝 コントリビューション
|
||||
|
||||
プルリクエストやイシューの報告を歓迎します。
|
||||
|
||||
## 📞 サポート
|
||||
|
||||
問題が発生した場合は、GitHubのIssueにて報告してください。
|
||||
348
app.py
Normal file
348
app.py
Normal file
@@ -0,0 +1,348 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Email to Discord Webhook Forwarder
|
||||
メールサーバーを監視してDiscordに転送するアプリケーション
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import imaplib
|
||||
import email
|
||||
import json
|
||||
import logging
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
import signal
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
|
||||
# ログ設定
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@dataclass
|
||||
class EmailMessage:
|
||||
"""メールメッセージのデータクラス"""
|
||||
subject: str
|
||||
sender: str
|
||||
date: str
|
||||
body: str
|
||||
uid: str
|
||||
|
||||
class EmailMonitor:
|
||||
"""メールサーバー監視クラス"""
|
||||
|
||||
def __init__(self):
|
||||
self.running = False
|
||||
self.mail_client = None
|
||||
self.last_processed_uid = None
|
||||
|
||||
# 環境変数から設定を取得
|
||||
self.imap_server = os.getenv('IMAP_SERVER', 'imap.gmail.com')
|
||||
self.imap_port = int(os.getenv('IMAP_PORT', '993'))
|
||||
self.email_user = os.getenv('EMAIL_USER')
|
||||
self.email_password = os.getenv('EMAIL_PASSWORD')
|
||||
self.discord_webhook_url = os.getenv('DISCORD_WEBHOOK_URL')
|
||||
self.check_interval = int(os.getenv('CHECK_INTERVAL', '60')) # 秒
|
||||
self.mailbox = os.getenv('MAILBOX', 'INBOX')
|
||||
self.use_ssl = os.getenv('USE_SSL', 'true').lower() == 'true'
|
||||
|
||||
# 設定の検証
|
||||
self._validate_config()
|
||||
|
||||
def _validate_config(self):
|
||||
"""設定の検証"""
|
||||
required_vars = ['EMAIL_USER', 'EMAIL_PASSWORD', 'DISCORD_WEBHOOK_URL']
|
||||
missing_vars = [var for var in required_vars if not os.getenv(var)]
|
||||
|
||||
if missing_vars:
|
||||
logger.error(f"必要な環境変数が設定されていません: {', '.join(missing_vars)}")
|
||||
sys.exit(1)
|
||||
|
||||
logger.info("設定の検証が完了しました")
|
||||
|
||||
def connect_to_email(self) -> bool:
|
||||
"""メールサーバーに接続"""
|
||||
try:
|
||||
if self.use_ssl:
|
||||
self.mail_client = imaplib.IMAP4_SSL(self.imap_server, self.imap_port)
|
||||
else:
|
||||
self.mail_client = imaplib.IMAP4(self.imap_server, self.imap_port)
|
||||
|
||||
self.mail_client.login(self.email_user, self.email_password)
|
||||
self.mail_client.select(self.mailbox)
|
||||
logger.info(f"メールサーバーに接続しました: {self.imap_server}:{self.imap_port}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"メールサーバーへの接続に失敗しました: {str(e)}")
|
||||
return False
|
||||
|
||||
def disconnect_from_email(self):
|
||||
"""メールサーバーから切断"""
|
||||
if self.mail_client:
|
||||
try:
|
||||
self.mail_client.close()
|
||||
self.mail_client.logout()
|
||||
logger.info("メールサーバーから切断しました")
|
||||
except Exception as e:
|
||||
logger.warning(f"メールサーバーからの切断でエラーが発生しました: {str(e)}")
|
||||
|
||||
def get_new_emails(self) -> List[EmailMessage]:
|
||||
"""新しいメールを取得"""
|
||||
try:
|
||||
# UNSEENフラグのメールを検索
|
||||
typ, data = self.mail_client.search(None, 'UNSEEN')
|
||||
|
||||
if typ != 'OK':
|
||||
logger.warning("メール検索に失敗しました")
|
||||
return []
|
||||
|
||||
email_ids = data[0].split()
|
||||
new_emails = []
|
||||
|
||||
for email_id in email_ids:
|
||||
try:
|
||||
# メールを取得
|
||||
typ, msg_data = self.mail_client.fetch(email_id, '(RFC822)')
|
||||
|
||||
if typ != 'OK':
|
||||
continue
|
||||
|
||||
email_body = msg_data[0][1]
|
||||
email_message = email.message_from_bytes(email_body)
|
||||
|
||||
# メールデータを解析
|
||||
parsed_email = self._parse_email(email_message, email_id.decode())
|
||||
if parsed_email:
|
||||
new_emails.append(parsed_email)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"メール解析エラー (ID: {email_id}): {str(e)}")
|
||||
continue
|
||||
|
||||
return new_emails
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"新しいメールの取得に失敗しました: {str(e)}")
|
||||
return []
|
||||
|
||||
def _parse_email(self, email_message, uid: str) -> Optional[EmailMessage]:
|
||||
"""メールメッセージを解析"""
|
||||
try:
|
||||
# ヘッダー情報を取得
|
||||
subject = self._decode_header(email_message.get('Subject', ''))
|
||||
sender = self._decode_header(email_message.get('From', ''))
|
||||
date = email_message.get('Date', '')
|
||||
|
||||
# メール本文を取得
|
||||
body = self._get_email_body(email_message)
|
||||
|
||||
return EmailMessage(
|
||||
subject=subject,
|
||||
sender=sender,
|
||||
date=date,
|
||||
body=body,
|
||||
uid=uid
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"メール解析エラー: {str(e)}")
|
||||
return None
|
||||
|
||||
def _decode_header(self, header: str) -> str:
|
||||
"""メールヘッダーをデコード"""
|
||||
if not header:
|
||||
return ''
|
||||
|
||||
try:
|
||||
decoded_header = email.header.decode_header(header)
|
||||
result = ''
|
||||
|
||||
for text, encoding in decoded_header:
|
||||
if isinstance(text, bytes):
|
||||
if encoding:
|
||||
text = text.decode(encoding, errors='ignore')
|
||||
else:
|
||||
text = text.decode('utf-8', errors='ignore')
|
||||
result += text
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"ヘッダーデコードエラー: {str(e)}")
|
||||
return str(header)
|
||||
|
||||
def _get_email_body(self, email_message) -> str:
|
||||
"""メール本文を取得"""
|
||||
body = ''
|
||||
|
||||
try:
|
||||
if email_message.is_multipart():
|
||||
for part in email_message.walk():
|
||||
content_type = part.get_content_type()
|
||||
content_disposition = str(part.get('Content-Disposition'))
|
||||
|
||||
if content_type == 'text/plain' and 'attachment' not in content_disposition:
|
||||
charset = part.get_content_charset() or 'utf-8'
|
||||
body_bytes = part.get_payload(decode=True)
|
||||
if body_bytes:
|
||||
body = body_bytes.decode(charset, errors='ignore')
|
||||
break
|
||||
else:
|
||||
charset = email_message.get_content_charset() or 'utf-8'
|
||||
body_bytes = email_message.get_payload(decode=True)
|
||||
if body_bytes:
|
||||
body = body_bytes.decode(charset, errors='ignore')
|
||||
|
||||
# 本文が長い場合は切り詰める(Discord制限対策)
|
||||
if len(body) > 1900:
|
||||
body = body[:1900] + '\n...(本文が切り詰められました)'
|
||||
|
||||
return body
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"メール本文取得エラー: {str(e)}")
|
||||
return '本文の取得に失敗しました'
|
||||
|
||||
def send_to_discord(self, email_msg: EmailMessage) -> bool:
|
||||
"""DiscordにWebhookでメールを送信"""
|
||||
try:
|
||||
# Discord Embed形式でメッセージを構築
|
||||
embed = {
|
||||
"title": "📧 新しいメール",
|
||||
"color": 0x3498db,
|
||||
"fields": [
|
||||
{
|
||||
"name": "件名",
|
||||
"value": email_msg.subject or "件名なし",
|
||||
"inline": False
|
||||
},
|
||||
{
|
||||
"name": "送信者",
|
||||
"value": email_msg.sender or "送信者不明",
|
||||
"inline": True
|
||||
},
|
||||
{
|
||||
"name": "日時",
|
||||
"value": email_msg.date or "日時不明",
|
||||
"inline": True
|
||||
},
|
||||
{
|
||||
"name": "本文",
|
||||
"value": email_msg.body[:1000] if email_msg.body else "本文なし",
|
||||
"inline": False
|
||||
}
|
||||
],
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
webhook_data = {
|
||||
"username": "Email Monitor",
|
||||
"avatar_url": "https://cdn-icons-png.flaticon.com/512/732/732200.png",
|
||||
"embeds": [embed]
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
self.discord_webhook_url,
|
||||
json=webhook_data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 204:
|
||||
logger.info(f"Discordにメールを送信しました: {email_msg.subject}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Discord送信エラー: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Discord送信エラー: {str(e)}")
|
||||
return False
|
||||
|
||||
def start_monitoring(self):
|
||||
"""メール監視を開始"""
|
||||
logger.info("メール監視を開始します...")
|
||||
self.running = True
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
# メールサーバーに接続
|
||||
if not self.connect_to_email():
|
||||
logger.warning(f"{self.check_interval}秒後に再試行します...")
|
||||
time.sleep(self.check_interval)
|
||||
continue
|
||||
|
||||
# 新しいメールをチェック
|
||||
new_emails = self.get_new_emails()
|
||||
|
||||
if new_emails:
|
||||
logger.info(f"{len(new_emails)}件の新しいメールが見つかりました")
|
||||
|
||||
for email_msg in new_emails:
|
||||
if self.send_to_discord(email_msg):
|
||||
logger.info(f"処理完了: {email_msg.subject}")
|
||||
else:
|
||||
logger.warning(f"Discord送信失敗: {email_msg.subject}")
|
||||
else:
|
||||
logger.debug("新しいメールはありません")
|
||||
|
||||
# メールサーバーから切断
|
||||
self.disconnect_from_email()
|
||||
|
||||
# 次のチェックまで待機
|
||||
logger.debug(f"{self.check_interval}秒後に次のチェックを実行します")
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("キーボード割り込みを受信しました")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"監視ループでエラーが発生しました: {str(e)}")
|
||||
self.disconnect_from_email()
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
logger.info("メール監視を停止しました")
|
||||
|
||||
def stop_monitoring(self):
|
||||
"""メール監視を停止"""
|
||||
self.running = False
|
||||
self.disconnect_from_email()
|
||||
|
||||
def signal_handler(signum, frame, monitor):
|
||||
"""シグナルハンドラー"""
|
||||
logger.info(f"シグナル {signum} を受信しました。アプリケーションを終了します...")
|
||||
monitor.stop_monitoring()
|
||||
sys.exit(0)
|
||||
|
||||
def main():
|
||||
"""メイン関数"""
|
||||
logger.info("Email to Discord Webhook Forwarder を開始します")
|
||||
logger.info(f"チェック間隔: {os.getenv('CHECK_INTERVAL', '60')}秒")
|
||||
logger.info(f"メールボックス: {os.getenv('MAILBOX', 'INBOX')}")
|
||||
logger.info(f"IMAPサーバー: {os.getenv('IMAP_SERVER', 'imap.gmail.com')}")
|
||||
|
||||
# メール監視インスタンスを作成
|
||||
monitor = EmailMonitor()
|
||||
|
||||
# シグナルハンドラーを設定
|
||||
signal.signal(signal.SIGINT, lambda s, f: signal_handler(s, f, monitor))
|
||||
signal.signal(signal.SIGTERM, lambda s, f: signal_handler(s, f, monitor))
|
||||
|
||||
try:
|
||||
# 監視開始
|
||||
monitor.start_monitoring()
|
||||
except Exception as e:
|
||||
logger.error(f"アプリケーションエラー: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
38
docker-compose.yml
Normal file
38
docker-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
email-to-discord:
|
||||
build: .
|
||||
container_name: email-to-discord-monitor
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# メールサーバー設定
|
||||
- IMAP_SERVER=imap.gmail.com
|
||||
- IMAP_PORT=993
|
||||
- USE_SSL=true
|
||||
- MAILBOX=INBOX
|
||||
|
||||
# メール認証情報(実際の値に変更してください)
|
||||
- EMAIL_USER=your-email@gmail.com
|
||||
- EMAIL_PASSWORD=your-app-password
|
||||
|
||||
# Discord Webhook URL(実際のURLに変更してください)
|
||||
- DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
||||
|
||||
# 監視設定
|
||||
- CHECK_INTERVAL=60 # チェック間隔(秒)
|
||||
|
||||
# ログの設定
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# リソース制限
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
reservations:
|
||||
memory: 128M
|
||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
requests==2.31.0
|
||||
python-dotenv==1.0.0
|
||||
343
start.ps1
Normal file
343
start.ps1
Normal file
@@ -0,0 +1,343 @@
|
||||
# Email to Discord Monitor - Windows起動スクリプト
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Action = ""
|
||||
)
|
||||
|
||||
# 色付きメッセージ用の関数
|
||||
function Write-ColoredText {
|
||||
param(
|
||||
[string]$Text,
|
||||
[string]$Color = "White"
|
||||
)
|
||||
Write-Host $Text -ForegroundColor $Color
|
||||
}
|
||||
|
||||
function Log-Info {
|
||||
param([string]$Message)
|
||||
Write-ColoredText "[INFO] $Message" "Green"
|
||||
}
|
||||
|
||||
function Log-Warn {
|
||||
param([string]$Message)
|
||||
Write-ColoredText "[WARN] $Message" "Yellow"
|
||||
}
|
||||
|
||||
function Log-Error {
|
||||
param([string]$Message)
|
||||
Write-ColoredText "[ERROR] $Message" "Red"
|
||||
}
|
||||
|
||||
function Log-Blue {
|
||||
param([string]$Message)
|
||||
Write-ColoredText "[INFO] $Message" "Blue"
|
||||
}
|
||||
|
||||
# ヘルプメッセージ
|
||||
function Show-Help {
|
||||
Write-Host "Email to Discord Monitor - Windows起動スクリプト"
|
||||
Write-Host ""
|
||||
Write-Host "使用方法:"
|
||||
Write-Host " .\start.ps1 [オプション]"
|
||||
Write-Host ""
|
||||
Write-Host "オプション:"
|
||||
Write-Host " build Dockerイメージをビルド"
|
||||
Write-Host " start コンテナを起動"
|
||||
Write-Host " stop コンテナを停止"
|
||||
Write-Host " restart コンテナを再起動"
|
||||
Write-Host " logs ログを表示"
|
||||
Write-Host " logs-f ログをリアルタイムで表示"
|
||||
Write-Host " status コンテナの状態を確認"
|
||||
Write-Host " clean 停止済みコンテナとイメージを削除"
|
||||
Write-Host " setup 初期セットアップ(.envファイル作成)"
|
||||
Write-Host " compose-up docker-compose で起動"
|
||||
Write-Host " compose-down docker-compose で停止"
|
||||
Write-Host " python Python直接実行"
|
||||
Write-Host " help このヘルプを表示"
|
||||
Write-Host ""
|
||||
Write-Host "例:"
|
||||
Write-Host " .\start.ps1 setup # 初期セットアップ"
|
||||
Write-Host " .\start.ps1 build # イメージをビルド"
|
||||
Write-Host " .\start.ps1 start # コンテナを起動"
|
||||
Write-Host " .\start.ps1 logs-f # ログをリアルタイム表示"
|
||||
}
|
||||
|
||||
# 必要なツールの確認
|
||||
function Test-Requirements {
|
||||
$missingTools = @()
|
||||
|
||||
if (!(Get-Command docker -ErrorAction SilentlyContinue)) {
|
||||
$missingTools += "docker"
|
||||
}
|
||||
|
||||
if (!(Get-Command docker-compose -ErrorAction SilentlyContinue)) {
|
||||
$missingTools += "docker-compose"
|
||||
}
|
||||
|
||||
if ($missingTools.Count -gt 0) {
|
||||
Log-Error "以下のツールがインストールされていません: $($missingTools -join ', ')"
|
||||
Log-Info "Dockerのインストール: https://docs.docker.com/desktop/windows/"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# .envファイルのセットアップ
|
||||
function Setup-Environment {
|
||||
Log-Info "初期セットアップを開始します..."
|
||||
|
||||
if (Test-Path ".env") {
|
||||
Log-Warn ".envファイルが既に存在します"
|
||||
$response = Read-Host "上書きしますか? (y/N)"
|
||||
if ($response -ne "y" -and $response -ne "Y") {
|
||||
Log-Info "セットアップをキャンセルしました"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Test-Path ".env.example")) {
|
||||
Log-Error ".env.exampleファイルが見つかりません"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Copy-Item ".env.example" ".env"
|
||||
Log-Info ".envファイルを作成しました"
|
||||
|
||||
Log-Blue "以下の設定を.envファイルに入力してください:"
|
||||
Write-Host ""
|
||||
Write-Host "1. EMAIL_USER=your-email@gmail.com"
|
||||
Write-Host "2. EMAIL_PASSWORD=your-app-password"
|
||||
Write-Host "3. DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"
|
||||
Write-Host ""
|
||||
Log-Warn "設定完了後、'.\start.ps1 build' でイメージをビルドしてください"
|
||||
}
|
||||
|
||||
# Dockerイメージをビルド
|
||||
function Build-Image {
|
||||
Log-Info "Dockerイメージをビルドしています..."
|
||||
docker build -t email-to-discord .
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Log-Info "ビルドが完了しました"
|
||||
} else {
|
||||
Log-Error "ビルドに失敗しました"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# コンテナを起動
|
||||
function Start-Container {
|
||||
Log-Info "コンテナを起動しています..."
|
||||
|
||||
# 既存のコンテナを確認・削除
|
||||
$existingContainer = docker ps -a --format "table {{.Names}}" | Select-String "^email-monitor$"
|
||||
if ($existingContainer) {
|
||||
Log-Warn "既存のコンテナを削除します..."
|
||||
docker rm -f email-monitor 2>$null
|
||||
}
|
||||
|
||||
# .envファイルの確認
|
||||
if (!(Test-Path ".env")) {
|
||||
Log-Error ".envファイルが見つかりません"
|
||||
Log-Info "'.\start.ps1 setup' を実行して設定を行ってください"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# コンテナを起動
|
||||
docker run -d `
|
||||
--name email-monitor `
|
||||
--restart unless-stopped `
|
||||
--env-file .env `
|
||||
email-to-discord
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Log-Info "コンテナが起動しました"
|
||||
Log-Blue "ログを確認するには: .\start.ps1 logs-f"
|
||||
} else {
|
||||
Log-Error "コンテナの起動に失敗しました"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# コンテナを停止
|
||||
function Stop-Container {
|
||||
Log-Info "コンテナを停止しています..."
|
||||
docker stop email-monitor 2>$null
|
||||
docker rm email-monitor 2>$null
|
||||
Log-Info "コンテナを停止しました"
|
||||
}
|
||||
|
||||
# コンテナを再起動
|
||||
function Restart-Container {
|
||||
Log-Info "コンテナを再起動しています..."
|
||||
Stop-Container
|
||||
Start-Sleep -Seconds 2
|
||||
Start-Container
|
||||
}
|
||||
|
||||
# ログを表示
|
||||
function Show-Logs {
|
||||
param([bool]$Follow = $false)
|
||||
|
||||
if ($Follow) {
|
||||
Log-Info "ログをリアルタイムで表示します (Ctrl+C で終了)"
|
||||
docker logs -f email-monitor
|
||||
} else {
|
||||
Log-Info "ログを表示します"
|
||||
docker logs email-monitor
|
||||
}
|
||||
}
|
||||
|
||||
# コンテナの状態を確認
|
||||
function Get-Status {
|
||||
Log-Info "コンテナの状態を確認しています..."
|
||||
|
||||
$runningContainer = docker ps --format "table {{.Names}}" | Select-String "email-monitor"
|
||||
if ($runningContainer) {
|
||||
Log-Info "コンテナは実行中です"
|
||||
docker ps --format "table {{.Names}}`t{{.Status}}`t{{.CreatedAt}}" | Select-String "email-monitor"
|
||||
} else {
|
||||
Log-Warn "コンテナは実行されていません"
|
||||
$stoppedContainer = docker ps -a --format "table {{.Names}}" | Select-String "email-monitor"
|
||||
if ($stoppedContainer) {
|
||||
Log-Info "停止済みコンテナが存在します"
|
||||
docker ps -a --format "table {{.Names}}`t{{.Status}}`t{{.CreatedAt}}" | Select-String "email-monitor"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# クリーンアップ
|
||||
function Invoke-Cleanup {
|
||||
Log-Info "クリーンアップを実行しています..."
|
||||
|
||||
# コンテナを停止・削除
|
||||
docker stop email-monitor 2>$null
|
||||
docker rm email-monitor 2>$null
|
||||
|
||||
# イメージを削除
|
||||
docker rmi email-to-discord 2>$null
|
||||
|
||||
# 未使用のリソースを削除
|
||||
docker system prune -f
|
||||
|
||||
Log-Info "クリーンアップが完了しました"
|
||||
}
|
||||
|
||||
# docker-compose で起動
|
||||
function Start-Compose {
|
||||
Log-Info "docker-compose でサービスを起動しています..."
|
||||
docker-compose up -d
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Log-Info "サービスが起動しました"
|
||||
Log-Blue "ログを確認するには: .\start.ps1 compose-logs"
|
||||
} else {
|
||||
Log-Error "サービスの起動に失敗しました"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# docker-compose で停止
|
||||
function Stop-Compose {
|
||||
Log-Info "docker-compose でサービスを停止しています..."
|
||||
docker-compose down
|
||||
Log-Info "サービスを停止しました"
|
||||
}
|
||||
|
||||
# Python直接実行
|
||||
function Start-Python {
|
||||
Log-Info "Python環境で直接実行します..."
|
||||
|
||||
# Python3の確認
|
||||
if (!(Get-Command python -ErrorAction SilentlyContinue)) {
|
||||
Log-Error "Pythonがインストールされていません"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# pipの確認
|
||||
if (!(Get-Command pip -ErrorAction SilentlyContinue)) {
|
||||
Log-Error "pipがインストールされていません"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 依存関係のインストール
|
||||
Log-Info "依存関係をインストールしています..."
|
||||
pip install -r requirements.txt
|
||||
|
||||
# .envファイルの確認
|
||||
if (!(Test-Path ".env")) {
|
||||
Log-Error ".envファイルが見つかりません"
|
||||
Log-Info "'.\start.ps1 setup' を実行して設定を行ってください"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 環境変数を読み込んで実行
|
||||
Log-Info "アプリケーションを起動しています..."
|
||||
|
||||
# .envファイルから環境変数を読み込み
|
||||
Get-Content ".env" | ForEach-Object {
|
||||
if ($_ -match "^([^=]+)=(.*)$") {
|
||||
[Environment]::SetEnvironmentVariable($matches[1], $matches[2], "Process")
|
||||
}
|
||||
}
|
||||
|
||||
python app.py
|
||||
}
|
||||
|
||||
# メイン処理
|
||||
switch ($Action.ToLower()) {
|
||||
"build" {
|
||||
Test-Requirements
|
||||
Build-Image
|
||||
}
|
||||
"start" {
|
||||
Test-Requirements
|
||||
Start-Container
|
||||
}
|
||||
"stop" {
|
||||
Stop-Container
|
||||
}
|
||||
"restart" {
|
||||
Test-Requirements
|
||||
Restart-Container
|
||||
}
|
||||
"logs" {
|
||||
Show-Logs
|
||||
}
|
||||
"logs-f" {
|
||||
Show-Logs -Follow $true
|
||||
}
|
||||
"status" {
|
||||
Get-Status
|
||||
}
|
||||
"clean" {
|
||||
Invoke-Cleanup
|
||||
}
|
||||
"setup" {
|
||||
Setup-Environment
|
||||
}
|
||||
"compose-up" {
|
||||
Test-Requirements
|
||||
Start-Compose
|
||||
}
|
||||
"compose-down" {
|
||||
Stop-Compose
|
||||
}
|
||||
"compose-logs" {
|
||||
docker-compose logs -f
|
||||
}
|
||||
"python" {
|
||||
Start-Python
|
||||
}
|
||||
"help" {
|
||||
Show-Help
|
||||
}
|
||||
"" {
|
||||
Log-Error "引数が指定されていません"
|
||||
Write-Host ""
|
||||
Show-Help
|
||||
}
|
||||
default {
|
||||
Log-Error "不明なオプション: $Action"
|
||||
Write-Host ""
|
||||
Show-Help
|
||||
}
|
||||
}
|
||||
344
start.sh
Normal file
344
start.sh
Normal file
@@ -0,0 +1,344 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Email to Discord Monitor - Linux起動スクリプト
|
||||
|
||||
set -e # エラー時に終了
|
||||
|
||||
# 色付きメッセージ用の定数
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# ログ関数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_blue() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
# ヘルプメッセージ
|
||||
show_help() {
|
||||
echo "Email to Discord Monitor - 起動スクリプト"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " $0 [オプション]"
|
||||
echo ""
|
||||
echo "オプション:"
|
||||
echo " build Dockerイメージをビルド"
|
||||
echo " start コンテナを起動"
|
||||
echo " stop コンテナを停止"
|
||||
echo " restart コンテナを再起動"
|
||||
echo " logs ログを表示"
|
||||
echo " logs-f ログをリアルタイムで表示"
|
||||
echo " status コンテナの状態を確認"
|
||||
echo " clean 停止済みコンテナとイメージを削除"
|
||||
echo " setup 初期セットアップ(.envファイル作成)"
|
||||
echo " compose-up docker-compose で起動"
|
||||
echo " compose-down docker-compose で停止"
|
||||
echo " python Python直接実行"
|
||||
echo " help このヘルプを表示"
|
||||
echo ""
|
||||
echo "例:"
|
||||
echo " $0 setup # 初期セットアップ"
|
||||
echo " $0 build # イメージをビルド"
|
||||
echo " $0 start # コンテナを起動"
|
||||
echo " $0 logs-f # ログをリアルタイム表示"
|
||||
}
|
||||
|
||||
# 必要なツールの確認
|
||||
check_requirements() {
|
||||
local missing_tools=()
|
||||
|
||||
if ! command -v docker &> /dev/null; then
|
||||
missing_tools+=("docker")
|
||||
fi
|
||||
|
||||
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
|
||||
missing_tools+=("docker-compose")
|
||||
fi
|
||||
|
||||
if [ ${#missing_tools[@]} -ne 0 ]; then
|
||||
log_error "以下のツールがインストールされていません: ${missing_tools[*]}"
|
||||
log_info "Dockerのインストール: https://docs.docker.com/get-docker/"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# .envファイルのセットアップ
|
||||
setup_env() {
|
||||
log_info "初期セットアップを開始します..."
|
||||
|
||||
if [ -f ".env" ]; then
|
||||
log_warn ".envファイルが既に存在します"
|
||||
read -p "上書きしますか? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "セットアップをキャンセルしました"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f ".env.example" ]; then
|
||||
log_error ".env.exampleファイルが見つかりません"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp .env.example .env
|
||||
log_info ".envファイルを作成しました"
|
||||
|
||||
log_blue "以下の設定を.envファイルに入力してください:"
|
||||
echo ""
|
||||
echo "1. EMAIL_USER=your-email@gmail.com"
|
||||
echo "2. EMAIL_PASSWORD=your-app-password"
|
||||
echo "3. DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"
|
||||
echo ""
|
||||
log_warn "設定完了後、'$0 build' でイメージをビルドしてください"
|
||||
}
|
||||
|
||||
# Dockerイメージをビルド
|
||||
build_image() {
|
||||
log_info "Dockerイメージをビルドしています..."
|
||||
docker build -t email-to-discord .
|
||||
log_info "ビルドが完了しました"
|
||||
}
|
||||
|
||||
# コンテナを起動
|
||||
start_container() {
|
||||
log_info "コンテナを起動しています..."
|
||||
|
||||
# 既存のコンテナを確認
|
||||
if docker ps -a --format "table {{.Names}}" | grep -q "^email-monitor$"; then
|
||||
log_warn "既存のコンテナを削除します..."
|
||||
docker rm -f email-monitor 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# .envファイルの確認
|
||||
if [ ! -f ".env" ]; then
|
||||
log_error ".envファイルが見つかりません"
|
||||
log_info "'$0 setup' を実行して設定を行ってください"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 環境変数を読み込み
|
||||
source .env
|
||||
|
||||
# 必須変数の確認
|
||||
if [ -z "$EMAIL_USER" ] || [ -z "$EMAIL_PASSWORD" ] || [ -z "$DISCORD_WEBHOOK_URL" ]; then
|
||||
log_error "必須の環境変数が設定されていません"
|
||||
log_info ".envファイルを確認してください"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# コンテナを起動
|
||||
docker run -d \
|
||||
--name email-monitor \
|
||||
--restart unless-stopped \
|
||||
--env-file .env \
|
||||
email-to-discord
|
||||
|
||||
log_info "コンテナが起動しました"
|
||||
log_blue "ログを確認するには: $0 logs-f"
|
||||
}
|
||||
|
||||
# コンテナを停止
|
||||
stop_container() {
|
||||
log_info "コンテナを停止しています..."
|
||||
docker stop email-monitor 2>/dev/null || log_warn "コンテナが実行されていません"
|
||||
docker rm email-monitor 2>/dev/null || log_warn "削除するコンテナがありません"
|
||||
log_info "コンテナを停止しました"
|
||||
}
|
||||
|
||||
# コンテナを再起動
|
||||
restart_container() {
|
||||
log_info "コンテナを再起動しています..."
|
||||
stop_container
|
||||
sleep 2
|
||||
start_container
|
||||
}
|
||||
|
||||
# ログを表示
|
||||
show_logs() {
|
||||
if [ "$1" = "-f" ]; then
|
||||
log_info "ログをリアルタイムで表示します (Ctrl+C で終了)"
|
||||
docker logs -f email-monitor
|
||||
else
|
||||
log_info "ログを表示します"
|
||||
docker logs email-monitor
|
||||
fi
|
||||
}
|
||||
|
||||
# コンテナの状態を確認
|
||||
check_status() {
|
||||
log_info "コンテナの状態を確認しています..."
|
||||
|
||||
if docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -q "email-monitor"; then
|
||||
log_info "コンテナは実行中です"
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}" | grep email-monitor
|
||||
else
|
||||
log_warn "コンテナは実行されていません"
|
||||
if docker ps -a --format "table {{.Names}}" | grep -q "email-monitor"; then
|
||||
log_info "停止済みコンテナが存在します"
|
||||
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}" | grep email-monitor
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# クリーンアップ
|
||||
cleanup() {
|
||||
log_info "クリーンアップを実行しています..."
|
||||
|
||||
# コンテナを停止・削除
|
||||
docker stop email-monitor 2>/dev/null || true
|
||||
docker rm email-monitor 2>/dev/null || true
|
||||
|
||||
# イメージを削除
|
||||
docker rmi email-to-discord 2>/dev/null || log_warn "削除するイメージがありません"
|
||||
|
||||
# 未使用のリソースを削除
|
||||
docker system prune -f
|
||||
|
||||
log_info "クリーンアップが完了しました"
|
||||
}
|
||||
|
||||
# docker-compose で起動
|
||||
compose_up() {
|
||||
log_info "docker-compose でサービスを起動しています..."
|
||||
|
||||
if command -v docker-compose &> /dev/null; then
|
||||
docker-compose up -d
|
||||
else
|
||||
docker compose up -d
|
||||
fi
|
||||
|
||||
log_info "サービスが起動しました"
|
||||
log_blue "ログを確認するには: $0 compose-logs"
|
||||
}
|
||||
|
||||
# docker-compose で停止
|
||||
compose_down() {
|
||||
log_info "docker-compose でサービスを停止しています..."
|
||||
|
||||
if command -v docker-compose &> /dev/null; then
|
||||
docker-compose down
|
||||
else
|
||||
docker compose down
|
||||
fi
|
||||
|
||||
log_info "サービスを停止しました"
|
||||
}
|
||||
|
||||
# Python直接実行
|
||||
run_python() {
|
||||
log_info "Python環境で直接実行します..."
|
||||
|
||||
# Python3の確認
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
log_error "Python3がインストールされていません"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# pipの確認
|
||||
if ! command -v pip3 &> /dev/null; then
|
||||
log_error "pip3がインストールされていません"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 依存関係のインストール
|
||||
log_info "依存関係をインストールしています..."
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
# .envファイルの確認
|
||||
if [ ! -f ".env" ]; then
|
||||
log_error ".envファイルが見つかりません"
|
||||
log_info "'$0 setup' を実行して設定を行ってください"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 環境変数を読み込んで実行
|
||||
log_info "アプリケーションを起動しています..."
|
||||
export $(cat .env | xargs)
|
||||
python3 app.py
|
||||
}
|
||||
|
||||
# メイン処理
|
||||
main() {
|
||||
case "$1" in
|
||||
"build")
|
||||
check_requirements
|
||||
build_image
|
||||
;;
|
||||
"start")
|
||||
check_requirements
|
||||
start_container
|
||||
;;
|
||||
"stop")
|
||||
stop_container
|
||||
;;
|
||||
"restart")
|
||||
check_requirements
|
||||
restart_container
|
||||
;;
|
||||
"logs")
|
||||
show_logs
|
||||
;;
|
||||
"logs-f")
|
||||
show_logs -f
|
||||
;;
|
||||
"status")
|
||||
check_status
|
||||
;;
|
||||
"clean")
|
||||
cleanup
|
||||
;;
|
||||
"setup")
|
||||
setup_env
|
||||
;;
|
||||
"compose-up")
|
||||
check_requirements
|
||||
compose_up
|
||||
;;
|
||||
"compose-down")
|
||||
compose_down
|
||||
;;
|
||||
"compose-logs")
|
||||
if command -v docker-compose &> /dev/null; then
|
||||
docker-compose logs -f
|
||||
else
|
||||
docker compose logs -f
|
||||
fi
|
||||
;;
|
||||
"python")
|
||||
run_python
|
||||
;;
|
||||
"help"|"--help"|"-h")
|
||||
show_help
|
||||
;;
|
||||
"")
|
||||
log_error "引数が指定されていません"
|
||||
echo ""
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
log_error "不明なオプション: $1"
|
||||
echo ""
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# スクリプト実行
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user