175 lines
6.0 KiB
Python
175 lines
6.0 KiB
Python
import os
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
import boto3
|
|
import cups
|
|
import yaml
|
|
from dotenv import load_dotenv
|
|
from loguru import logger
|
|
|
|
class Config:
|
|
def __init__(self):
|
|
load_dotenv()
|
|
with open('config.yaml', 'r') as f:
|
|
self.config = yaml.safe_load(f)
|
|
|
|
# 環境変数で設定値を上書き
|
|
self.config['s3']['bucket'] = os.getenv('S3_BUCKET_NAME', self.config['s3']['bucket'])
|
|
self.config['s3']['prefix'] = self.config['s3']['prefix'].replace('${LOCATION}', os.getenv('LOCATION', ''))
|
|
self.config['printer']['name'] = os.getenv('PRINTER_NAME', self.config['printer']['name'])
|
|
|
|
class S3Manager:
|
|
def __init__(self, config: Config):
|
|
self.config = config
|
|
self.s3_client = boto3.client('s3')
|
|
|
|
def list_files(self) -> List[str]:
|
|
"""S3バケットのファイル一覧を取得"""
|
|
try:
|
|
files = []
|
|
paginator = self.s3_client.get_paginator('list_objects_v2')
|
|
for page in paginator.paginate(
|
|
Bucket=self.config.config['s3']['bucket'],
|
|
Prefix=self.config.config['s3']['prefix']
|
|
):
|
|
if 'Contents' in page:
|
|
files.extend([obj['Key'] for obj in page['Contents']])
|
|
return files
|
|
except Exception as e:
|
|
logger.error(f"S3ファイル一覧の取得に失敗: {e}")
|
|
return []
|
|
|
|
def download_file(self, key: str, local_path: str) -> bool:
|
|
"""S3からファイルをダウンロード"""
|
|
try:
|
|
self.s3_client.download_file(
|
|
self.config.config['s3']['bucket'],
|
|
key,
|
|
local_path
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"ファイルのダウンロードに失敗 {key}: {e}")
|
|
return False
|
|
|
|
class PrinterManager:
|
|
def __init__(self, config: Config):
|
|
self.config = config
|
|
self.conn = cups.Connection()
|
|
|
|
def print_file(self, filepath: str) -> bool:
|
|
"""ファイルを印刷"""
|
|
printer_config = self.config.config['printer']
|
|
max_attempts = printer_config['retry']['max_attempts']
|
|
delay = printer_config['retry']['delay_seconds']
|
|
|
|
for attempt in range(max_attempts):
|
|
try:
|
|
job_id = self.conn.printFile(
|
|
printer_config['name'],
|
|
filepath,
|
|
"Rogaining Score",
|
|
printer_config['options']
|
|
)
|
|
logger.info(f"印刷ジョブを送信: {filepath} (Job ID: {job_id})")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"印刷に失敗 (試行 {attempt + 1}/{max_attempts}): {e}")
|
|
if attempt < max_attempts - 1:
|
|
time.sleep(delay)
|
|
else:
|
|
return False
|
|
|
|
class FileManager:
|
|
def __init__(self, config: Config):
|
|
self.config = config
|
|
self.file_log_path = Path(self.config.config['app']['save_path']) / self.config.config['app']['file_log']
|
|
self.processed_files = self._load_processed_files()
|
|
|
|
def _load_processed_files(self) -> List[str]:
|
|
"""処理済みファイルの一覧を読み込み"""
|
|
try:
|
|
if self.file_log_path.exists():
|
|
with open(self.file_log_path, 'r') as f:
|
|
return json.load(f)
|
|
return []
|
|
except Exception as e:
|
|
logger.error(f"処理済みファイル一覧の読み込みに失敗: {e}")
|
|
return []
|
|
|
|
def save_processed_files(self):
|
|
"""処理済みファイルの一覧を保存"""
|
|
try:
|
|
self.file_log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(self.file_log_path, 'w') as f:
|
|
json.dump(self.processed_files, f)
|
|
except Exception as e:
|
|
logger.error(f"処理済みファイル一覧の保存に失敗: {e}")
|
|
|
|
def get_new_files(self, current_files: List[str]) -> List[str]:
|
|
"""新規ファイルを特定"""
|
|
return list(set(current_files) - set(self.processed_files))
|
|
|
|
def setup_logging(config: Config):
|
|
"""ロギングの設定"""
|
|
log_path = Path(config.config['app']['log_path'])
|
|
log_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
logger.add(
|
|
log_path / "app.log",
|
|
rotation="1 day",
|
|
retention="30 days",
|
|
level="INFO"
|
|
)
|
|
logger.add(
|
|
log_path / config.config['app']['error_log'],
|
|
level="ERROR"
|
|
)
|
|
|
|
def main():
|
|
config = Config()
|
|
setup_logging(config)
|
|
|
|
s3_manager = S3Manager(config)
|
|
printer_manager = PrinterManager(config)
|
|
file_manager = FileManager(config)
|
|
|
|
logger.info("スコアボード監視システムを開始")
|
|
|
|
while True:
|
|
try:
|
|
# S3のファイル一覧を取得
|
|
current_files = s3_manager.list_files()
|
|
|
|
# 新規ファイルを特定
|
|
new_files = file_manager.get_new_files(current_files)
|
|
|
|
for file_key in new_files:
|
|
if not file_key.endswith('.pdf'):
|
|
file_manager.processed_files.append(file_key)
|
|
continue
|
|
|
|
# 保存先パスの設定
|
|
local_path = Path(config.config['app']['save_path']) / Path(file_key).name
|
|
local_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# ファイルのダウンロードと印刷
|
|
if s3_manager.download_file(file_key, str(local_path)):
|
|
if printer_manager.print_file(str(local_path)):
|
|
file_manager.processed_files.append(file_key)
|
|
file_manager.save_processed_files()
|
|
|
|
time.sleep(10) # ポーリング間隔
|
|
|
|
except Exception as e:
|
|
logger.error(f"予期せぬエラーが発生: {e}")
|
|
time.sleep(30) # エラー時は長めの待機
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|