Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(db): store sessions in the database #182

Merged
merged 2 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/gallia/command/uds.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,7 @@ def implicit_logging(self, value: bool) -> None:
self._apply_implicit_logging_setting()

def _apply_implicit_logging_setting(self) -> None:
if self._implicit_logging:
self.ecu.db_handler = self.db_handler
else:
self.ecu.db_handler = None
self.ecu.implicit_logging = self._implicit_logging

async def setup(self, args: Namespace) -> None:
await super().setup(args)
Expand All @@ -132,6 +129,8 @@ async def setup(self, args: Namespace) -> None:
power_supply=self.power_supply,
)

self.ecu.db_handler = self.db_handler

if self.db_handler is not None:
try:
# No idea, but str(args.target) fails with a strange traceback.
Expand Down
16 changes: 13 additions & 3 deletions src/gallia/commands/scan/uds/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async def set_session_with_hooks_handling(
self, session: int, use_hooks: bool
) -> NegativeResponse | DiagnosticSessionControlResponse:
resp = await self.ecu.set_session(
session, config=UDSRequestConfig(skip_hooks=True)
session, config=UDSRequestConfig(skip_hooks=True), use_db=False
)

if (
Expand All @@ -78,7 +78,7 @@ async def set_session_with_hooks_handling(
return resp

resp_ = await self.ecu.set_session(
session, config=UDSRequestConfig(skip_hooks=False)
session, config=UDSRequestConfig(skip_hooks=False), use_db=False
)

if isinstance(resp, NegativeResponse):
Expand Down Expand Up @@ -168,7 +168,7 @@ async def main(self, args: Namespace) -> None:
await self.ecu.reconnect()

try:
resp = await self.ecu.set_session(0x01)
resp = await self.ecu.set_session(0x01, use_db=False)
if isinstance(resp, NegativeResponse):
self.logger.error(
f"Could not change to default session: {resp}"
Expand Down Expand Up @@ -240,6 +240,11 @@ async def main(self, args: Namespace) -> None:
previous_session = session
self.logger.result(f"* Session {g_repr(session)} ")

if self.db_handler is not None:
await self.db_handler.insert_session_transition(
session, res["stack"]
)

self.logger.result(
f"\tvia stack: {'->'.join([f'{g_repr(i)}' for i in res['stack']])}"
)
Expand All @@ -260,6 +265,11 @@ async def main(self, args: Namespace) -> None:
previous_session = session
self.logger.result(f"* Session {g_repr(session)} ")

if self.db_handler is not None:
await self.db_handler.insert_session_transition(
session, res["stack"]
)

self.logger.result(
f"\tvia stack: {'->'.join([f'{g_repr(i)}' for i in res['stack']])} "
f"(NRC: {res['error']})"
Expand Down
57 changes: 56 additions & 1 deletion src/gallia/db/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ def bytes_repr(data: bytes) -> str:
exception text
);
CREATE INDEX IF NOT EXISTS ix_scan_result_request_pdu ON scan_result(request_pdu);
CREATE TABLE IF NOT EXISTS session_transition (
run int not null references scan_run(id) on update cascade on delete cascade,
destination int not null,
steps json check(json_valid(steps))
);

CREATE VIEW IF NOT EXISTS run_stats AS
SELECT
Expand Down Expand Up @@ -130,6 +135,7 @@ def __init__(self, database: Path):
self.path = database
self.connection: aiosqlite.Connection | None = None
self.scan_run: int | None = None
self.target: str | None = None
self.discovery_run: int | None = None
self.meta: int | None = None
self.logger = get_logger("db")
Expand Down Expand Up @@ -234,6 +240,7 @@ async def insert_scan_run(self, target: str) -> None:
cursor = await self.connection.execute(query, (target, self.meta))

self.scan_run = cursor.lastrowid
self.target = target
await self.connection.commit()

async def insert_scan_run_properties_pre(
Expand Down Expand Up @@ -364,7 +371,7 @@ async def insert_scan_result(
)

async def execute() -> None:
assert self.connection is not None
assert self.connection is not None, "Not connected to the database"

done = False

Expand All @@ -381,3 +388,51 @@ async def execute() -> None:
await self.connection.commit()

self.tasks.append(asyncio.create_task(execute()))

async def insert_session_transition(
self, destination: int, steps: list[int]
) -> None:
assert self.connection is not None, "Not connected to the database"

query = "INSERT INTO session_transition VALUES(?, ?, ?)"
parameters = (self.scan_run, destination, json.dumps(steps))
await self.connection.execute(query, parameters)

async def get_sessions(self) -> list[int]:
assert self.connection is not None, "Not connected to the database"
assert self.target is not None, "Scan run not yet created, target unknown"

query = (
"SELECT DISTINCT destination "
"FROM session_transition st, "
" scan_run sr, "
" address ad "
"WHERE st.run = sr.id AND sr.address = ad.id "
"AND ad.url = ?"
)
parameters = (self.target,)

cursor: aiosqlite.Cursor = await self.connection.execute(query, parameters)
return list(x[0] for x in await cursor.fetchall())

async def get_session_transition(self, destination: int) -> list[int] | None:
assert self.connection is not None, "Not connected to the database"
assert self.target is not None, "Scan run not yet created, target unknown"

query = (
"SELECT steps "
"FROM session_transition st, "
" scan_run sr, "
" address ad "
"WHERE st.run = sr.id AND sr.address = ad.id "
"AND st.destination = ? AND ad.url = ?"
)
parameters = (destination, self.target)
cursor: aiosqlite.Cursor = await self.connection.execute(query, parameters)
row = await cursor.fetchone()

if row is None:
return None

result: list[int] = json.loads(row[0])
return result
24 changes: 23 additions & 1 deletion src/gallia/services/uds/ecu.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def __init__(
self.power_supply = power_supply
self.state = ECUState()
self.db_handler: DBHandler | None = None
self.implicit_logging = True

async def connect(self) -> None:
...
Expand Down Expand Up @@ -264,6 +265,7 @@ async def set_session(
self,
level: int,
config: UDSRequestConfig | None = None,
use_db: bool = True,
) -> service.NegativeResponse | service.DiagnosticSessionControlResponse:
config = config if config is not None else UDSRequestConfig()

Expand All @@ -272,6 +274,26 @@ async def set_session(

resp = await self.diagnostic_session_control(level, config=config)

if (
isinstance(resp, service.NegativeResponse)
and self.db_handler is not None
and use_db
):
self.logger.debug(
"Could not switch to session. Trying with database transitions ..."
)

if self.db_handler is not None:
steps = await self.db_handler.get_session_transition(level)

self.logger.debug(f"Found the following steps in database: {steps}")

if steps is not None:
for step in steps:
await self.set_session(step, use_db=False)

resp = await self.diagnostic_session_control(level, config=config)

if not isinstance(resp, service.NegativeResponse) and not config.skip_hooks:
await self.set_session_post(level, config=config)

Expand Down Expand Up @@ -483,7 +505,7 @@ async def _request(
raise
finally:
try:
if self.db_handler is not None:
if self.implicit_logging and self.db_handler is not None:
mode = LogMode.implicit

if (
Expand Down