Coverage for view / web / routes / streaming.py: 100%

33 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-04 15:08 +0000

1""" 

2실시간 현재가 구독 관리 API 엔드포인트. 

3PriceSubscriptionService를 통해 UI에서 구독 요청/해지/현황 조회. 

4""" 

5from fastapi import APIRouter, HTTPException 

6from pydantic import BaseModel 

7from view.web.api_common import _get_ctx 

8from services.price_subscription_service import SubscriptionPriority 

9 

10router = APIRouter() 

11 

12 

13class SubscribeRequest(BaseModel): 

14 code: str 

15 reason: str # "ui_view", "watchlist" 등 

16 

17 

18@router.post("/streaming/subscribe") 

19async def subscribe_stock(req: SubscribeRequest): 

20 """UI에서 특정 종목 실시간 가격 구독 요청.""" 

21 ctx = _get_ctx() 

22 svc = getattr(ctx, "price_subscription_service", None) 

23 if not svc: 

24 raise HTTPException(status_code=503, detail="PriceSubscriptionService가 초기화되지 않았습니다") 

25 

26 category_key = f"ui_{req.reason}" 

27 await svc.add_subscription(req.code, SubscriptionPriority.LOW, category_key) 

28 return {"success": True, "code": req.code, "category": category_key} 

29 

30 

31@router.post("/streaming/unsubscribe") 

32async def unsubscribe_stock(req: SubscribeRequest): 

33 """UI에서 특정 종목 실시간 가격 구독 해지.""" 

34 ctx = _get_ctx() 

35 svc = getattr(ctx, "price_subscription_service", None) 

36 if not svc: 

37 raise HTTPException(status_code=503, detail="PriceSubscriptionService가 초기화되지 않았습니다") 

38 

39 category_key = f"ui_{req.reason}" 

40 await svc.remove_subscription(req.code, category_key) 

41 return {"success": True, "code": req.code, "category": category_key} 

42 

43 

44@router.get("/streaming/status") 

45def get_streaming_status(): 

46 """현재 실시간 구독 현황 반환.""" 

47 ctx = _get_ctx() 

48 svc = getattr(ctx, "price_subscription_service", None) 

49 if not svc: 

50 return {"success": True, "data": {"active_count": 0, "active_codes": []}} 

51 

52 return {"success": True, "data": svc.get_status()}