[+] clean async_api
1. comment out not used logic; 2. remove app.py and websocket_api.py;
This commit is contained in:
		
							parent
							
								
									c81ee3c4ec
								
							
						
					
					
						commit
						207a8737ba
					
				
							
								
								
									
										68
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/app.py
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										68
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/app.py
									
									
									
									
										vendored
									
									
								
							| @ -1,68 +0,0 @@ | |||||||
| import asyncio |  | ||||||
| import datetime |  | ||||||
| import logging |  | ||||||
| # import os |  | ||||||
| from ..tickers_retrieval.emcont import Emcont |  | ||||||
| from ..tickers.models import Ticker |  | ||||||
| from ..tickers.logic import ticker_store_multiple, markets_get_by_symbol |  | ||||||
| from .db import create_engine |  | ||||||
| import sqlalchemy.ext.asyncio |  | ||||||
| from sqlalchemy.ext.asyncio import AsyncSession |  | ||||||
| from sqlalchemy.ext.asyncio import async_sessionmaker |  | ||||||
| 
 |  | ||||||
| from typing import Any |  | ||||||
| 
 |  | ||||||
| logger = logging.getLogger(__name__) |  | ||||||
| 
 |  | ||||||
| async def run() -> None: |  | ||||||
| 	async_session = create_engine() |  | ||||||
| 
 |  | ||||||
| 	async def store_cb( |  | ||||||
| 		rates: list[Emcont.rates_get_t.data_t.rate_t], |  | ||||||
| 		timestamp: datetime.datetime, |  | ||||||
| 		session: 'async_sessionmaker[AsyncSession]', |  | ||||||
| 	) -> None: |  | ||||||
| 		logger.info(dict( |  | ||||||
| 			msg='before markets', |  | ||||||
| 		)) |  | ||||||
| 
 |  | ||||||
| 		markets = await markets_get_by_symbol( |  | ||||||
| 			session, |  | ||||||
| 			set([ |  | ||||||
| 				rate.symbol |  | ||||||
| 				for rate in rates |  | ||||||
| 			]), |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 		logger.info(dict( |  | ||||||
| 			msg='after markets', |  | ||||||
| 		)) |  | ||||||
| 
 |  | ||||||
| 		await ticker_store_multiple( |  | ||||||
| 			session, |  | ||||||
| 			[ |  | ||||||
| 				Ticker( |  | ||||||
| 					id=markets[rate.symbol], |  | ||||||
| 					timestamp=timestamp, |  | ||||||
| 					value=rate.value, |  | ||||||
| 				) |  | ||||||
| 				for rate in rates |  | ||||||
| 			] |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 		logger.info(dict( |  | ||||||
| 			rates=rates, |  | ||||||
| 			timestamp=timestamp.isoformat() |  | ||||||
| 		)) |  | ||||||
| 
 |  | ||||||
| 	await Emcont.worker( |  | ||||||
| 		only_symbols={'EURUSD', 'USDJPY', 'GBPUSD', 'AUDUSD', 'USDCAD'}, |  | ||||||
| 		session=async_session, |  | ||||||
| 		store_cb=store_cb, |  | ||||||
| 		request_timeout=2, |  | ||||||
| 		store_timeout=0.5, |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
| 	logging.basicConfig(level=logging.INFO) |  | ||||||
| 	asyncio.run(run()) |  | ||||||
							
								
								
									
										2
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/db.py
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/db.py
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| from ..tickers.settings import Settings as ModelsSettings | from ..payloads.settings import Settings as ModelsSettings | ||||||
| 
 | 
 | ||||||
| import sqlalchemy.ext.asyncio | import sqlalchemy.ext.asyncio | ||||||
| from sqlalchemy.ext.asyncio import AsyncSession | from sqlalchemy.ext.asyncio import AsyncSession | ||||||
|  | |||||||
							
								
								
									
										60
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/fastapi.py
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										60
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/fastapi.py
									
									
									
									
										vendored
									
									
								
							| @ -9,49 +9,49 @@ import sys | |||||||
| 
 | 
 | ||||||
| from .settings import Settings as APISettings | from .settings import Settings as APISettings | ||||||
| from .db import create_engine | from .db import create_engine | ||||||
| from .websocket_api import WebsocketAPI | # from .websocket_api import WebsocketAPI | ||||||
| 
 | 
 | ||||||
| from typing import (Any, Optional, Literal, Annotated,) | from typing import (Any, Optional, Literal, Annotated,) | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| async def websocket_tickers( | # async def websocket_tickers( | ||||||
| 	websocket: fastapi.WebSocket, | # 	websocket: fastapi.WebSocket, | ||||||
| 	websocket_api: WebsocketAPI, | # 	websocket_api: WebsocketAPI, | ||||||
| ) -> None: | # ) -> None: | ||||||
| 	try: | # 	try: | ||||||
| 		await websocket_api.connect(websocket) | # 		await websocket_api.connect(websocket) | ||||||
| 
 | # | ||||||
| 		while True: | # 		while True: | ||||||
| 			msg = await websocket.receive_text() | # 			msg = await websocket.receive_text() | ||||||
| 			await websocket_api.on_message(websocket, msg) | # 			await websocket_api.on_message(websocket, msg) | ||||||
| 	except fastapi.WebSocketDisconnect: | # 	except fastapi.WebSocketDisconnect: | ||||||
| 		pass | # 		pass | ||||||
| 		# websocket_api.disconnect(websocket) | # 		# websocket_api.disconnect(websocket) | ||||||
| 	except: | # 	except: | ||||||
| 		logger.exception('') | # 		logger.exception('') | ||||||
| 		raise | # 		raise | ||||||
| 	finally: | # 	finally: | ||||||
| 		await websocket_api.disconnect(websocket) | # 		await websocket_api.disconnect(websocket) | ||||||
| 
 | 
 | ||||||
| def create_app() -> fastapi.FastAPI: | def create_app() -> fastapi.FastAPI: | ||||||
| 	async_session = create_engine() | 	async_session = create_engine() | ||||||
| 
 | 
 | ||||||
| 	websocket_api = WebsocketAPI( | 	# websocket_api = WebsocketAPI( | ||||||
| 		session=async_session, | 	# 	session=async_session, | ||||||
| 	) | 	# ) | ||||||
| 
 | 
 | ||||||
| 	app = fastapi.FastAPI() | 	app = fastapi.FastAPI() | ||||||
| 
 | 
 | ||||||
| 	app.websocket( | 	# app.websocket( | ||||||
| 		'/tickers/', | 	# 	'/tickers/', | ||||||
| 	)( | 	# )( | ||||||
| 		functools.partial( | 	# 	functools.partial( | ||||||
| 			websocket_tickers, | 	# 		websocket_tickers, | ||||||
| 			websocket_api=fastapi.Depends(lambda : websocket_api), | 	# 		websocket_api=fastapi.Depends(lambda : websocket_api), | ||||||
| 		) | 	# 	) | ||||||
| 	) | 	# ) | ||||||
| 
 | 
 | ||||||
| 	return app | 	return app | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										125
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/schema.py
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										125
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/schema.py
									
									
									
									
										vendored
									
									
								
							| @ -3,65 +3,66 @@ import decimal | |||||||
| 
 | 
 | ||||||
| from typing import (Literal, Annotated,) | from typing import (Literal, Annotated,) | ||||||
| 
 | 
 | ||||||
| class SubscribeAction(pydantic.BaseModel): | # class SubscribeAction(pydantic.BaseModel): | ||||||
| 	action: Literal['subscribe'] | # 	action: Literal['subscribe'] | ||||||
| 	class message_t(pydantic.BaseModel): | # 	class message_t(pydantic.BaseModel): | ||||||
| 		asset_id: Annotated[ | # 		asset_id: Annotated[ | ||||||
| 			int, | # 			int, | ||||||
| 			pydantic.Field(alias='assetId') | # 			pydantic.Field(alias='assetId') | ||||||
| 		] | # 		] | ||||||
| 
 | # | ||||||
| 	message: message_t | # 	message: message_t | ||||||
| 
 | # | ||||||
| class AssetsAction(pydantic.BaseModel): | # class AssetsAction(pydantic.BaseModel): | ||||||
| 	action: Literal['assets'] | # 	action: Literal['assets'] | ||||||
| 	class message_t(pydantic.BaseModel): | # 	class message_t(pydantic.BaseModel): | ||||||
| 		pass | # 		pass | ||||||
| 
 | # | ||||||
| 	message: Annotated[ | # 	message: Annotated[ | ||||||
| 		message_t, | # 		message_t, | ||||||
| 		pydantic.Field( | # 		pydantic.Field( | ||||||
| 			default_factory=message_t, | # 			default_factory=message_t, | ||||||
| 		) | # 		) | ||||||
| 	] | # 	] | ||||||
| 
 | # | ||||||
| Action = pydantic.RootModel[ | # Action = pydantic.RootModel[ | ||||||
| 	AssetsAction | SubscribeAction | # 	AssetsAction | SubscribeAction | ||||||
| ] | # ] | ||||||
| 
 | # | ||||||
| class AssetHistoryResponse(pydantic.BaseModel): | # class AssetHistoryResponse(pydantic.BaseModel): | ||||||
| 	action: Literal['asset_history'] = 'asset_history' | # 	action: Literal['asset_history'] = 'asset_history' | ||||||
| 
 | # | ||||||
| 	class message_t(pydantic.BaseModel): | # 	class message_t(pydantic.BaseModel): | ||||||
| 		class point_t(pydantic.BaseModel): | # 		class point_t(pydantic.BaseModel): | ||||||
| 			asset_name : Annotated[ | # 			asset_name : Annotated[ | ||||||
| 				str, | # 				str, | ||||||
| 				pydantic.Field( | # 				pydantic.Field( | ||||||
| 					alias='assetName', | # 					alias='assetName', | ||||||
| 				) | # 				) | ||||||
| 			] | # 			] | ||||||
| 			time: int | # 			time: int | ||||||
| 			asset_id : Annotated[ | # 			asset_id : Annotated[ | ||||||
| 				int, | # 				int, | ||||||
| 				pydantic.Field(alias='assetId') | # 				pydantic.Field(alias='assetId') | ||||||
| 			] | # 			] | ||||||
| 			value: decimal.Decimal | # 			value: decimal.Decimal | ||||||
| 
 | # | ||||||
| 		points: list[point_t] | # 		points: list[point_t] | ||||||
| 	message: message_t | # 	message: message_t | ||||||
| 
 | # | ||||||
| class AssetTickerResponse(pydantic.BaseModel): | # class AssetTickerResponse(pydantic.BaseModel): | ||||||
| 	action: Literal['point'] = 'point' | # 	action: Literal['point'] = 'point' | ||||||
| 
 | # | ||||||
| 	message: 'AssetHistoryResponse.message_t.point_t' | # 	message: 'AssetHistoryResponse.message_t.point_t' | ||||||
| 
 | # | ||||||
| class AssetsResponse(pydantic.BaseModel): | # class AssetsResponse(pydantic.BaseModel): | ||||||
| 	action: Literal['assets'] = 'assets' | # 	action: Literal['assets'] = 'assets' | ||||||
| 
 | # | ||||||
| 	class message_t(pydantic.BaseModel): | # 	class message_t(pydantic.BaseModel): | ||||||
| 		class asset_t(pydantic.BaseModel): | # 		class asset_t(pydantic.BaseModel): | ||||||
| 			id: int | # 			id: int | ||||||
| 			name: str | # 			name: str | ||||||
| 
 | # | ||||||
| 		assets: list[asset_t] | # 		assets: list[asset_t] | ||||||
| 	message: message_t | # 	message: message_t | ||||||
|  | # | ||||||
|  | |||||||
							
								
								
									
										126
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/websocket_api.py
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										126
									
								
								deps/test-task-2025-07-17-v2/python/online/fxreader/pr34/test_task_2025_07_17_v2/async_api/websocket_api.py
									
									
									
									
										vendored
									
									
								
							| @ -1,126 +0,0 @@ | |||||||
| import fastapi |  | ||||||
| import datetime |  | ||||||
| from sqlalchemy.ext.asyncio import AsyncSession |  | ||||||
| from sqlalchemy.ext.asyncio import async_sessionmaker |  | ||||||
| from . import schema |  | ||||||
| from ..tickers.logic import tickers_get_by_period, markets_all |  | ||||||
| 
 |  | ||||||
| from typing import (Optional, Literal) |  | ||||||
| 
 |  | ||||||
| class WebsocketAPI: |  | ||||||
| 	def __init__( |  | ||||||
| 		self, |  | ||||||
| 		session: 'async_sessionmaker[AsyncSession]', |  | ||||||
| 	) -> None: |  | ||||||
| 		self.connections : set[ |  | ||||||
| 			fastapi.WebSocket, |  | ||||||
| 		] = set() |  | ||||||
| 		self.subscriptions_by_asset_id : dict[ |  | ||||||
| 			int, set[fastapi.WebSocket] |  | ||||||
| 		] = dict() |  | ||||||
| 		self.subscriptions_by_client : dict[ |  | ||||||
| 			fastapi.WebSocket, |  | ||||||
| 			int, |  | ||||||
| 		] = dict() |  | ||||||
| 		self.session = session |  | ||||||
| 
 |  | ||||||
| 	async def connect(self, client: fastapi.WebSocket) -> None: |  | ||||||
| 		assert not client in self.connections |  | ||||||
| 
 |  | ||||||
| 		await client.accept() |  | ||||||
| 
 |  | ||||||
| 		self.connections.add(client) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	async def subscribe( |  | ||||||
| 		self, |  | ||||||
| 		client: fastapi.WebSocket, |  | ||||||
| 		asset_id: int |  | ||||||
| 	) -> None: |  | ||||||
| 		if client in self.subscriptions_by_client: |  | ||||||
| 			last_asset_id = self.subscriptions_by_client[client] |  | ||||||
| 			del self.subscriptions_by_asset_id[last_asset_id] |  | ||||||
| 			del self.subscriptions_by_client[client] |  | ||||||
| 
 |  | ||||||
| 		if not asset_id in self.subscriptions_by_asset_id: |  | ||||||
| 			self.subscriptions_by_asset_id[asset_id] = set() |  | ||||||
| 
 |  | ||||||
| 		self.subscriptions_by_asset_id[asset_id].add(client) |  | ||||||
| 		self.subscriptions_by_client[client] = asset_id |  | ||||||
| 
 |  | ||||||
| 		await self.asset_last_period(client, asset_id) |  | ||||||
| 
 |  | ||||||
| 	async def asset_last_period( |  | ||||||
| 		self, |  | ||||||
| 		client: fastapi.WebSocket, |  | ||||||
| 		asset_id: int, |  | ||||||
| 	) -> None: |  | ||||||
| 		tickers = await tickers_get_by_period( |  | ||||||
| 			self.session, |  | ||||||
| 			period=datetime.timedelta(minutes=30), |  | ||||||
| 			market_id=asset_id, |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 		await client.send_text( |  | ||||||
| 			schema.AssetHistoryResponse( |  | ||||||
| 				message=schema.AssetHistoryResponse.message_t( |  | ||||||
| 					points=[ |  | ||||||
| 						schema.AssetHistoryResponse.message_t.point_t.model_construct( |  | ||||||
| 							asset_name=o.market.name, |  | ||||||
| 							asset_id=o.market.id, |  | ||||||
| 							time=int(o.timestamp.timestamp()), |  | ||||||
| 							value=o.value, |  | ||||||
| 						) |  | ||||||
| 						for o in tickers |  | ||||||
| 					] |  | ||||||
| 				) |  | ||||||
| 			).json(by_alias=True,), |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 	async def assets_index( |  | ||||||
| 		self, |  | ||||||
| 		client: fastapi.WebSocket, |  | ||||||
| 	)	-> None: |  | ||||||
| 		markets = await markets_all( |  | ||||||
| 			self.session, |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 		await client.send_text( |  | ||||||
| 			schema.AssetsResponse( |  | ||||||
| 				message=schema.AssetsResponse.message_t( |  | ||||||
| 					assets=[ |  | ||||||
| 						schema.AssetsResponse.message_t.asset_t.model_construct( |  | ||||||
| 							name=o.name, |  | ||||||
| 							id=o.id, |  | ||||||
| 						) |  | ||||||
| 						for o in markets |  | ||||||
| 					] |  | ||||||
| 				) |  | ||||||
| 			).json(by_alias=True,), |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 	async def on_message( |  | ||||||
| 		self, |  | ||||||
| 		client: fastapi.WebSocket, |  | ||||||
| 		msg_raw: str |  | ||||||
| 	) -> None: |  | ||||||
| 		msg = schema.Action.model_validate_json( |  | ||||||
| 			msg_raw |  | ||||||
| 		).root |  | ||||||
| 
 |  | ||||||
| 		if isinstance(msg, schema.SubscribeAction): |  | ||||||
| 			await self.subscribe( |  | ||||||
| 				client, |  | ||||||
| 				msg.message.asset_id |  | ||||||
| 			) |  | ||||||
| 		elif isinstance(msg, schema.AssetsAction): |  | ||||||
| 			await self.assets_index( |  | ||||||
| 				client, |  | ||||||
| 			) |  | ||||||
| 		else: |  | ||||||
| 			raise NotImplementedError |  | ||||||
| 
 |  | ||||||
| 	async def disconnect(self, client: fastapi.WebSocket) -> None: |  | ||||||
| 		assert client in self.connections |  | ||||||
| 
 |  | ||||||
| 		self.connections.remove(client) |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user