Skip to content

Commit

Permalink
⏪ Use uvicorn instead guinicorn
Browse files Browse the repository at this point in the history
  • Loading branch information
lleans committed Mar 13, 2024
1 parent 6746d6c commit 4983769
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 61 deletions.
26 changes: 12 additions & 14 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@ on:
- fast-api

jobs:

docker:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ vars.DOCKERHUB_USERNAME }}/muslimpro-api:${{ vars.VERSION }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ vars.DOCKERHUB_USERNAME }}/muslimpro-api:${{ vars.VERSION }}
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ COPY . /app
WORKDIR /app
RUN pip3 install -Ur requirements.txt

CMD ["gunicorn" , "router:app", "-w 4", "-k uvicorn.workers.UvicornWorker"]
CMD python3 router.py
2 changes: 1 addition & 1 deletion MuslimProScrapper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .main import Search
from .model import Item, Response
from .const import CalculationMethod, AsrjuristicMethod
from .const import CalculationMethod, AsrjuristicMethod
4 changes: 3 additions & 1 deletion MuslimProScrapper/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# Indonesian Based
RAMADHAN_API_INDONESIA = "https://calendarific.com/holiday/indonesia/idul-fitri"


class CalculationMethod(Enum):
DEFAULT = "Precalc"
ALGERIAN_MINISTER_OF_RELIGIOUS_AND_WAKFS = "Algeria"
Expand All @@ -25,11 +26,12 @@ class CalculationMethod(Enum):
SHIA_ITHNA_ASHARI_JAFARI = "Jafari"
SIHAT_KEMENAG_KEMENTERIAN_AGAMA_RI = "KEMENAG"
TUNISIAN_MINISTRY_OF_RELIGIOUS_AFFAIRS = "Tunisia"
UAE_GENERAL_AUTHORITY_OF_ISLAMIC_AFFAIRS_AND_ENDOWMENTS = "AwqafUAE"
UAE_GENERAL_AUTHORITY_OF_ISLAMIC_AFFAIRS_AND_ENDOWMENTS = "AwqafUAE"
UMM_AL_QURA_MAKKAH = "Makkah"
UNIVERSITY_OF_TEHRAN = "Tehran"
FEDERATION_OF_ISLAMIC_ASSOCIATIONS_IN_BASQUE_COUNTRY = "BASQUE"


class AsrjuristicMethod(Enum):
STANDARD_SHAFI_MALIKI_HANBALI = "Standard"
HANAFI = "Hanafi"
7 changes: 0 additions & 7 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@ cssselect==1.2.0
fastapi==0.110.0
fastapi-cache2==0.2.1
frozenlist==1.4.1
gunicorn==21.2.0
h11==0.14.0
httptools==0.6.1
idna==3.6
lxml==5.1.0
multidict==6.0.5
packaging==24.0
pendulum==3.0.0
pydantic==2.6.4
pydantic_core==2.16.3
pyquery==2.0.0
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
PyYAML==6.0.1
redis==4.6.0
setuptools==68.2.2
six==1.16.0
Expand All @@ -32,7 +27,5 @@ time-machine==2.14.0
typing_extensions==4.10.0
tzdata==2024.1
uvicorn==0.28.0
watchfiles==0.21.0
websockets==12.0
wheel==0.41.2
yarl==1.9.4
98 changes: 63 additions & 35 deletions router.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from pydantic import BaseModel, Field

from fastapi import FastAPI, Request
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
from fastapi.encoders import jsonable_encoder
from fastapi.staticfiles import StaticFiles
Expand All @@ -21,13 +21,14 @@
from MuslimProScrapper import Search, Response as MuslimProResp
from MuslimProScrapper.const import AsrjuristicMethod, CalculationMethod


@asynccontextmanager
async def lifespan(_):
redis = aioredis.from_url(f"redis://:{environ.get('REDIS_PASS')}@redis")
redis = aioredis.from_url("redis://redis")
FastAPICache.init(RedisBackend(redis), prefix="muslimproapi-cache")
yield

app = FastAPI(title='MuslimPro_API', lifespan=lifespan)
app = FastAPI(title='MuslimPro API', lifespan=lifespan, version="2.0")
app.mount("/static", StaticFiles(directory="static"), name="static")


Expand All @@ -49,7 +50,7 @@ async def where_ip(session: ClientSession, ip_address: str) -> str:


class ModelResponse(BaseModel):
location: str = Field(default="Location not found!!")
location: str = Field(default="")
calculationMethod: str = Field(default="")
asrjuristicMethod: str = Field(default="")
praytimes: dict = Field(default=dict())
Expand All @@ -62,14 +63,29 @@ class BaseResponse(BaseModel):
data: ModelResponse = Field(default=ModelResponse())


@app.get('/favicon.ico')
class CustomException(Exception):

def __init__(self, status_code: int, message: str) -> None:
self.body: BaseResponse = BaseResponse()
self.body.status_code = status_code
self.body.message = message
self.body.data.location = ""


@app.get('/favicon.ico', response_class=FileResponse, include_in_schema=False)
def favicon() -> FileResponse:
return FileResponse("static/favicon.ico")


@app.get('/', response_model=None)
async def get_location_based(request: Request) -> RedirectResponse | JSONResponse:
resp: BaseResponse = BaseResponse()
@app.get('/', response_class=RedirectResponse, responses={
307: {'description': "Will redirect into your specific location path"}
})
async def get_location_based(request: Request) -> RedirectResponse:
"""
Root redirection based ip
By Looking up your ip adress location, this will redirect you into the specific path based your location
"""
try:
async with ClientSession() as session:
client_ip: str = request.client.host
Expand All @@ -79,28 +95,34 @@ async def get_location_based(request: Request) -> RedirectResponse | JSONRespons
return RedirectResponse(redirect_url)

except (IndexError, KeyError):
resp.status_code = 404
return JSONResponse(content=jsonable_encoder(resp), status_code=404)
raise CustomException(
status_code=404, message="Location was not found!!")
except:
resp.message = "Something went wrong"
resp.status_code = 500
resp.data.location = ""
return JSONResponse(content=jsonable_encoder(resp), status_code=500)
raise CustomException(
status_code=500, message="Something went wrong!?")


@app.get('/{query}', response_class=JSONResponse)
@app.get('/{query}', response_model=BaseResponse, responses={
200: {'description': "Will return the data, as the model", 'model': BaseResponse}
})
@cache(expire=86400)
async def main_app(query: str, calcMethod: str = "", asjurMethod: str = "") -> JSONResponse:
async def main_app(query: str, calcMethod: str = CalculationMethod.DEFAULT.name, asjurMethod: str = AsrjuristicMethod.STANDARD_SHAFI_MALIKI_HANBALI.name) -> JSONResponse:
"""
Main Appplication
- Query\n
:query -> Pass this your location, to lookup the data
- Parameters\n
:calcMethod[Optional] -> Put calculation method(read source code)\n
:asjurMethod[Optional] -> Put asrjuristic method(read source code)
"""
resp: BaseResponse = BaseResponse()
status: int = 200

par1, par2 = calcMethod.replace(
' ', '_').upper(), asjurMethod.replace(' ', '_').upper()
par1 = calcMethod.replace(' ', '_').upper()
par2 = asjurMethod.replace(' ', '_').upper()
calc = CalculationMethod[par1]
asjur = AsrjuristicMethod[par2]

calc = CalculationMethod[par1] if hasattr(
CalculationMethod, par1) else CalculationMethod.DEFAULT
asjur = AsrjuristicMethod[par2] if hasattr(
AsrjuristicMethod, par2) else AsrjuristicMethod.STANDARD_SHAFI_MALIKI_HANBALI
async with ClientSession() as session:
api = Search(session=session, calculation=calc,
asrjuristic=asjur)
Expand All @@ -114,7 +136,8 @@ async def main_app(query: str, calcMethod: str = "", asjurMethod: str = "") -> J
city_name: str = location.get('city_name', '')
country_name: str = location.get('country_name', '')

resp.data.location = f"{city_name.title()}, {country_name.title()}"
resp.data.location = f"{city_name.title()}, {
country_name.title()}"
resp.data.calculationMethod = data.calculationMethod
resp.data.asrjuristicMethod = data.asrjuristicMethod
for i in iter(data.raw):
Expand All @@ -128,20 +151,25 @@ async def main_app(query: str, calcMethod: str = "", asjurMethod: str = "") -> J
resp.data.ramadhan = "Currently only supported in Indonesia"

except (IndexError, KeyError):
status = 404
resp.status_code = status
raise CustomException(
status_code=404, message="Location was not found!!")
except:
status = 500
resp.message = "Something went wrong"
resp.status_code = status
resp.data.location = ""
raise CustomException(
status_code=500, message="Something went wrong!?")

return JSONResponse(content=jsonable_encoder(resp), status_code=status)
return JSONResponse(content=jsonable_encoder(resp))


@app.exception_handler(400)
@app.exception_handler(404)
async def docs(e):
return RedirectResponse('https://github.com/lleans/Muslim-Pro-Scrapper')
@app.exception_handler(500)
@app.exception_handler(422)
@app.exception_handler(400)
async def error_handling(_, exec: Exception) -> JSONResponse:
if isinstance(exec, CustomException):
return JSONResponse(content=jsonable_encoder(exec.body), status_code=exec.body.status_code)

return RedirectResponse(url='/docs')

uvicorn.run("router:app", port=int(environ.get('PORT')) or 8000, workers=4)
if __name__ == "__main__":
uvicorn.run("router:app", host="0.0.0.0",
port=int(environ.get('PORT')) or 8000, log_level="info", workers=3)
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import setuptools

requirements = [requirement.strip() for requirement in open('requirements.txt', 'r', encoding='utf-8').readlines()]
requirements = [requirement.strip() for requirement in open(
'requirements.txt', 'r', encoding='utf-8').readlines()]

with open("README.md", "r", encoding='utf-8') as fh:
long_description = fh.read()
Expand All @@ -21,4 +22,4 @@
"Operating System :: OS Independent",
], install_requires=requirements,
python_requires='>=3.10',
)
)

0 comments on commit 4983769

Please sign in to comment.