blob: 31a547cd71aefedb085c2ef565b6b51b161d7b34 [file]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Programmatic table generation utilities to eliminate duplication.
This module provides utilities to generate reverse mappings and derived tables
from the primary forward mapping tables, ensuring single source of truth and
reducing maintenance overhead.
"""
from __future__ import annotations
from typing import Any
from functools import cache
from hrw4u.states import SectionType
class TableGenerator:
"""Generates derived tables and reverse mappings from primary tables."""
def __init__(self) -> None:
pass
@staticmethod
def _clean_tag(tag: str) -> str:
"""Extract clean tag name from %{TAG:payload} format."""
return tag.strip().removeprefix('%{').removesuffix('}').split(':')[0]
def generate_reverse_condition_map(self, condition_map: tuple[tuple[str, Any], ...]) -> dict[str, str]:
"""Generate reverse condition mapping from forward condition map."""
reverse_map = {}
for ident_key, params in condition_map:
if not ident_key.endswith('.'):
tag = params.target if params else None
if tag:
clean_tag = self._clean_tag(tag)
reverse_map[clean_tag] = ident_key
return reverse_map
def generate_reverse_function_map(self, function_map: tuple[tuple[str, Any], ...]) -> dict[str, str]:
"""Generate reverse function mapping from forward function map."""
return {params.target: func_name for func_name, params in function_map}
@cache
def generate_section_hook_mapping(self) -> dict[str, str]:
"""Generate section name to hook name mapping."""
return {section.value: section.hook_name for section in SectionType}
@cache
def generate_hook_section_mapping(self) -> dict[str, str]:
"""Generate hook name to section name mapping."""
return {section.hook_name: section.value for section in SectionType}
def generate_ip_mapping(self) -> dict[str, str]:
"""Generate IP payload to identifier mapping from CONDITION_MAP."""
from hrw4u.tables import CONDITION_MAP
ip_mapping = {}
for condition_key, params in CONDITION_MAP.items():
tag = params.target if params else None
reverse_info = params.rev if params else None
if reverse_info and reverse_info.get("reverse_tag") == "IP":
payload = reverse_info.get("reverse_payload")
if payload:
ip_mapping[payload] = condition_key
return ip_mapping
def generate_status_target_mapping(self) -> dict[frozenset[SectionType], str]:
"""Generate status target mappings based on section restrictions."""
return {
frozenset({SectionType.REMAP, SectionType.SEND_RESPONSE}): "inbound.status",
frozenset({SectionType.PRE_REMAP, SectionType.READ_REQUEST, SectionType.SEND_REQUEST,
SectionType.READ_RESPONSE}): "outbound.status"
}
def generate_context_mappings(self) -> dict[str, dict[SectionType | frozenset[SectionType], str]]:
"""Generate context type mappings for headers, URLs, etc."""
return {
"HEADER_CONTEXT_MAP":
{
SectionType.REMAP: "inbound.req.",
frozenset({SectionType.PRE_REMAP, SectionType.READ_REQUEST, SectionType.SEND_REQUEST}): "outbound.req.",
SectionType.READ_RESPONSE: "outbound.resp."
},
"URL_CONTEXT_MAP":
{
SectionType.REMAP: "inbound.url.",
frozenset({SectionType.PRE_REMAP, SectionType.READ_REQUEST, SectionType.SEND_REQUEST}): "outbound.url."
}
}
def generate_ambiguous_tag_resolution(self) -> dict[str, dict[str, Any]]:
"""Generate ambiguous tag resolution mappings."""
return {
"STATUS":
{
"outbound_sections":
frozenset(
{SectionType.PRE_REMAP, SectionType.READ_REQUEST, SectionType.SEND_REQUEST, SectionType.READ_RESPONSE}),
"outbound_result": "outbound.status",
"inbound_result": "inbound.status"
},
"METHOD":
{
"outbound_sections": frozenset({SectionType.SEND_REQUEST}),
"outbound_result": "outbound.method",
"inbound_result": "inbound.method"
}
}
def generate_complete_reverse_resolution_map(self) -> dict[str, Any]:
"""Generate the complete reverse resolution map.
Combines all individual mapping generators into a single structure.
"""
reverse_map = {}
# Add IP mappings
reverse_map["IP"] = self.generate_ip_mapping()
# Add ambiguous tag resolution
ambiguous_mappings = self.generate_ambiguous_tag_resolution()
for tag, mapping in ambiguous_mappings.items():
reverse_map[tag] = mapping
# Add status target mappings
reverse_map["STATUS_TARGETS"] = self.generate_status_target_mapping()
# Add context mappings
context_mappings = self.generate_context_mappings()
for name, mapping in context_mappings.items():
reverse_map[name] = mapping
# Add context type mappings
from hrw4u.tables import CONTEXT_TYPE_MAP, FALLBACK_TAG_MAP
reverse_map["CONTEXT_TYPE_MAP"] = CONTEXT_TYPE_MAP.copy()
# Add fallback tag mappings
reverse_map["FALLBACK_TAG_MAP"] = FALLBACK_TAG_MAP.copy()
return reverse_map
# Singleton instance for global use
_table_generator = TableGenerator()
def get_reverse_condition_map(condition_map: dict[str, tuple]) -> dict[str, str]:
"""Get reverse condition mapping."""
return _table_generator.generate_reverse_condition_map(tuple(condition_map.items()))
def get_reverse_function_map(function_map: dict[str, Any]) -> dict[str, str]:
"""Get reverse function mapping."""
return _table_generator.generate_reverse_function_map(tuple(function_map.items()))
def get_section_mappings() -> tuple[dict[str, str], dict[str, str]]:
"""Get both section->hook and hook->section mappings."""
return (_table_generator.generate_section_hook_mapping(), _table_generator.generate_hook_section_mapping())
def get_complete_reverse_resolution_map() -> dict[str, Any]:
"""Get the complete generated reverse resolution map."""
return _table_generator.generate_complete_reverse_resolution_map()