fixcore-engine 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {fixcore_engine-0.1.4/fixcore_engine.egg-info → fixcore_engine-0.1.6}/PKG-INFO +1 -1
  2. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/session/session.py +16 -0
  3. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/transport/initiator.py +17 -3
  4. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6/fixcore_engine.egg-info}/PKG-INFO +1 -1
  5. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/pyproject.toml +1 -1
  6. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/LICENSE +0 -0
  7. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/README.md +0 -0
  8. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/__init__.py +0 -0
  9. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/application.py +0 -0
  10. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/gui.py +0 -0
  11. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/gui_ui/app.js +0 -0
  12. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/gui_ui/fixcore_logo.svg +0 -0
  13. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/gui_ui/index.html +0 -0
  14. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/gui_ui/style.css +0 -0
  15. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/log/__init__.py +0 -0
  16. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/log/base.py +0 -0
  17. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/log/factory.py +0 -0
  18. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/log/file_log.py +0 -0
  19. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/log/screen.py +0 -0
  20. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/message/__init__.py +0 -0
  21. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/message/cracker.py +0 -0
  22. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/message/data_dictionary.py +0 -0
  23. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/message/exceptions.py +0 -0
  24. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/message/field.py +0 -0
  25. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/message/message.py +0 -0
  26. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/session/__init__.py +0 -0
  27. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/session/session_id.py +0 -0
  28. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/session/session_settings.py +0 -0
  29. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/session/state.py +0 -0
  30. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/store/__init__.py +0 -0
  31. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/store/base.py +0 -0
  32. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/store/factory.py +0 -0
  33. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/store/file_store.py +0 -0
  34. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/store/memory.py +0 -0
  35. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/transport/__init__.py +0 -0
  36. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/transport/acceptor.py +0 -0
  37. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore/transport/framer.py +0 -0
  38. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore_engine.egg-info/SOURCES.txt +0 -0
  39. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore_engine.egg-info/dependency_links.txt +0 -0
  40. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore_engine.egg-info/entry_points.txt +0 -0
  41. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore_engine.egg-info/requires.txt +0 -0
  42. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/fixcore_engine.egg-info/top_level.txt +0 -0
  43. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/setup.cfg +0 -0
  44. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_cracker.py +0 -0
  45. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_data_dictionary.py +0 -0
  46. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_file_log.py +0 -0
  47. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_file_store.py +0 -0
  48. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_framer.py +0 -0
  49. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_integration.py +0 -0
  50. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_message.py +0 -0
  51. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_session.py +0 -0
  52. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_session_id.py +0 -0
  53. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_store.py +0 -0
  54. {fixcore_engine-0.1.4 → fixcore_engine-0.1.6}/tests/test_transport.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixcore-engine
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Pure Python FIX protocol engine
5
5
  Author-email: Aidan Chisholm <aidan.chisholm@gmail.com>
6
6
  License: MIT License
@@ -3,10 +3,13 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import logging
6
7
  import time
7
8
  from datetime import datetime, timezone
8
9
  from typing import Awaitable, Callable
9
10
 
11
+ logger = logging.getLogger(__name__)
12
+
10
13
  from fixcore.application import Application
11
14
  from fixcore.log.base import Log
12
15
  from fixcore.message.message import Message
@@ -111,17 +114,22 @@ class Session:
111
114
 
112
115
  async def on_connect(self, send_fn: SendFn) -> None:
113
116
  """Called by transport when connection is established."""
117
+ logger.debug("[%s] on_connect: setting send_fn", self._id)
114
118
  self._send_fn = send_fn
115
119
  self._last_recv_time = time.monotonic()
116
120
 
117
121
  if self._reset_on_logon:
122
+ logger.debug("[%s] on_connect: resetting store", self._id)
118
123
  self._store.reset()
119
124
 
120
125
  self._state = SessionState.LOGON_TIMEOUT
126
+ logger.debug("[%s] on_connect: starting timer loop", self._id)
121
127
  self._heartbeat_task = asyncio.create_task(self._timer_loop())
122
128
 
123
129
  if self._is_initiator:
130
+ logger.debug("[%s] on_connect: sending Logon", self._id)
124
131
  await self._send_logon()
132
+ logger.debug("[%s] on_connect: Logon sent", self._id)
125
133
 
126
134
  async def on_disconnect(self) -> None:
127
135
  """Called by transport when connection is lost."""
@@ -304,13 +312,16 @@ class Session:
304
312
  # ------------------------------------------------------------------
305
313
 
306
314
  async def _send_logon(self) -> None:
315
+ logger.debug("[%s] _send_logon: building Logon message", self._id)
307
316
  msg = Message()
308
317
  msg.header.set(TAG_MSG_TYPE, MSG_LOGON)
309
318
  msg.set_field(TAG_ENCRYPT_METHOD, "0")
310
319
  msg.set_field(TAG_HEART_BT_INT, str(self._heartbt_int))
311
320
  self._app.to_admin(msg, self._id)
321
+ logger.debug("[%s] _send_logon: calling _send_message", self._id)
312
322
  await self._send_message(msg, is_admin=True)
313
323
  self._logon_sent_at = time.monotonic()
324
+ logger.debug("[%s] _send_logon: complete", self._id)
314
325
 
315
326
  async def _send_logout(self, text: str = "") -> None:
316
327
  msg = Message()
@@ -435,6 +446,7 @@ class Session:
435
446
  msg.header.set(TAG_SENDING_TIME, _utc_timestamp())
436
447
 
437
448
  raw = msg.encode()
449
+ logger.debug("[%s] _send_message: seq=%s len=%d", self._id, seq_num, len(raw))
438
450
  self._store.set(seq_num, raw)
439
451
  self._store.incr_next_sender_msg_seq_num()
440
452
  self._last_send_time = time.monotonic()
@@ -442,7 +454,11 @@ class Session:
442
454
  self._log.on_outgoing(raw.replace(b"\x01", b"|").decode("latin-1"))
443
455
 
444
456
  if self._send_fn is not None:
457
+ logger.debug("[%s] _send_message: calling send_fn", self._id)
445
458
  await self._send_fn(raw)
459
+ logger.debug("[%s] _send_message: send_fn returned", self._id)
460
+ else:
461
+ logger.warning("[%s] _send_message: send_fn is None — message not sent", self._id)
446
462
 
447
463
  # ------------------------------------------------------------------
448
464
  # Sequence number validation
@@ -3,8 +3,11 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import logging
6
7
 
7
8
  from fixcore.application import Application
9
+
10
+ logger = logging.getLogger(__name__)
8
11
  from fixcore.log.base import LogFactory
9
12
  from fixcore.session.session import Session
10
13
  from fixcore.session.session_id import SessionID
@@ -61,12 +64,14 @@ class SocketInitiator:
61
64
  """Launch a connect-loop task for each configured initiator session."""
62
65
  self._stop_event.clear()
63
66
  self._no_reconnect.clear()
67
+ logger.info("SocketInitiator starting %d session(s)", len(self._sessions))
64
68
  for sid, session in self._sessions.items():
65
69
  task = asyncio.create_task(
66
70
  self._connect_loop(sid, session),
67
71
  name=f"initiator-{sid}",
68
72
  )
69
73
  self._tasks.append(task)
74
+ logger.debug("Connect-loop task created for %s", sid)
70
75
 
71
76
  async def stop(self) -> None:
72
77
  """Signal all connect loops to exit and wait for them to finish."""
@@ -108,14 +113,17 @@ class SocketInitiator:
108
113
  port = int(self._settings.get(sid, "SocketConnectPort"))
109
114
  reconnect = self._settings.get_int(sid, "ReconnectInterval", 10)
110
115
 
116
+ logger.info("[%s] Connect loop started — target %s:%s", sid, host, port)
111
117
  while not self._stop_event.is_set():
118
+ logger.debug("[%s] Attempting connection to %s:%s", sid, host, port)
112
119
  try:
113
120
  reader, writer = await asyncio.open_connection(host, port)
114
- except OSError:
115
- # Connection refused or network error wait and retry
121
+ except OSError as exc:
122
+ logger.warning("[%s] Connection failed: %s retrying in %ss", sid, exc, reconnect)
116
123
  await self._interruptible_sleep(reconnect)
117
124
  continue
118
125
 
126
+ logger.info("[%s] TCP connected to %s:%s", sid, host, port)
119
127
  framer = MessageFramer()
120
128
 
121
129
  async def send_fn(data: bytes, _w: asyncio.StreamWriter = writer) -> None:
@@ -123,21 +131,26 @@ class SocketInitiator:
123
131
  await _w.drain()
124
132
 
125
133
  await session.on_connect(send_fn)
134
+ logger.debug("[%s] on_connect complete — Logon sent", sid)
126
135
 
127
136
  try:
128
137
  while not self._stop_event.is_set():
129
138
  try:
130
139
  data = await reader.read(4096)
131
140
  except (ConnectionResetError, asyncio.IncompleteReadError,
132
- asyncio.CancelledError):
141
+ asyncio.CancelledError) as exc:
142
+ logger.info("[%s] Read interrupted: %s", sid, type(exc).__name__)
133
143
  break
134
144
  if not data:
145
+ logger.info("[%s] Connection closed by peer", sid)
135
146
  break
136
147
 
148
+ logger.debug("[%s] Received %d bytes", sid, len(data))
137
149
  for raw_msg in framer.feed(data):
138
150
  await session.on_data(raw_msg)
139
151
 
140
152
  finally:
153
+ logger.info("[%s] Disconnecting", sid)
141
154
  await session.on_disconnect()
142
155
  try:
143
156
  writer.close()
@@ -147,6 +160,7 @@ class SocketInitiator:
147
160
  framer.reset()
148
161
 
149
162
  if not self._stop_event.is_set() and not self._no_reconnect.is_set():
163
+ logger.info("[%s] Waiting %ss before reconnect", sid, reconnect)
150
164
  await self._interruptible_sleep(reconnect)
151
165
 
152
166
  async def _interruptible_sleep(self, seconds: float) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixcore-engine
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Pure Python FIX protocol engine
5
5
  Author-email: Aidan Chisholm <aidan.chisholm@gmail.com>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fixcore-engine"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  description = "Pure Python FIX protocol engine"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
File without changes
File without changes
File without changes