-
Notifications
You must be signed in to change notification settings - Fork 516
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into readme-local
- Loading branch information
Showing
21 changed files
with
1,018 additions
and
559 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1 @@ | ||
"""Entrypoint.""" | ||
|
||
import asyncio | ||
import functools | ||
import os | ||
import signal | ||
|
||
from aiohttp import ClientSession | ||
|
||
from .conductor import Conductor | ||
from .config.argparse import get_settings, parse_args | ||
from .config.default_context import DefaultContextBuilder | ||
from .config.logging import LoggingConfigurator | ||
from .postgres import load_postgres_plugin | ||
|
||
|
||
async def get_genesis_transactions(genesis_url: str): | ||
"""Get genesis transactions.""" | ||
headers = {} | ||
headers["Content-Type"] = "application/json" | ||
async with ClientSession() as client_session: | ||
response = await client_session.get(genesis_url, headers=headers) | ||
genesis_txns = await response.text() | ||
return genesis_txns | ||
|
||
|
||
async def start_app(conductor: Conductor): | ||
"""Start up.""" | ||
await conductor.setup() | ||
await conductor.start() | ||
|
||
|
||
async def shutdown_app(conductor: Conductor): | ||
"""Shut down.""" | ||
print("\nShutting down") | ||
await conductor.stop() | ||
tasks = [ | ||
task | ||
for task in asyncio.Task.all_tasks() | ||
if task is not asyncio.tasks.Task.current_task() | ||
] | ||
for task in tasks: | ||
task.cancel() | ||
await asyncio.gather(*tasks, return_exceptions=True) | ||
asyncio.get_event_loop().stop() | ||
|
||
|
||
def main(): | ||
"""Entrypoint.""" | ||
args = parse_args() | ||
settings = get_settings(args) | ||
|
||
# Set up logging | ||
log_config = settings.get("log.config") | ||
log_level = settings.get("log.level") or os.getenv("LOG_LEVEL") | ||
LoggingConfigurator.configure(log_config, log_level) | ||
|
||
# Fetch genesis transactions if necessary | ||
if not settings.get("ledger.genesis_transactions") and settings.get( | ||
"ledger.genesis_url" | ||
): | ||
loop = asyncio.get_event_loop() | ||
settings["ledger.genesis_transactions"] = loop.run_until_complete( | ||
get_genesis_transactions(settings["ledger.genesis_url"]) | ||
) | ||
|
||
# Load postgres plug-in if necessary | ||
if ( | ||
settings.get("wallet.type") | ||
and settings.get("wallet.storage_type") == "postgres_storage" | ||
): | ||
if args.wallet_storage_type == "postgres_storage": | ||
load_postgres_plugin() | ||
|
||
# Support WEBHOOK_URL environment variable | ||
webhook_url = os.environ.get("WEBHOOK_URL") | ||
if webhook_url: | ||
webhook_urls = list(settings.get("admin.webhook_urls") or []) | ||
webhook_urls.append(webhook_url) | ||
settings["admin.webhook_urls"] = webhook_urls | ||
|
||
# Create the Conductor instance | ||
context_builder = DefaultContextBuilder(settings) | ||
conductor = Conductor(context_builder) | ||
|
||
# Run the application | ||
loop = asyncio.get_event_loop() | ||
loop.add_signal_handler( | ||
signal.SIGTERM, | ||
functools.partial(asyncio.ensure_future, shutdown_app(conductor), loop=loop), | ||
) | ||
asyncio.ensure_future(start_app(conductor), loop=loop) | ||
|
||
try: | ||
loop.run_forever() | ||
except KeyboardInterrupt: | ||
loop.run_until_complete(shutdown_app(conductor)) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() # pragma: no cover | ||
"""Aries Cloud Agent.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
"""Commands module common setup.""" | ||
|
||
from importlib import import_module | ||
from typing import Sequence | ||
|
||
|
||
def available_commands(): | ||
"""Index available commands.""" | ||
return [ | ||
{"name": "help", "summary": "Print available commands"}, | ||
{"name": "provision", "summary": "Provision an agent"}, | ||
{"name": "start", "summary": "Start a new agent process"}, | ||
] | ||
|
||
|
||
def load_command(command: str): | ||
"""Load the module corresponding with a named command.""" | ||
module = None | ||
module_path = None | ||
for cmd in available_commands(): | ||
if cmd["name"] == command: | ||
module = cmd["name"] | ||
if "module" in cmd: | ||
module_path = cmd["module"] | ||
break | ||
if module and not module_path: | ||
module_path = f"{__package__}.{module}" | ||
if module_path: | ||
return import_module(module_path) | ||
|
||
|
||
def run_command(command: str, argv: Sequence[str] = None): | ||
"""Execute a named command with command line arguments.""" | ||
module = load_command(command) or load_command("help") | ||
module.execute(argv) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
"""Help command for indexing available commands.""" | ||
|
||
from argparse import ArgumentParser | ||
from typing import Sequence | ||
|
||
|
||
def execute(argv: Sequence[str] = None): | ||
"""Execute the help command.""" | ||
from . import available_commands, load_command | ||
|
||
parser = ArgumentParser() | ||
subparsers = parser.add_subparsers() | ||
for cmd in available_commands(): | ||
if cmd["name"] == "help": | ||
continue | ||
module = load_command(cmd["name"]) | ||
subparser = subparsers.add_parser(cmd["name"], help=cmd["summary"]) | ||
module.init_argument_parser(subparser) | ||
parser.print_help() | ||
|
||
|
||
if __name__ == "__main__": | ||
execute() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
"""Provision command for setting up agent settings before starting.""" | ||
|
||
import asyncio | ||
from argparse import ArgumentParser | ||
from typing import Sequence | ||
|
||
from ..config import argparse as arg | ||
from ..config.default_context import DefaultContextBuilder | ||
from ..config.util import common_config | ||
from ..error import BaseError | ||
from ..wallet.base import BaseWallet | ||
from ..wallet.crypto import seed_to_did | ||
|
||
|
||
class ProvisionError(BaseError): | ||
"""Base exception for provisioning errors.""" | ||
|
||
|
||
def init_argument_parser(parser: ArgumentParser): | ||
"""Initialize an argument parser with the module's arguments.""" | ||
return arg.load_argument_groups( | ||
parser, *arg.group.get_registered(arg.CAT_PROVISION) | ||
) | ||
|
||
|
||
async def provision(category: str, settings: dict): | ||
"""Perform provisioning.""" | ||
context_builder = DefaultContextBuilder(settings) | ||
context = await context_builder.build() | ||
|
||
if category == "wallet": | ||
# Initialize wallet | ||
wallet: BaseWallet = await context.inject(BaseWallet) | ||
if wallet.type != "indy": | ||
raise ProvisionError("Cannot provision a non-Indy wallet type") | ||
if wallet.created: | ||
print("Created new wallet") | ||
else: | ||
print("Opened existing wallet") | ||
print("Wallet type:", wallet.type) | ||
print("Wallet name:", wallet.name) | ||
wallet_seed = context.settings.get("wallet.seed") | ||
public_did_info = await wallet.get_public_did() | ||
if public_did_info: | ||
# If we already have a registered public did and it doesn't match | ||
# the one derived from `wallet_seed` then we error out. | ||
# TODO: Add a command to change public did explicitly | ||
if wallet_seed and seed_to_did(wallet_seed) != public_did_info.did: | ||
raise ProvisionError( | ||
"New seed provided which doesn't match the registered" | ||
+ f" public did {public_did_info.did}" | ||
) | ||
elif wallet_seed: | ||
public_did_info = await wallet.create_public_did(seed=wallet_seed) | ||
print("Created new public DID") | ||
if public_did_info: | ||
print("Public DID:", public_did_info.did) | ||
print("Verkey:", public_did_info.verkey) | ||
else: | ||
print("No public DID") | ||
|
||
|
||
def execute(argv: Sequence[str] = None): | ||
"""Entrypoint.""" | ||
parser = ArgumentParser() | ||
parser.prog += " provision" | ||
parser.add_argument( | ||
dest="provision_category", | ||
type=str, | ||
metavar=("<category>"), | ||
choices=["wallet"], | ||
help="The provision command to invoke", | ||
) | ||
get_settings = init_argument_parser(parser) | ||
args = parser.parse_args(argv) | ||
settings = get_settings(args) | ||
common_config(settings) | ||
|
||
loop = asyncio.get_event_loop() | ||
loop.run_until_complete(provision(args.provision_category, settings)) | ||
|
||
|
||
if __name__ == "__main__": | ||
execute() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
"""Entrypoint.""" | ||
|
||
import asyncio | ||
import functools | ||
import os | ||
import signal | ||
from argparse import ArgumentParser | ||
from typing import Coroutine, Sequence | ||
|
||
from ..conductor import Conductor | ||
from ..config import argparse as arg | ||
from ..config.default_context import DefaultContextBuilder | ||
from ..config.util import common_config | ||
|
||
|
||
async def start_app(conductor: Conductor): | ||
"""Start up.""" | ||
await conductor.setup() | ||
await conductor.start() | ||
|
||
|
||
async def shutdown_app(conductor: Conductor): | ||
"""Shut down.""" | ||
print("\nShutting down") | ||
await conductor.stop() | ||
|
||
|
||
def init_argument_parser(parser: ArgumentParser): | ||
"""Initialize an argument parser with the module's arguments.""" | ||
return arg.load_argument_groups(parser, *arg.group.get_registered(arg.CAT_START)) | ||
|
||
|
||
def execute(argv: Sequence[str] = None): | ||
"""Entrypoint.""" | ||
parser = ArgumentParser() | ||
parser.prog += " start" | ||
get_settings = init_argument_parser(parser) | ||
args = parser.parse_args(argv) | ||
settings = get_settings(args) | ||
common_config(settings) | ||
|
||
# Support WEBHOOK_URL environment variable | ||
webhook_url = os.environ.get("WEBHOOK_URL") | ||
if webhook_url: | ||
webhook_urls = list(settings.get("admin.webhook_urls") or []) | ||
webhook_urls.append(webhook_url) | ||
settings["admin.webhook_urls"] = webhook_urls | ||
|
||
# Create the Conductor instance | ||
context_builder = DefaultContextBuilder(settings) | ||
conductor = Conductor(context_builder) | ||
|
||
# Run the application | ||
run_loop(start_app(conductor), shutdown_app(conductor)) | ||
|
||
|
||
def run_loop(startup: Coroutine, shutdown: Coroutine): | ||
"""Execute the application, handling signals and ctrl-c.""" | ||
|
||
async def done(): | ||
"""Run shutdown and clean up any outstanding tasks.""" | ||
await shutdown | ||
tasks = [ | ||
task | ||
for task in asyncio.Task.all_tasks() | ||
if task is not asyncio.Task.current_task() | ||
] | ||
for task in tasks: | ||
task.cancel() | ||
if tasks: | ||
await asyncio.gather(*tasks, return_exceptions=True) | ||
asyncio.get_event_loop().stop() | ||
|
||
loop = asyncio.get_event_loop() | ||
loop.add_signal_handler( | ||
signal.SIGTERM, functools.partial(asyncio.ensure_future, done(), loop=loop) | ||
) | ||
asyncio.ensure_future(startup, loop=loop) | ||
|
||
try: | ||
loop.run_forever() | ||
except KeyboardInterrupt: | ||
loop.run_until_complete(done()) | ||
|
||
|
||
if __name__ == "__main__": | ||
execute() |
Empty file.
Oops, something went wrong.