[+] 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 | ||||
| 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 .db import create_engine | ||||
| from .websocket_api import WebsocketAPI | ||||
| # from .websocket_api import WebsocketAPI | ||||
| 
 | ||||
| from typing import (Any, Optional, Literal, Annotated,) | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| async def websocket_tickers( | ||||
| 	websocket: fastapi.WebSocket, | ||||
| 	websocket_api: WebsocketAPI, | ||||
| ) -> None: | ||||
| 	try: | ||||
| 		await websocket_api.connect(websocket) | ||||
| 
 | ||||
| 		while True: | ||||
| 			msg = await websocket.receive_text() | ||||
| 			await websocket_api.on_message(websocket, msg) | ||||
| 	except fastapi.WebSocketDisconnect: | ||||
| 		pass | ||||
| 		# websocket_api.disconnect(websocket) | ||||
| 	except: | ||||
| 		logger.exception('') | ||||
| 		raise | ||||
| 	finally: | ||||
| 		await websocket_api.disconnect(websocket) | ||||
| # async def websocket_tickers( | ||||
| # 	websocket: fastapi.WebSocket, | ||||
| # 	websocket_api: WebsocketAPI, | ||||
| # ) -> None: | ||||
| # 	try: | ||||
| # 		await websocket_api.connect(websocket) | ||||
| # | ||||
| # 		while True: | ||||
| # 			msg = await websocket.receive_text() | ||||
| # 			await websocket_api.on_message(websocket, msg) | ||||
| # 	except fastapi.WebSocketDisconnect: | ||||
| # 		pass | ||||
| # 		# websocket_api.disconnect(websocket) | ||||
| # 	except: | ||||
| # 		logger.exception('') | ||||
| # 		raise | ||||
| # 	finally: | ||||
| # 		await websocket_api.disconnect(websocket) | ||||
| 
 | ||||
| def create_app() -> fastapi.FastAPI: | ||||
| 	async_session = create_engine() | ||||
| 
 | ||||
| 	websocket_api = WebsocketAPI( | ||||
| 		session=async_session, | ||||
| 	) | ||||
| 	# websocket_api = WebsocketAPI( | ||||
| 	# 	session=async_session, | ||||
| 	# ) | ||||
| 
 | ||||
| 	app = fastapi.FastAPI() | ||||
| 
 | ||||
| 	app.websocket( | ||||
| 		'/tickers/', | ||||
| 	)( | ||||
| 		functools.partial( | ||||
| 			websocket_tickers, | ||||
| 			websocket_api=fastapi.Depends(lambda : websocket_api), | ||||
| 		) | ||||
| 	) | ||||
| 	# app.websocket( | ||||
| 	# 	'/tickers/', | ||||
| 	# )( | ||||
| 	# 	functools.partial( | ||||
| 	# 		websocket_tickers, | ||||
| 	# 		websocket_api=fastapi.Depends(lambda : websocket_api), | ||||
| 	# 	) | ||||
| 	# ) | ||||
| 
 | ||||
| 	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,) | ||||
| 
 | ||||
| class SubscribeAction(pydantic.BaseModel): | ||||
| 	action: Literal['subscribe'] | ||||
| 	class message_t(pydantic.BaseModel): | ||||
| 		asset_id: Annotated[ | ||||
| 			int, | ||||
| 			pydantic.Field(alias='assetId') | ||||
| 		] | ||||
| 
 | ||||
| 	message: message_t | ||||
| 
 | ||||
| class AssetsAction(pydantic.BaseModel): | ||||
| 	action: Literal['assets'] | ||||
| 	class message_t(pydantic.BaseModel): | ||||
| 		pass | ||||
| 
 | ||||
| 	message: Annotated[ | ||||
| 		message_t, | ||||
| 		pydantic.Field( | ||||
| 			default_factory=message_t, | ||||
| 		) | ||||
| 	] | ||||
| 
 | ||||
| Action = pydantic.RootModel[ | ||||
| 	AssetsAction | SubscribeAction | ||||
| ] | ||||
| 
 | ||||
| class AssetHistoryResponse(pydantic.BaseModel): | ||||
| 	action: Literal['asset_history'] = 'asset_history' | ||||
| 
 | ||||
| 	class message_t(pydantic.BaseModel): | ||||
| 		class point_t(pydantic.BaseModel): | ||||
| 			asset_name : Annotated[ | ||||
| 				str, | ||||
| 				pydantic.Field( | ||||
| 					alias='assetName', | ||||
| 				) | ||||
| 			] | ||||
| 			time: int | ||||
| 			asset_id : Annotated[ | ||||
| 				int, | ||||
| 				pydantic.Field(alias='assetId') | ||||
| 			] | ||||
| 			value: decimal.Decimal | ||||
| 
 | ||||
| 		points: list[point_t] | ||||
| 	message: message_t | ||||
| 
 | ||||
| class AssetTickerResponse(pydantic.BaseModel): | ||||
| 	action: Literal['point'] = 'point' | ||||
| 
 | ||||
| 	message: 'AssetHistoryResponse.message_t.point_t' | ||||
| 
 | ||||
| class AssetsResponse(pydantic.BaseModel): | ||||
| 	action: Literal['assets'] = 'assets' | ||||
| 
 | ||||
| 	class message_t(pydantic.BaseModel): | ||||
| 		class asset_t(pydantic.BaseModel): | ||||
| 			id: int | ||||
| 			name: str | ||||
| 
 | ||||
| 		assets: list[asset_t] | ||||
| 	message: message_t | ||||
| # class SubscribeAction(pydantic.BaseModel): | ||||
| # 	action: Literal['subscribe'] | ||||
| # 	class message_t(pydantic.BaseModel): | ||||
| # 		asset_id: Annotated[ | ||||
| # 			int, | ||||
| # 			pydantic.Field(alias='assetId') | ||||
| # 		] | ||||
| # | ||||
| # 	message: message_t | ||||
| # | ||||
| # class AssetsAction(pydantic.BaseModel): | ||||
| # 	action: Literal['assets'] | ||||
| # 	class message_t(pydantic.BaseModel): | ||||
| # 		pass | ||||
| # | ||||
| # 	message: Annotated[ | ||||
| # 		message_t, | ||||
| # 		pydantic.Field( | ||||
| # 			default_factory=message_t, | ||||
| # 		) | ||||
| # 	] | ||||
| # | ||||
| # Action = pydantic.RootModel[ | ||||
| # 	AssetsAction | SubscribeAction | ||||
| # ] | ||||
| # | ||||
| # class AssetHistoryResponse(pydantic.BaseModel): | ||||
| # 	action: Literal['asset_history'] = 'asset_history' | ||||
| # | ||||
| # 	class message_t(pydantic.BaseModel): | ||||
| # 		class point_t(pydantic.BaseModel): | ||||
| # 			asset_name : Annotated[ | ||||
| # 				str, | ||||
| # 				pydantic.Field( | ||||
| # 					alias='assetName', | ||||
| # 				) | ||||
| # 			] | ||||
| # 			time: int | ||||
| # 			asset_id : Annotated[ | ||||
| # 				int, | ||||
| # 				pydantic.Field(alias='assetId') | ||||
| # 			] | ||||
| # 			value: decimal.Decimal | ||||
| # | ||||
| # 		points: list[point_t] | ||||
| # 	message: message_t | ||||
| # | ||||
| # class AssetTickerResponse(pydantic.BaseModel): | ||||
| # 	action: Literal['point'] = 'point' | ||||
| # | ||||
| # 	message: 'AssetHistoryResponse.message_t.point_t' | ||||
| # | ||||
| # class AssetsResponse(pydantic.BaseModel): | ||||
| # 	action: Literal['assets'] = 'assets' | ||||
| # | ||||
| # 	class message_t(pydantic.BaseModel): | ||||
| # 		class asset_t(pydantic.BaseModel): | ||||
| # 			id: int | ||||
| # 			name: str | ||||
| # | ||||
| # 		assets: list[asset_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