Skip to content

Commit

Permalink
⏪️ aiohttp 관련 변경사항 revert
Browse files Browse the repository at this point in the history
"aiohttp 사용하도록 변경"부터 "async 함수를 await 하지 않아서 발생하던 오류 수정"까지
  • Loading branch information
junah201 committed Apr 24, 2024
1 parent e01a86a commit 6d469ff
Show file tree
Hide file tree
Showing 7 changed files with 292 additions and 358 deletions.
11 changes: 2 additions & 9 deletions lambdas/event_handler/events/add_notification.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import asyncio
import aiohttp
from datetime import datetime
import json

Expand All @@ -14,7 +12,7 @@
dynamodb = boto3.client('dynamodb')


async def middleware(event, context):
def handler(event, context):
body = json.loads(event["body"])
data = body.get("data", {})

Expand Down Expand Up @@ -62,8 +60,7 @@ async def middleware(event, context):
},
}

async with aiohttp.ClientSession() as session:
chzzk = await get_chzzk(chzzk_id, session=session)
chzzk = get_chzzk(chzzk_id)

# 실제 치지직 채널이 있는지 확인
if not chzzk:
Expand Down Expand Up @@ -216,7 +213,3 @@ async def middleware(event, context):
],
}
}


def handler(event, context):
return asyncio.run(middleware(event, context))
295 changes: 129 additions & 166 deletions lambdas/live_check/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
특정 시간마다 DynamoDB에 저장된 채널 정보들을 조회하여 채널이 라이브 중일 경우 디스코드 알림을 보냅니다.
"""

import asyncio
import json
from datetime import datetime

Expand All @@ -17,159 +16,19 @@
dynamodb = boto3.client('dynamodb')


async def send_notice_message(
chzzk: ChzzkLive,
noti: dict,
index: str,
session: aiohttp.ClientSession
) -> bool:
"""
해당 디스코드 채널로 방송 알림 메시지를 전송하고, 성공 여부를 반환합니다.
"""

res = await send_message(
channel_id=noti["channel_id"]["S"],
data={
"content": noti.get("custom_message", {}).get("S", ""),
"embeds": [
{
"title": f"{chzzk['liveTitle']}",
"description": f"{chzzk['channel']['channelName']} 님이 방송을 시작했습니다.",
"color": 0x02E895,
"fields": [
{
"name": '카테고리',
"value": chzzk['liveCategoryValue']
}
],
"image": {
"url": (chzzk['liveImageUrl'] or chzzk['channel']['channelImageUrl'] or "").replace("_{type}", "_1080"),
},
"author": {
"name": f"{chzzk['channel']['channelName']}",
"url": f"https://chzzk.naver.com/live/{chzzk['channel']['channelId']}",
"icon_url": chzzk['channel']['channelImageUrl'] or "https://ssl.pstatic.net/cmstatic/nng/img/img_anonymous_square_gray_opacity2x.png?type=f120_120_na"
},
"footer": {
"text": f"치직 ({index})"
},
"url": f"https://chzzk.naver.com/live/{chzzk['channel']['channelId']}",
"timestamp": datetime.now().isoformat()
},
],
"components": [
{
"type": COMPONENT_TYPE.ACTION_ROW,
"components": [
{
"type": COMPONENT_TYPE.BUTTON,
"label": "바로가기",
"style": BUTTON_STYLE.LINK,
"url": f"https://chzzk.naver.com/live/{chzzk['channel']['channelId']}"
}
]
},
],
},
session=session
)

# 채널이 존재하지 않는 경우
if res.status == 404:
print(
f"channel not found, NOTI#{noti['channel_id']['S']} CHZZK#{chzzk['channel']['channelId']}, index: {index}"
)
dynamodb.delete_item(
TableName='chzzk-bot-db',
Key={
'PK': noti.get('PK'),
'SK': noti.get('SK')
}
)
return False

# 메시지 전송에 실패한 경우
if res.status != 200:
msg = f"send message fail {res.status}, NOTI#{noti['channel_id']['S']} CHZZK#{chzzk['channel']['channelId']}, index: {index}"
try:
msg += f"\n{await res.json()}"
except:
try:
msg += f"\n{await res.text()}"
except Exception as e:
msg += f"\n{e}"
print(msg)
return False

# 성공
print(
f"send message success, NOTI#{noti['channel_id']['S']} CHZZK#{chzzk['channel']['channelId']}, index: {index}")
return True


async def check_live(item: dict, index: str, session: aiohttp.ClientSession):
chzzk_channel_id = item["PK"]["S"].split("#")[1]
last_live_id = item["lastLiveId"]["N"]

chzzk = await get_chzzk(
chzzk_channel_id,
session=session
)
if not chzzk:
return (1, 0, 0, 0)

if str(chzzk['liveId']) == str(last_live_id):
return (1, 0, 0, 0)

if chzzk['status'] != "OPEN":
return (1, 0, 0, 0)

dynamodb.update_item(
TableName='chzzk-bot-db',
Key={
'PK': item.get('PK'),
'SK': item.get('SK')
},
UpdateExpression='SET lastLiveId = :live_id, lastLiveTitle = :live_title',
ExpressionAttributeValues={
':live_id': {'N': f"{chzzk['liveId']}"},
':live_title': {'S': chzzk['liveTitle']}
}
)

print(
f"LIVE_START {chzzk['channel']['channelName']}, {chzzk['liveId']}, {chzzk['liveTitle']}, index: {index}")

all_noti = dynamodb.query(
TableName='chzzk-bot-db',
KeyConditionExpression='PK = :pk_val AND begins_with(SK, :sk_val)',
ExpressionAttributeValues={
':pk_val': {'S': f"CHZZK#{chzzk_channel_id}"},
':sk_val': {'S': 'NOTI#'}
}
)

tmp = await asyncio.gather(
*[
send_notice_message(
chzzk,
noti,
index=index,
session=session
) for noti in all_noti["Items"]
]
)

# 총 채널 개수, 라이브를 킨 채널 개수, 알림 전송 성공 개수, 알림 전송 실패 개수
return (1, 1, tmp.count(True), tmp.count(False))


async def middleware(event, context):
def middleware(event, context):
index = int(event.get("resources", [])[0][-1])
"""
트리거마다 처리하는 데이터가 다르게 분산화합니다.
"""

result = {
"total_channel_count": 0,
"live_channel_count": 0,
"total_send_count": 0,
"fail_send_count": 0,
}

res = dynamodb.query(
TableName='chzzk-bot-db',
IndexName='GSI-index',
Expand All @@ -182,30 +41,134 @@ async def middleware(event, context):
}
)

async with aiohttp.ClientSession() as session:
tmp = await asyncio.gather(
*[
check_live(
item,
index,
session
) for item in res["Items"]
]
result["total_channel_count"] = res["Count"]

for item in res["Items"]:
channel_id = item["PK"]["S"].split("#")[1]
last_live_id = item["lastLiveId"]["N"]

chzzk = get_chzzk(channel_id)

if not chzzk:
continue

if str(chzzk['liveId']) == str(last_live_id):
continue

if chzzk['status'] != "OPEN":
continue

result["live_channel_count"] += 1

dynamodb.update_item(
TableName='chzzk-bot-db',
Key={
'PK': item.get('PK'),
'SK': item.get('SK')
},
UpdateExpression='SET lastLiveId = :live_id, lastLiveTitle = :live_title',
ExpressionAttributeValues={
':live_id': {'N': f"{chzzk['liveId']}"},
':live_title': {'S': chzzk['liveTitle']}
}
)

result = {
"index": index,
"total_channel_count": sum([i[0] for i in tmp]),
"live_channel_count": sum([i[1] for i in tmp]),
"total_send_count": sum([i[2] for i in tmp]),
"fail_send_count": sum([i[3] for i in tmp]),
}
print(
f"LIVE_START {chzzk['channel']['channelName']}, {chzzk['liveId']}, {chzzk['liveTitle']}, {index=}")

res = dynamodb.query(
TableName='chzzk-bot-db',
KeyConditionExpression='PK = :pk_val AND begins_with(SK, :sk_val)',
ExpressionAttributeValues={
':pk_val': {'S': f"CHZZK#{channel_id}"},
':sk_val': {'S': 'NOTI#'}
}
)

for noti in res["Items"]:
discord_channel_id = noti["channel_id"]["S"]

res = send_message(
channel_id=discord_channel_id,
data={
"content": noti.get("custom_message", {}).get("S", ""),
"embeds": [
{
"title": f"{chzzk['liveTitle']}",
"description": f"{chzzk['channel']['channelName']} 님이 방송을 시작했습니다.",
"color": 0x02E895,
"fields": [
{
"name": '카테고리',
"value": chzzk['liveCategoryValue']
}
],
"image": {
"url": (chzzk['liveImageUrl'] or chzzk['channel']['channelImageUrl'] or "").replace("_{type}", "_1080"),
},
"author": {
"name": f"{chzzk['channel']['channelName']}",
"url": f"https://chzzk.naver.com/live/{channel_id}",
"icon_url": chzzk['channel']['channelImageUrl'] or "https://ssl.pstatic.net/cmstatic/nng/img/img_anonymous_square_gray_opacity2x.png?type=f120_120_na"
},
"footer": {
"text": "치직"
},
"url": f"https://chzzk.naver.com/live/{channel_id}",
"timestamp": datetime.now().isoformat()
},
],
"components": [
{
"type": COMPONENT_TYPE.ACTION_ROW,
"components": [
{
"type": COMPONENT_TYPE.BUTTON,
"label": "바로가기",
"style": BUTTON_STYLE.LINK,
"url": f"https://chzzk.naver.com/live/{channel_id}"
}
]
},
],
}
)

# 채널이 존재하지 않는 경우
if res.status_code == 404:
print("channel not found")
dynamodb.delete_item(
TableName='chzzk-bot-db',
Key={
'PK': noti.get('PK'),
'SK': noti.get('SK')
}
)
result["fail_send_count"] += 1
continue

# 메시지 전송에 실패한 경우
if res.status_code != 200:
print("send message fail", res.status_code)
try:
print(res.json())
except:
try:
print(res.text)
except:
print("unknown error")
result["fail_send_count"] += 1
continue

# 성공
print("send message success")
result["total_send_count"] += 1

return result


def lambda_handler(event, context):
res = asyncio.run(middleware(event, context))
res = middleware(event, context)

print("=== res ===")
print(json.dumps(res))
Expand Down
Loading

0 comments on commit 6d469ff

Please sign in to comment.