Skip to content

Commit

Permalink
Merge pull request #12 from NeonGeckoCom/dev
Browse files Browse the repository at this point in the history
GitHub Automation, Minor Bugfixes
  • Loading branch information
NeonDaniel authored Aug 18, 2021
2 parents 8c400e7 + 70b94cf commit d1c4fff
Show file tree
Hide file tree
Showing 15 changed files with 310 additions and 28 deletions.
59 changes: 59 additions & 0 deletions .github/workflows/publish_docker_container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# This workflow will generate a release distribution and upload it to PyPI

name: Publish Docker Image
on:
push:
branches:
- master
workflow_run:
workflows:
- "Publish Alpha Build"
types:
- completed
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build_and_publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Get Version
id: version
run: |
VERSION=$(sed "s/a/-a./" <<< $(python setup.py --version))
echo ::set-output name=version::${VERSION}
env:
image_name: ${{ env.IMAGE_NAME }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v2
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ steps.version.outputs.version }}
type=ref,event=branch
- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
40 changes: 40 additions & 0 deletions .github/workflows/publish_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This workflow will generate a release distribution and upload it to PyPI

name: Publish Build and GitHub Release
on:
push:
branches:
- master

jobs:
tag_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get Version
run: |
VERSION=$(python setup.py --version)
echo "VERSION=${VERSION}" >> $GITHUB_ENV
- uses: ncipollo/release-action@v1
with:
token: ${{secrets.GITHUB_TOKEN}}
tag: ${{env.VERSION}}
build_and_publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.8
- name: Install Build Tools
run: |
python -m pip install build wheel
- name: Build Distribution Packages
run: |
python setup.py bdist_wheel
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{secrets.PYPI_TOKEN}}
40 changes: 40 additions & 0 deletions .github/workflows/publish_test_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This workflow will generate a distribution and upload it to PyPI

name: Publish Alpha Build
on:
push:
branches:
- dev
paths-ignore:
- 'version.py'
workflow_dispatch:

jobs:
build_and_publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.8
- name: Install Build Tools
run: |
python -m pip install build wheel
- name: Increment Version
run: |
VER=$(python setup.py --version)
python version_bump.py
- name: Push Version Change
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Increment Version
- name: Build Distribution Packages
run: |
python setup.py bdist_wheel
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{secrets.PYPI_TOKEN}}
21 changes: 21 additions & 0 deletions .github/workflows/pull_master.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# This workflow will generate a PR for changes in cert into master

name: Pull to Master
on:
push:
branches:
- dev
workflow_dispatch:

jobs:
pull_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: pull-request-action
uses: repo-sync/pull-request@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
pr_reviewer: 'neonreviewers'
pr_assignee: 'neondaniel'
pr_draft: true
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM python:3.8

ADD . /neon_api_proxy
WORKDIR /neon_api_proxy
RUN apt-get update && \
apt-get install -y \
gcc \
python3 \
python3-dev \
&& pip install wheel \
&& pip install .

WORKDIR /config

ENV NEON_API_PROXY_CONFIG_PATH /config/config.json
ENV NEON_MQ_PROXY_CONFIG_PATH /config/config.json

CMD ["neon_api_proxy"]
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ Responses will be returned as dictionaries. Responses should contain the followi
- `content` - Usually contains the HTTP content (bytes) from the requested API, but may include a string message for errors.
- `encoding` = Usually contains the HTTP content encoding if content is the byte representation of a string, may be `None`
## Docker Configuration
When running this as a docker container, the path to configuration files should be mounted to `/config`.
For example, if your configuration resides in `~/.config`:
```commandline
docker run -v /home/$USER/.config:/config neon_api_proxy
```
2 changes: 1 addition & 1 deletion neon_api_proxy/alpha_vantage_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def handle_query(self, **kwargs) -> dict:
:return: dict containing stock data from URL response
"""
symbol = kwargs.get('symbol')
company = kwargs.get('company')
company = kwargs.get('company', kwargs.get('keywords'))
search_term = symbol or company
if not search_term:
return {"status_code": -1,
Expand Down
46 changes: 27 additions & 19 deletions neon_api_proxy/api_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ def __init__(self, config: dict, service_name: str, proxy: NeonAPIProxyControlle

self.vhost = '/neon_api'
self.proxy = proxy
self.consumers = dict(neon_api_consumer=ConsumerThread(connection=self.create_mq_connection(vhost=self.vhost),
queue='neon_api_input',
callback_func=self.handle_api_input))

def handle_api_input(self,
channel: pika.channel.Channel,
Expand All @@ -56,25 +53,36 @@ def handle_api_input(self,
:param method: MQ return method (pika.spec.Basic.Return)
:param properties: MQ properties (pika.spec.BasicProperties)
:param body: request body (bytes)
"""
if body and isinstance(body, bytes):
request = b64_to_dict(body)
LOG.debug(f"request={request}")
respond = self.proxy.resolve_query(request)
LOG.debug(f"respond={respond}")
data = dict_to_b64(respond)
message_id = None
try:
if body and isinstance(body, bytes):
request = b64_to_dict(body)
message_id = request.get("message_id")
respond = self.proxy.resolve_query(request)
LOG.debug(f"message={message_id} status={respond.get('status_code')}")
data = dict_to_b64(respond)

# queue declare is idempotent, just making sure queue exists
channel.queue_declare(queue='neon_api_output')

# queue declare is idempotent, just making sure queue exists
channel.queue_declare(queue='neon_api_output')
channel.basic_publish(exchange='',
routing_key='neon_api_output',
body=data,
properties=pika.BasicProperties(expiration='1000')
)
else:
raise TypeError(f'Invalid body received, expected: bytes string; got: {type(body)}')
except Exception as e:
LOG.error(f"message_id={message_id}")
LOG.error(e)

channel.basic_publish(exchange='',
routing_key='neon_api_output',
body=data,
properties=pika.BasicProperties(expiration='1000')
)
else:
raise TypeError(f'Invalid body received, expected: bytes string; got: {type(body)}')
def handle_error(self, thread, exception):
LOG.error(exception)
LOG.info(f"Restarting Consumers")
self.stop_consumers()
self.run()

def run(self):
self.register_consumer("neon_api_consumer", self.vhost, 'neon_api_input', self.handle_api_input)
self.run_consumers()
6 changes: 3 additions & 3 deletions neon_api_proxy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def get_proxy_config() -> dict:
if path.isfile(path.expanduser(config_path)):
valid_config_path = path.expanduser(config_path)
elif path.isfile(path.expanduser("~/.config/neon/credentials.json")):
valid_config_path = path.expanduser("~/.local/share/neon/credentials.json")
valid_config_path = path.expanduser("~/.config/neon/credentials.json")
elif path.isfile(path.expanduser("~/.local/share/neon/credentials.json")):
valid_config_path = path.expanduser("~/.local/share/neon/credentials.json")
else:
Expand All @@ -48,8 +48,8 @@ def get_mq_config() -> dict:
Locates a valid MQ config for MQ Authentication
:return: dict containing "MQ" key with server and users configurations
"""
if path.isfile("config.json"):
valid_config_path = "config.json"
if path.isfile(environ.get('NEON_MQ_CONFIG_PATH', 'config.json')):
valid_config_path = environ.get('NEON_API_PROXY_CONFIG_PATH', 'config.json')
elif path.isfile(path.expanduser("~/.config/neon/mq_config.json")):
valid_config_path = path.expanduser("~/.config/neon/mq_config.json")
elif path.isfile(path.expanduser("~/.local/share/neon/mq_config.json")):
Expand Down
4 changes: 3 additions & 1 deletion neon_api_proxy/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from neon_api_proxy.owm_api import OpenWeatherAPI
from neon_api_proxy.alpha_vantage_api import AlphaVantageAPI
from neon_api_proxy.wolfram_api import WolframAPI
from neon_api_proxy.test_api import TestAPI


class NeonAPIProxyController:
Expand All @@ -15,7 +16,8 @@ class NeonAPIProxyController:
service_class_mapping = {
'wolfram_alpha': WolframAPI,
'alpha_vantage': AlphaVantageAPI,
'open_weather_map': OpenWeatherAPI
'open_weather_map': OpenWeatherAPI,
'api_test_endpoint': TestAPI
}

def __init__(self, config: dict = None):
Expand Down
4 changes: 2 additions & 2 deletions neon_api_proxy/owm_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from requests import Response

from neon_api_proxy.cached_api import CachedAPI
from neon_utils.log_utils import LOG
from neon_utils.logger import LOG
from neon_utils.authentication_utils import find_neon_owm_key


Expand All @@ -45,7 +45,7 @@ def handle_query(self, **kwargs) -> dict:
:return: dict containing `status_code`, `content`, `encoding` from URL response
"""
lat = kwargs.get("lat")
lng = kwargs.get("lng")
lng = kwargs.get("lng", kwargs.get("lon"))
units = "metric" if kwargs.get("units") == "metric" else "imperial"

if not all((lat, lng, units)):
Expand Down
43 changes: 43 additions & 0 deletions neon_api_proxy/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# NEON AI (TM) SOFTWARE, Software Development Kit & Application Development System
#
# Copyright 2008-2021 Neongecko.com Inc. | All Rights Reserved
#
# Notice of License - Duplicating this Notice of License near the start of any file containing
# a derivative of this software is a condition of license for this software.
# Friendly Licensing:
# No charge, open source royalty free use of the Neon AI software source and object is offered for
# educational users, noncommercial enthusiasts, Public Benefit Corporations (and LLCs) and
# Social Purpose Corporations (and LLCs). Developers can contact [email protected]
# For commercial licensing, distribution of derivative works or redistribution please contact [email protected]
# Distributed on an "AS IS” basis without warranties or conditions of any kind, either express or implied.
# Trademarks of Neongecko: Neon AI(TM), Neon Assist (TM), Neon Communicator(TM), Klat(TM)
# Authors: Guy Daniels, Daniel McKnight, Regina Bloomstine, Elon Gasper, Richard Leeds
#
# Specialized conversational reconveyance options from Conversation Processing Intelligence Corp.
# US Patents 2008-2021: US7424516, US20140161250, US20140177813, US8638908, US8068604, US8553852, US10530923, US10530924
# China Patent: CN102017585 - Europe Patent: EU2156652 - Patents Pending

import urllib.parse

from enum import Enum
from neon_utils.log_utils import LOG
from neon_utils.authentication_utils import find_neon_wolfram_key
from neon_api_proxy.cached_api import CachedAPI


class TestAPI(CachedAPI):
"""
API for querying Wolfram|Alpha.
"""

def __init__(self, api_key: str = None):
super().__init__("Test")

def handle_query(self, **kwargs) -> dict:
"""
Handles an incoming query and provides a response
:return: dict containing `status_code`, `content`, `encoding` from URL response
"""
return {"status_code": 200,
"content": "Success",
"encoding": None}
2 changes: 1 addition & 1 deletion requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
requests-cache==0.6.4
requests~=2.25
neon_utils>=0.6.1a6
neon_mq_connector @ git+https://github.com/neongeckocom/neon_mq_connector
neon_mq_connector>=0.0.4
2 changes: 1 addition & 1 deletion version.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
# US Patents 2008-2021: US7424516, US20140161250, US20140177813, US8638908, US8068604, US8553852, US10530923, US10530924
# China Patent: CN102017585 - Europe Patent: EU2156652 - Patents Pending

__version__ = "0.0.2"
__version__ = "0.1.0"
Loading

0 comments on commit d1c4fff

Please sign in to comment.