{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Hypha Demos\n",
        "\n",
        "## Install client library"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "try:\n",
        "    # For pyodide in the browser\n",
        "    import micropip\n",
        "    await micropip.install(['imjoy_rpc'])\n",
        "except ImportError:\n",
        "    # For native python with pip\n",
        "    import subprocess\n",
        "    subprocess.call(['pip', 'install', 'imjoy_rpc'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Connect to the server"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "from imjoy_rpc.hypha import connect_to_server\n",
        "\n",
        "api = await connect_to_server(\n",
        "    {\"name\": \"test client\", \"server_url\": \"https://ai.imjoy.io\"}\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "# Generate credentials for later usage\n",
        "workspace = api.config.workspace\n",
        "token = await api.generate_token()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## List all the public services"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 99,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[{'id': 'public/workspace-manager:triton-client',\n",
              "  'name': 'Triton Client',\n",
              "  'type': 'triton-client',\n",
              "  'config': {'visibility': 'public',\n",
              "   'require_context': True,\n",
              "   'workspace': 'public',\n",
              "   'flags': []}},\n",
              " {'id': 'public/workspace-manager:s3-storage',\n",
              "  'name': 'S3 Storage',\n",
              "  'type': 's3-storage',\n",
              "  'config': {'visibility': 'public',\n",
              "   'require_context': True,\n",
              "   'workspace': 'public',\n",
              "   'flags': []}},\n",
              " {'id': 'public/workspace-manager:rdf',\n",
              "  'name': 'RDF',\n",
              "  'type': 'rdf',\n",
              "  'config': {'visibility': 'public',\n",
              "   'require_context': True,\n",
              "   'workspace': 'public',\n",
              "   'flags': []}},\n",
              " {'id': 'public/workspace-manager:server-apps',\n",
              "  'name': 'Server Apps',\n",
              "  'type': 'server-apps',\n",
              "  'config': {'visibility': 'public',\n",
              "   'require_context': True,\n",
              "   'workspace': 'public',\n",
              "   'flags': []}}]"
            ]
          },
          "execution_count": 99,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "public_services = await api.list_services(\"public\")\n",
        "public_services"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Use the s3-storage service"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 100,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'config': {'visibility': 'public',\n",
              "  'require_context': True,\n",
              "  'workspace': 'public',\n",
              "  'flags': []},\n",
              " 'id': 's3-storage',\n",
              " 'name': 'S3 Storage',\n",
              " 'type': 's3-storage',\n",
              " 'list_files': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'generate_credential': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'generate_presigned_url': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>}"
            ]
          },
          "execution_count": 100,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "s3 = await api.get_service(\"s3-storage\")\n",
        "s3"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Generate credential for s3 client"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 101,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'endpoint_url': 'https://s3.imjoy.io',\n",
              " 'access_key_id': 'PpxTnuczVrF4xNg8LGb4fS',\n",
              " 'secret_access_key': 'IefT9XG26iQdnfy1D4zB',\n",
              " 'bucket': 'hypha-workspaces',\n",
              " 'prefix': 'PpxTnuczVrF4xNg8LGb4fS/'}"
            ]
          },
          "execution_count": 101,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "info = await s3.generate_credential()\n",
        "info"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Upload an file to the workspace via hypha"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 104,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'{\"ResponseMetadata\":{\"RequestId\":\"16EA80BB0B90A875\",\"HostId\":\"\",\"HTTPStatusCode\":200,\"HTTPHeaders\":{\"accept-ranges\":\"bytes\",\"content-length\":\"0\",\"content-security-policy\":\"block-all-mixed-content\",\"etag\":\"\\\\\"aff97160474a056e838c1f721af01edf\\\\\"\",\"server\":\"MinIO\",\"strict-transport-security\":\"max-age=31536000; includeSubDomains\",\"vary\":\"Accept-Encoding\",\"x-amz-request-id\":\"16EA80BB0B90A875\",\"x-content-type-options\":\"nosniff\",\"x-xss-protection\":\"1; mode=block\",\"date\":\"Fri, 29 Apr 2022 23:09:14 GMT\"},\"RetryAttempts\":0},\"ETag\":\"\\\\\"aff97160474a056e838c1f721af01edf\\\\\"\"}'"
            ]
          },
          "execution_count": 104,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from js import fetch, File, Object, eval\n",
        "url = f\"https://ai.imjoy.io/{workspace}/files/hello.txt\"\n",
        "headers = eval(f\"headers={{Authorization: 'Bearer {token}'}}\")\n",
        "file = File.new([\"hi!\"], \"hello.txt\");\n",
        "response = await fetch(url, method=\"PUT\", body=file, withCredentials=True, headers=headers)\n",
        "await response.text()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Generate a presigned url for downloading a file"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 105,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "https://s3.imjoy.io/hypha-workspaces/PpxTnuczVrF4xNg8LGb4fS/hello.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=europas3%2F20220429%2FEU%2Fs3%2Faws4_request&X-Amz-Date=20220429T230919Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=d7784bb2db00958dceb35e41dc822786d01d6ade4d228748d33da73c7f66ae48\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "'hi!'"
            ]
          },
          "execution_count": 105,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "url = await s3.generate_presigned_url(\n",
        "    info[\"bucket\"], info[\"prefix\"] + \"hello.txt\"\n",
        ")\n",
        "print(url)\n",
        "response = await fetch(url, method=\"GET\")\n",
        "await response.text()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Download the file"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 106,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'hi!'"
            ]
          },
          "execution_count": 106,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from js import fetch, File, Object, eval\n",
        "url = f\"https://ai.imjoy.io/{workspace}/files/hello.txt\"\n",
        "headers = eval(f\"headers={{Authorization: 'Bearer {token}'}}\")\n",
        "response = await fetch(url, method=\"GET\", withCredentials=True, headers=headers)\n",
        "await response.text()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 107,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[{'type': 'file',\n",
              "  'name': 'hello.txt',\n",
              "  'size': 3,\n",
              "  'last_modified': 1651273754.223}]"
            ]
          },
          "execution_count": 107,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await s3.list_files()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Use triton-client service"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "from js import fetch\n",
        "import io\n",
        "from PIL import Image\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "\n",
        "async def fetch_image(url, name=None, grayscale=False, transpose=False, size=None):\n",
        "    response = await fetch(url)\n",
        "    bytes = await response.arrayBuffer()\n",
        "    bytes = bytes.to_py()\n",
        "    buffer = io.BytesIO(bytes)\n",
        "    buffer.name = name or url.split('?')[0].split('/')[1]\n",
        "    image = Image.open(buffer)\n",
        "    if grayscale:\n",
        "        image = image.convert('L')\n",
        "    if size:\n",
        "        image = image.resize(size=size)\n",
        "    image = np.array(image).astype('float32')\n",
        "    if transpose:\n",
        "        image = image.transpose(2, 0, 1)\n",
        "    return image\n",
        "\n",
        "def display_image(image, mask):\n",
        "    # display the output\n",
        "    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))\n",
        "    ax1.imshow(image)\n",
        "    ax1.set_title('input image')\n",
        "    ax2.imshow(mask)\n",
        "    ax2.set_title('predicted mask')\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "image = await fetch_image('https://static.imjoy.io/img/img02.png', transpose=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 169232 characters]",
            "text/plain": [
              "<pyolite.display.Image at 0x3d4fbd8>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "triton = await api.get_service(\"triton-client\")\n",
        "results = await triton.execute(inputs=[image, {'diameter': 30}], model_name='cellpose-python', decode_json=True)\n",
        "\n",
        "mask = results['mask'][0]\n",
        "display_image(image.transpose(1, 2, 0).astype('uint8'), mask)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Use server-apps service"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'config': {'visibility': 'public',\n",
              "  'require_context': True,\n",
              "  'workspace': 'public',\n",
              "  'flags': []},\n",
              " 'id': 'server-apps',\n",
              " 'name': 'Server Apps',\n",
              " 'type': 'server-apps',\n",
              " 'launch': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'list_apps': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'list_running': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'install': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'get_log': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'start': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'stop': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>,\n",
              " 'uninstall': <function imjoy_rpc.hypha.rpc.RPC._generate_remote_method.<locals>.remote_method(*arguments, **kwargs)>}"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "controller = await api.get_service(\"server-apps\")\n",
        "controller"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Launch a window plugin"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "TEST_APP_CODE = \"\"\"\n",
        "api.log('awesome!connected!');\n",
        "\n",
        "api.export({\n",
        "    async setup(){\n",
        "        console.log(\"this is a log\");\n",
        "        console.error(\"this is an error\");\n",
        "        await api.log(\"initialized\")\n",
        "    },\n",
        "    async check_webgpu(){\n",
        "        if (\"gpu\" in navigator) {\n",
        "            // WebGPU is supported!\n",
        "            return true\n",
        "        }\n",
        "        else return false\n",
        "    },\n",
        "    async execute(a, b){\n",
        "        console.log(\"executing\", a, b);\n",
        "        return a + b\n",
        "    }\n",
        "})\n",
        "\"\"\"\n",
        "controller = await api.get_service(\"server-apps\")\n",
        "config = await controller.launch(\n",
        "    source=TEST_APP_CODE,\n",
        "    config={\"type\": \"window\"},\n",
        ")\n",
        "assert \"app_id\" in config\n",
        "plugin = await api.get_plugin(config.id)\n",
        "assert \"execute\" in plugin\n",
        "result = await plugin.execute(2, 4)\n",
        "assert result == 6\n",
        "webgpu_available = await plugin.check_webgpu()\n",
        "assert webgpu_available is True\n",
        "# only pass name so the app won't be removed\n",
        "await controller.stop(config.id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Launch a web-python plugin"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "TEST_APP_CODE = \"\"\"\n",
        "from imjoy_rpc import api\n",
        "\n",
        "async def setup():\n",
        "    await api.log(\"started\")\n",
        "\n",
        "api.export({\"setup\": setup})\n",
        "\"\"\"\n",
        "controller = await api.get_service(\"server-apps\")\n",
        "config = await controller.launch(\n",
        "    source=TEST_APP_CODE,\n",
        "    config={\"type\": \"web-python\"},\n",
        ")\n",
        "plugin = await api.get_plugin(config.id)\n",
        "assert \"setup\" in plugin"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "await plugin.setup()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[{'config': {'visibility': 'protected',\n",
              "   'require_context': False,\n",
              "   'workspace': 'DEcRy4JJvFmQ3sHcNDE3h8',\n",
              "   'flags': []},\n",
              "  'id': 'DEcRy4JJvFmQ3sHcNDE3h8/WcSKBPCquX5f8bmQdM2vey:default',\n",
              "  'name': 'Untitled Plugin',\n",
              "  'type': 'generic'},\n",
              " {'config': {'visibility': 'protected',\n",
              "   'require_context': False,\n",
              "   'workspace': 'DEcRy4JJvFmQ3sHcNDE3h8',\n",
              "   'flags': []},\n",
              "  'id': 'DEcRy4JJvFmQ3sHcNDE3h8/ERAWbr7kMU7Dw6ETF3MVio:default',\n",
              "  'name': 'Untitled Plugin',\n",
              "  'type': 'generic'}]"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plugins = await api.list_plugins()\n",
        "plugins"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'error': [],\n",
              " 'log': ['Loading distutils',\n",
              "  'Loading distutils from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/distutils.js',\n",
              "  'Loaded distutils',\n",
              "  'Loading micropip, pyparsing, packaging, distutils',\n",
              "  'Loading micropip from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/micropip.js',\n",
              "  'Loading pyparsing from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyparsing.js',\n",
              "  'Loading packaging from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/packaging.js',\n",
              "  'distutils already loaded from default channel',\n",
              "  'Loaded micropip, pyparsing, packaging, distutils',\n",
              "  'Loading msgpack',\n",
              "  'Loading msgpack from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/msgpack.js',\n",
              "  'Loaded msgpack']}"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await controller.get_log(config.id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [],
      "source": [
        "await controller.stop(config.id)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Launch a web-python plugin and serve a web app"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Server app running at https://ai.imjoy.io/DEcRy4JJvFmQ3sHcNDE3h8/apps/cellpose/predict\n"
          ]
        }
      ],
      "source": [
        "controller = await api.get_service(\"server-apps\")\n",
        "app = await controller.launch(\n",
        "    source=\"https://gist.githubusercontent.com/oeway/4667231efb08c39b9f41b827b91229de/raw/ASGIWebPythonPlugin.imjoy.html\",\n",
        "    timeout=20\n",
        ")\n",
        "server_info = await api.get_connection_info()\n",
        "\n",
        "print(f\"Server app running at {server_info.public_base_url}/{workspace}/apps/cellpose/predict\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'local_url': 'http://127.0.0.1:9520/apps/DEcRy4JJvFmQ3sHcNDE3h8/QmXUiEnpwTxfpnQFyajf7AQE839CznLdNLcL54H7ZEh9MF/index.html?client_id=cyGAid6K7h5kaCRZyhA3gY&workspace=DEcRy4JJvFmQ3sHcNDE3h8&server_url=ws://127.0.0.1:9520/ws&token=KX8P9cAsUtetsjNXCqkLNq@imjoy@eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2ltam95LmlvLyIsInN1YiI6IktYOFA5Y0FzVXRldHNqTlhDcWtMTnEiLCJhdWQiOiJodHRwczovL2ltam95LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjUxNDcyMjc3LjcxMjk1NzksImV4cCI6MTY1MTQ4MzA3Ny43MTI5NTc5LCJzY29wZSI6IkRFY1J5NEpKdkZtUTNzSGNOREUzaDgiLCJwYXJlbnQiOiJyb290IiwicGMiOiJERWNSeTRKSnZGbVEzc0hjTkRFM2g4L2NRc0JGQkduSHY3TWpWaEhjWmJ4VkYiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMiLCJodHRwczovL2FwaS5pbWpveS5pby9yb2xlcyI6W10sImh0dHBzOi8vYXBpLmltam95LmlvL2VtYWlsIjpudWxsfQ.haYr2EWJpLoOY5KvUOIwIlFCpZ3Xs67DtR8gYt_B-aM',\n",
              " 'id': 'cyGAid6K7h5kaCRZyhA3gY',\n",
              " 'workspace': 'DEcRy4JJvFmQ3sHcNDE3h8',\n",
              " 'app_id': 'DEcRy4JJvFmQ3sHcNDE3h8/QmXUiEnpwTxfpnQFyajf7AQE839CznLdNLcL54H7ZEh9MF',\n",
              " 'public_url': 'https://ai.imjoy.io/apps/DEcRy4JJvFmQ3sHcNDE3h8/QmXUiEnpwTxfpnQFyajf7AQE839CznLdNLcL54H7ZEh9MF/index.html?client_id=cyGAid6K7h5kaCRZyhA3gY&workspace=DEcRy4JJvFmQ3sHcNDE3h8&server_url=wss://ai.imjoy.io/ws&token=KX8P9cAsUtetsjNXCqkLNq@imjoy@eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2ltam95LmlvLyIsInN1YiI6IktYOFA5Y0FzVXRldHNqTlhDcWtMTnEiLCJhdWQiOiJodHRwczovL2ltam95LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjUxNDcyMjc3LjcxMjk1NzksImV4cCI6MTY1MTQ4MzA3Ny43MTI5NTc5LCJzY29wZSI6IkRFY1J5NEpKdkZtUTNzSGNOREUzaDgiLCJwYXJlbnQiOiJyb290IiwicGMiOiJERWNSeTRKSnZGbVEzc0hjTkRFM2g4L2NRc0JGQkduSHY3TWpWaEhjWmJ4VkYiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMiLCJodHRwczovL2FwaS5pbWpveS5pby9yb2xlcyI6W10sImh0dHBzOi8vYXBpLmltam95LmlvL2VtYWlsIjpudWxsfQ.haYr2EWJpLoOY5KvUOIwIlFCpZ3Xs67DtR8gYt_B-aM',\n",
              " 'name': 'ASGIWebPythonPlugin'}"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "app"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'error': [],\n",
              " 'log': ['Loading distutils',\n",
              "  'Loading distutils from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/distutils.js',\n",
              "  'Loaded distutils',\n",
              "  'Loading micropip, pyparsing, packaging, distutils',\n",
              "  'Loading micropip from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/micropip.js',\n",
              "  'Loading pyparsing from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyparsing.js',\n",
              "  'Loading packaging from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/packaging.js',\n",
              "  'distutils already loaded from default channel',\n",
              "  'Loaded micropip, pyparsing, packaging, distutils',\n",
              "  'Loading numpy, imageio, pillow, matplotlib, distutils, cycler, six, kiwisolver, pyparsing, python-dateutil, pytz, msgpack, typing-extensions',\n",
              "  'Loading numpy from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/numpy.js',\n",
              "  'Loading imageio from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/imageio.js',\n",
              "  'Loading pillow from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pillow.js',\n",
              "  'Loading matplotlib from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/matplotlib.js',\n",
              "  'distutils already loaded from default channel',\n",
              "  'Loading cycler from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/cycler.js',\n",
              "  'Loading six from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/six.js',\n",
              "  'Loading kiwisolver from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/kiwisolver.js',\n",
              "  'pyparsing already loaded from default channel',\n",
              "  'Loading python-dateutil from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/python-dateutil.js',\n",
              "  'Loading pytz from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pytz.js',\n",
              "  'Loading msgpack from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/msgpack.js',\n",
              "  'Loading typing-extensions from https://cdn.jsdelivr.net/pyodide/v0.18.1/full/typing-extensions.js',\n",
              "  'Loaded numpy, imageio, pillow, matplotlib, distutils, cycler, six, kiwisolver, pyparsing, python-dateutil, pytz, msgpack, typing-extensions']}"
            ]
          },
          "execution_count": 16,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "await controller.get_log(app.id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "trusted": true
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "stopping WcSKBPCquX5f8bmQdM2vey\n",
            "stopping cyGAid6K7h5kaCRZyhA3gY\n"
          ]
        }
      ],
      "source": [
        "apps = await controller.list_running()\n",
        "for app in apps:\n",
        "    print(\"stopping \" + app.id)\n",
        "    await controller.stop(app.id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Pyolite",
      "language": "python",
      "name": "python"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "python",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.8"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}
