Skip to content

Commit

Permalink
removed attrs
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienPensart committed Mar 6, 2024
1 parent af23667 commit f7edd2c
Show file tree
Hide file tree
Showing 16 changed files with 1,306 additions and 1,127 deletions.
336 changes: 240 additions & 96 deletions edgeproxy/Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion edgeproxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"

[dependencies]
tokio = { version = "1", features = ["macros"] }
salvo = { version = "0.63", features = ["proxy", "logging", "cache", "serve-static", "basic-auth"] }
salvo = { version = "0.65", features = ["proxy", "logging", "cache", "serve-static", "basic-auth"] }
serde_json = "1.0"
tracing = "0.1"
tracing-subscriber = "0.3"
Expand Down
3 changes: 3 additions & 0 deletions edgeproxy/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use salvo::basic_auth::{BasicAuth, BasicAuthValidator};
use salvo::prelude::*;
use tracing::{info, instrument};

pub struct Validator {
username: String,
Expand All @@ -13,7 +14,9 @@ impl BasicAuthValidator for Validator {
}
}

#[instrument]
pub fn create_basic_auth_handler(username: &str, password: &str) -> BasicAuth<Validator> {
info!("registered");
let validator = Validator {
username: username.into(),
password: password.into(),
Expand Down
14 changes: 9 additions & 5 deletions edgeproxy/src/edgify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use salvo::http::Method;
// use salvo::logging::Logger;
use salvo::prelude::*;
use std::time::Duration;
use tracing::{debug, info, warn};

#[derive(Debug)]
pub struct Edgify {
path: String,
query: String,
Expand All @@ -21,6 +23,7 @@ impl Edgify {
cache_duration,
}
}

pub fn router(self) -> Router {
let mut router = Router::with_path(self.path.clone());
if let Some(cache_duration) = self.cache_duration {
Expand All @@ -30,6 +33,7 @@ impl Edgify {
);
router = router.hoop(cache);
};
info!("{self:?} registered");
// router.hoop(self).hoop(Logger::new())
router.hoop(self)
}
Expand All @@ -44,7 +48,7 @@ impl Handler for Edgify {
res: &mut Response,
ctrl: &mut FlowCtrl,
) {
eprintln!("incoming request: {:?}", req);
debug!("incoming request: {:?}", req);
let query = self.query.clone();
*req.method_mut() = Method::POST;
*req.body_mut() = query.into();
Expand All @@ -53,9 +57,9 @@ impl Handler for Edgify {
req.headers_mut()
.insert(CONTENT_LENGTH, HeaderValue::from(self.query.len()));

eprintln!("outgoing request: {:?}", req);
debug!("outgoing request: {:?}", req);
ctrl.call_next(req, depot, res).await;
eprintln!("incoming response: {:?}", res);
debug!("incoming response: {:?}", res);

if self.cache_duration.is_some() {
match res.take_body() {
Expand All @@ -65,10 +69,10 @@ impl Handler for Edgify {
res.replace_body(salvo::http::ResBody::Once(body.to_bytes()));
}
_ => {
println!("Unknown body");
warn!("{req:?} has uncachable body");
}
}
}
eprintln!("outgoing response: {:?}", res);
debug!("outgoing response: {:?}", res);
}
}
3 changes: 2 additions & 1 deletion edgeproxy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ async fn start() -> Result<(), crate::errors::EdgeProxyError> {

let mut routes = vec![artists.router().get(proxy), index];
let edgeproxy = router.append(&mut routes);
let service = Service::new(edgeproxy).catcher(Catcher::default());
let catcher = Catcher::default();
let service = Service::new(edgeproxy).catcher(catcher);
let acceptor = TcpListener::new(opts.bind).bind().await;
Server::new(acceptor).serve(service).await;
Ok(())
Expand Down
6 changes: 5 additions & 1 deletion edgeproxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ use hyper_tls::HttpsConnector;
use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::client::legacy::Client as HyperUtilClient;
use salvo::proxy::{HyperClient, Proxy};
use std::fmt::Debug;
use tracing::{info, instrument};

#[instrument]
pub fn create_proxy<U>(
upstreams: U,
insecure: bool,
) -> Result<Proxy<U, HyperClient>, EdgeProxyError>
where
U: salvo::proxy::Upstreams,
U: salvo::proxy::Upstreams + Debug,
{
info!("registered");
if !insecure {
return Ok(Proxy::default_hyper_client(upstreams));
}
Expand Down
6 changes: 3 additions & 3 deletions linting.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set -e
sh code-format.sh

echo "linting : ruff..."
poetry run ruff musicbot tests
poetry run ruff check musicbot tests

echo "linting : pylint..."
poetry run pylint musicbot tests
Expand All @@ -18,8 +18,8 @@ poetry run flake8 musicbot tests
echo "static type checking : mypy..."
poetry run mypy musicbot tests

echo "static type checking : pyright..."
poetry run pyright
# echo "static type checking : pyright..."
# poetry run pyright

# echo "security checks : bandit..."
# poetry run bandit -r musicbot
Expand Down
17 changes: 9 additions & 8 deletions musicbot/cli/music_filter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from dataclasses import fields, replace

import click
from attr import fields
from beartype.typing import Any
from click_option_group import optgroup
from click_skeleton import add_options
Expand All @@ -12,8 +12,8 @@

logger = logging.getLogger(__name__)

FIELDS_NAMES = [field.name for field in fields(MusicFilter)]
JOINED_FIELDS_NAMES = ",".join(FIELDS_NAMES) # pylint: disable=not-an-iterable
NAME_TO_FIELD = {field.name: field for field in fields(MusicFilter)}
JOINED_FIELDS_NAMES = ",".join(NAME_TO_FIELD.keys()) # pylint: disable=not-an-iterable
FILTERS_REPRS = """\b
""" + "\n".join(
[f"{k}: {v.help_repr()}" for k, v in DEFAULT_PREFILTERS.items()]
Expand All @@ -38,7 +38,7 @@ def sane_music_filters(ctx: click.Context, param: click.Parameter, value: Any) -
raise click.Abort()

for val in value:
properties = {}
mf = MusicFilter()
for comma_separated in mysplit(val, ","):
if "=" not in comma_separated:
MusicbotObject.err('Error with a property, there is no "=" between key and value (<key>=<value>)')
Expand All @@ -47,16 +47,17 @@ def sane_music_filters(ctx: click.Context, param: click.Parameter, value: Any) -
if len(split_val) != 2:
MusicbotObject.err(f"Error with a property, splitted value should be of length 2 : {split_val}")
raise click.Abort()

property_key = split_val[0]
property_value = split_val[1]
property_value: str | int | float = split_val[1]

if property_key not in FIELDS_NAMES:
field = NAME_TO_FIELD.get(property_key, None)
if field is None:
MusicbotObject.err(f"Error : unknown property {property_key} for value {property_value}")
raise click.Abort()

properties[property_key] = property_value
mf = replace(mf, **{field.name: field.type(property_value)})

mf = MusicFilter(**properties)
and_filters.append(mf)

if not and_filters:
Expand Down
4 changes: 2 additions & 2 deletions musicbot/commands/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ async def custom_playlists(

for pike_keyword in pike_keywords:
MusicbotObject.success(f"Generating pike playlists for keyword {pike_keyword}")
for rating in [4, 4.5, 5]:
for rating in [4.0, 4.5, 5.0]:
MusicbotObject.success(f"Generating playlist for {pike_keyword}_{rating}")
pike_music_filter = MusicFilter(
artist="Buckethead",
Expand All @@ -410,7 +410,7 @@ async def custom_playlists(
out=out,
)

for rating in [4, 4.5, 5]:
for rating in [4.0, 4.5, 5.0]:
MusicbotObject.success(f"Generating playlist rating for Pikes {rating}")
rating_music_filter = MusicFilter(
artist="Buckethead",
Expand Down
10 changes: 5 additions & 5 deletions musicbot/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,8 @@ def to_mp3(self, destination: Path, flat: bool = False) -> Self | None:
self.err("unable to load existing mp3 file")
return None

mp3_file.track = self.track
if self.track is not None:
mp3_file.track = self.track
mp3_file.album = self.album
mp3_file.title = self.title
mp3_file.artist = self.artist
Expand Down Expand Up @@ -450,10 +451,9 @@ def to_mp3(self, destination: Path, flat: bool = False) -> Self | None:
self.err("unable to load freshly converted mp3 file")
return None

mp3_file.track = self.track

# rewrite some metadatas
mp3_file.track = self.track
if self.track is not None:
mp3_file.track = self.track
mp3_file.album = self.album
mp3_file.title = self.title
mp3_file.genre = self.genre
Expand All @@ -469,7 +469,7 @@ def to_mp3(self, destination: Path, flat: bool = False) -> Self | None:

async def shazam(self) -> Any:
shazam = Shazam()
return await shazam.recognize_song(self.path)
return await shazam.recognize(self.path)

def fingerprint(self, api_key: str) -> str | None:
try:
Expand Down
61 changes: 26 additions & 35 deletions musicbot/music_filter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from dataclasses import asdict, dataclass, fields

from attr import asdict, define, field, fields
from beartype.typing import Any
from beartype import beartype

from musicbot.defaults import (
DEFAULT_LIMIT,
Expand All @@ -19,48 +19,39 @@
logger = logging.getLogger(__name__)


@define(frozen=True)
@beartype
@dataclass(frozen=True)
class MusicFilter(MusicbotObject):
genre: str = field(default=MATCH_ALL)
keyword: str = field(default=MATCH_ALL)
artist: str = field(default=MATCH_ALL)
title: str = field(default=MATCH_ALL)
album: str = field(default=MATCH_ALL)
pattern: str = field(default="")

min_size = field(converter=int, default=DEFAULT_MIN_SIZE)
max_size = field(converter=int, default=DEFAULT_MAX_SIZE)
min_length = field(converter=int, default=DEFAULT_MIN_LENGTH)
max_length = field(converter=int, default=DEFAULT_MAX_LENGTH)
min_rating = field(converter=float, default=DEFAULT_MIN_RATING)
max_rating = field(converter=float, default=DEFAULT_MAX_RATING)
limit = field(converter=int, default=DEFAULT_LIMIT)

@min_rating.validator
def _check_min_rating(self, attribute: Any, value: float) -> None: # pylint: disable=unused-argument
"""min rating validator"""
if value not in RATING_CHOICES:
genre: str = MATCH_ALL
keyword: str = MATCH_ALL
artist: str = MATCH_ALL
title: str = MATCH_ALL
album: str = MATCH_ALL
pattern: str = ""

min_size: int = DEFAULT_MIN_SIZE
max_size: int = DEFAULT_MAX_SIZE
min_length: int = DEFAULT_MIN_LENGTH
max_length: int = DEFAULT_MAX_LENGTH
min_rating: float = DEFAULT_MIN_RATING
max_rating: float = DEFAULT_MAX_RATING
limit: int = DEFAULT_LIMIT

def __post_init__(self) -> None:
"""Check values"""
if self.min_rating not in RATING_CHOICES:
raise ValueError(f"Invalid minimum rating {self.min_rating}, it should be one of {RATING_CHOICES}")

@max_rating.validator
def _check_max_rating(self, attribute: Any, value: float) -> None: # pylint: disable=unused-argument
"""max rating validator"""
if value not in RATING_CHOICES:
if self.max_rating not in RATING_CHOICES:
raise ValueError(f"Invalid maximum rating {self.max_rating}, it should be one of {RATING_CHOICES}")

if self.min_rating > value:
if self.min_rating > self.max_rating:
raise ValueError(f"Invalid minimum ({self.min_rating}) or maximum ({self.max_rating}) rating")

@max_length.validator
def _check_max_length(self, attribute: Any, value: int) -> None: # pylint: disable=unused-argument
"""max length validator"""
if self.min_length > value:
if self.min_length > self.max_length:
raise ValueError(f"Invalid minimum ({self.min_length}) or maximum ({self.max_length}) length")

@max_size.validator
def _check_max_size(self, attribute: Any, value: int) -> None: # pylint: disable=unused-argument
"""max size validator"""
if self.min_size > value:
if self.min_size > self.max_size:
raise ValueError(f"Invalid minimum ({self.min_size}) or maximum ({self.max_size}) size")

def _short_repr(self) -> dict[str, str]:
Expand Down
5 changes: 2 additions & 3 deletions musicbot/musicdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import edgedb
import httpx
from async_lru import alru_cache
from attr import asdict as attr_asdict
from beartype import beartype
from beartype.typing import Any, Self
from edgedb.asyncio_client import AsyncIOClient, create_async_client
Expand Down Expand Up @@ -124,7 +123,7 @@ async def make_playlist(
for music_filter in music_filters:
intermediate_results: list[GenPlaylistResult] = await gen_playlist(
self.client,
**attr_asdict(music_filter),
**asdict(music_filter),
)
results.update(intermediate_results)
name = " | ".join([music_filter.help_repr() for music_filter in music_filters])
Expand Down Expand Up @@ -210,7 +209,7 @@ async def make_bests(
for music_filter in music_filters:
intermediate_result: GenBestsResult = await gen_bests(
self.client,
**attr_asdict(music_filter),
**asdict(music_filter),
)
results.append(intermediate_result)

Expand Down
24 changes: 15 additions & 9 deletions musicbot/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import traceback
from collections.abc import Callable, Collection, Iterable, Sequence
from datetime import datetime
from functools import lru_cache
from pathlib import Path
from typing import IO, Any, NoReturn, ParamSpec, TypeVar

Expand All @@ -19,7 +20,8 @@
import orjson
import rich
from beartype import beartype
from methodtools import lru_cache

# from methodtools import lru_cache
from progressbar import NullBar, ProgressBar

# from requests.structures import CaseInsensitiveDict
Expand Down Expand Up @@ -53,6 +55,17 @@ def default_encoder(data: Any) -> Any:
T = TypeVar("T")


@lru_cache(maxsize=None)
def _public_ip(timeout: int = 5) -> str | None:
try:
response = httpx.head("https://www.wikipedia.org", timeout=timeout)
logger.info(response.headers)
return response.headers["X-Client-IP"]
except Exception as error:
MusicbotObject.err("Unable to detect Public IP", error=error)
return None


@beartype
class MusicbotObject:
print_lock = threading.Lock()
Expand All @@ -71,16 +84,9 @@ class MusicbotObject:
def __repr__(self) -> str:
return "[DRY]" if self.dry else "[DOING]"

@lru_cache()
@staticmethod
def public_ip(timeout: int = 5) -> str | None:
try:
response = httpx.head("https://www.wikipedia.org", timeout=timeout)
logger.info(response.headers)
return response.headers["X-Client-IP"]
except Exception as error:
MusicbotObject.err("Unable to detect Public IP", error=error)
return None
return _public_ip(timeout=timeout)

@staticmethod
def is_dev() -> bool:
Expand Down
Loading

0 comments on commit f7edd2c

Please sign in to comment.