Skip to content

Commit

Permalink
Merge pull request #20 from Otoru/users/vitoru/new-changes
Browse files Browse the repository at this point in the history
🧑‍💻 (python) Change python version and logging format
  • Loading branch information
Otoru authored Aug 13, 2024
2 parents 694bd47 + 3461d28 commit ae3826a
Show file tree
Hide file tree
Showing 11 changed files with 440 additions and 394 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ jobs:
strategy:
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
steps:
- uses: actions/checkout@v2

Expand Down
6 changes: 4 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ At first, it is necessary to make it very clear where our library is supported

| Python Version | Supported |
| -------------- | ------------------ |
| 3.12.x | :white_check_mark: |
| 3.11.x | :white_check_mark: |
| 3.10.x | :white_check_mark: |
| 3.9.x | :white_check_mark: |
| 3.8.x | :white_check_mark: |
| 3.9.x | :warning: |
| 3.8.x | :warning: |
| 3.7.x | :warning: |

## Reporting a Vulnerability
Expand Down
15 changes: 8 additions & 7 deletions genesis/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
---------------
Simple abstraction used to put some syntactic sugar into freeswitch event consumption.
"""

from typing import Awaitable, NoReturn, Callable
import functools
import logging
import asyncio
import re

from .inbound import Inbound
from genesis.inbound import Inbound
from genesis.logger import logger


def filtrate(key: str, value: str = None, regex: bool = False):
Expand Down Expand Up @@ -86,28 +87,28 @@ async def wrapper(*args, **kwargs):

async def wait(self) -> Awaitable[NoReturn]:
while bool(self.protocol.is_connected):
logging.debug("Wait to recive new events...")
logger.debug("Wait to recive new events...")
await asyncio.sleep(1)

async def start(self) -> Awaitable[NoReturn]:
"""Method called to request the freeswitch to start sending us the appropriate events."""
try:
async with self.protocol as protocol:
logging.debug("Asking freeswitch to send us all events.")
logger.debug("Asking freeswitch to send us all events.")
await protocol.send("events plain ALL")

for event in protocol.handlers.keys():
logging.debug(
logger.debug(
f"Requesting freeswitch to filter events of type '{event}'."
)

if event.isupper():
logging.debug(
logger.debug(
f"Send command to filtrate events with name: '{event}'."
)
await protocol.send(f"filter Event-Name {event}")
else:
logging.debug(
logger.debug(
f"Send command to filtrate events with subclass: '{event}'."
)
await protocol.send(f"filter Event-Subclass {event}")
Expand Down
11 changes: 5 additions & 6 deletions genesis/inbound.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
---------------
ESL implementation used for incoming connections on freeswitch.
"""

from __future__ import annotations

from asyncio import open_connection, TimeoutError, wait_for
from typing import Awaitable
import logging

from genesis.exceptions import ConnectionTimeoutError, AuthenticationError
from genesis.protocol import Protocol
from genesis.logger import logger


class Inbound(Protocol):
Expand Down Expand Up @@ -48,11 +49,11 @@ async def __aexit__(self, *args, **kwargs) -> Awaitable[None]:
async def authenticate(self) -> Awaitable[None]:
"""Authenticates to the freeswitch server. Raises an exception on failure."""
await self.authentication_event.wait()
logging.debug("Send command to authenticate inbound ESL connection.")
logger.debug("Send command to authenticate inbound ESL connection.")
response = await self.send(f"auth {self.password}")

if response["Reply-Text"] != "+OK accepted":
logging.debug("Freeswitch said the passed password is incorrect.")
logger.debug("Freeswitch said the passed password is incorrect.")
raise AuthenticationError("Invalid password")

async def start(self) -> Awaitable[None]:
Expand All @@ -61,9 +62,7 @@ async def start(self) -> Awaitable[None]:
promise = open_connection(self.host, self.port)
self.reader, self.writer = await wait_for(promise, self.timeout)
except TimeoutError:
logging.debug(
"A timeout occurred when trying to connect to the freeswitch."
)
logger.debug("A timeout occurred when trying to connect to the freeswitch.")
raise ConnectionTimeoutError()

await super().start()
Expand Down
17 changes: 17 additions & 0 deletions genesis/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import logging

from rich.logging import RichHandler

logger = logging.getLogger("genesis")

handler = RichHandler(
show_time=False,
rich_tracebacks=True,
tracebacks_show_locals=True,
markup=True,
show_path=False,
)

handler.setFormatter(logging.Formatter("%(message)s"))
logger.setLevel(logging.DEBUG)
logger.propagate = False
47 changes: 24 additions & 23 deletions genesis/outbound.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
ESL implementation used for outgoing connections on freeswitch.
"""

from __future__ import annotations

from asyncio import StreamReader, StreamWriter, Queue, start_server, Event, sleep
from typing import Awaitable, NoReturn, Optional
from functools import partial
import logging
import socket

from genesis.protocol import Protocol
from genesis.inbound import Inbound
from genesis.parser import ESLEvent
from genesis.logger import logger


class Session(Protocol):
Expand Down Expand Up @@ -52,14 +53,14 @@ async def _awaitable_complete_command(self, application: str) -> Event:
semaphore = Event()

async def handler(session: Session, event: ESLEvent):
logging.debug(f"Recived channel execute complete event: {event}")
logger.debug(f"Recived channel execute complete event: {event}")

if "variable_current_application" in event:
if event["variable_current_application"] == application:
await session.fifo.put(event)
semaphore.set()

logging.debug(f"Register event handler to {application} complete event")
logger.debug(f"Register event handler to {application} complete event")
self.on("CHANNEL_EXECUTE_COMPLETE", partial(handler, self))

return semaphore
Expand All @@ -76,7 +77,7 @@ async def sendmsg(
if lock:
cmd += f"\nevent-lock: true"

logging.debug(f"Send command to freeswitch: '{cmd}'.")
logger.debug(f"Send command to freeswitch: '{cmd}'.")
return await self.send(cmd)

async def answer(self) -> Awaitable[ESLEvent]:
Expand All @@ -96,11 +97,11 @@ async def playback(self, path: str, block=True) -> Awaitable[ESLEvent]:
if not block:
return await self.sendmsg("execute", "playback", path)

logging.debug("Send playback command to freeswitch with block behavior.")
logger.debug("Send playback command to freeswitch with block behavior.")
command_is_complete = await self._awaitable_complete_command("playback")
response = await self.sendmsg("execute", "playback", path)

logging.debug("Await playback complete event...")
logger.debug("Await playback complete event...")
await command_is_complete.wait()

return response
Expand All @@ -120,21 +121,21 @@ async def say(
module += f":{lang}"

arguments = f"{module} {kind} {method} {gender} {text}"
logging.debug(f"Arguments used in say command: {arguments}")
logger.debug(f"Arguments used in say command: {arguments}")

if not block:
return await self.sendmsg("execute", "say", arguments)

logging.debug("Send say command to freeswitch with block behavior.")
logger.debug("Send say command to freeswitch with block behavior.")
command_is_complete = await self._awaitable_complete_command("say")
response = await self.sendmsg("execute", "say", arguments)
logging.debug(f"Response of say command: {response}")
logger.debug(f"Response of say command: {response}")

logging.debug("Await say complete event...")
logger.debug("Await say complete event...")
await command_is_complete.wait()

event = await self.fifo.get()
logging.debug(f"Execute complete event recived: {event}")
logger.debug(f"Execute complete event recived: {event}")

return event

Expand All @@ -153,7 +154,7 @@ async def play_and_get_digits(
digit_timeout: Optional[int] = None,
transfer_on_failure: Optional[str] = None,
) -> Awaitable[ESLEvent]:
formatter = lambda value: "" if value is None else value
formatter = lambda value: "" if value is None else str(value)
ordered_arguments = [
minimal,
maximum,
Expand All @@ -169,25 +170,25 @@ async def play_and_get_digits(
]
formated_ordered_arguments = map(formatter, ordered_arguments)
arguments = " ".join(formated_ordered_arguments)
logging.debug(f"Arguments used in play_and_get_digits command: {arguments}")
logger.debug(f"Arguments used in play_and_get_digits command: {arguments}")

if not block:
return await self.sendmsg("execute", "play_and_get_digits", arguments)

logging.debug(
logger.debug(
"Send play_and_get_digits command to freeswitch with block behavior."
)
command_is_complete = await self._awaitable_complete_command(
"play_and_get_digits"
)
response = await self.sendmsg("execute", "play_and_get_digits", arguments)
logging.debug(f"Response of play_and_get_digits command: {response}")
logger.debug(f"Response of play_and_get_digits command: {response}")

logging.debug("Await play_and_get_digits complete event...")
logger.debug("Await play_and_get_digits complete event...")
await command_is_complete.wait()

event = await self.fifo.get()
logging.debug(f"Execute complete event recived: {event}")
logger.debug(f"Execute complete event recived: {event}")

return event

Expand Down Expand Up @@ -234,13 +235,13 @@ async def start(self) -> Awaitable[NoReturn]:
handler, self.host, self.port, family=socket.AF_INET
)
address = f"{self.host}:{self.port}"
logging.debug(f"Start application server and listen on '{address}'.")
logger.debug(f"Start application server and listen on '{address}'.")
await self.server.serve_forever()

async def stop(self) -> Awaitable[None]:
"""Terminate the application server."""
if self.server:
logging.debug("Shutdown application server.")
logger.debug("Shutdown application server.")
self.server.close()
await self.server.wait_closed()

Expand All @@ -250,17 +251,17 @@ async def handler(
) -> Awaitable[None]:
"""Method used to process new connections."""
async with Session(reader, writer) as session:
logging.debug("Send command to start handle a call")
logger.debug("Send command to start handle a call")
session.context = await session.send("connect")

if server.myevents:
logging.debug("Send command to recive all call events")
logger.debug("Send command to recive all call events")
await session.send("myevents")

if server.linger:
logging.debug("Send linger command to freeswitch")
logger.debug("Send linger command to freeswitch")
await session.send("linger")
session.is_lingering = True

logging.debug("Start server session handler")
logger.debug("Start server session handler")
await server.app(session)
Loading

0 comments on commit ae3826a

Please sign in to comment.