Skip to content

Commit

Permalink
python-client: initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
koush committed Jul 4, 2023
1 parent f7e35fb commit 488d68e
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/python-client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.venv
16 changes: 16 additions & 0 deletions packages/python-client/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/test.py",
"console": "integratedTerminal",
"justMyCode": true
}
]
}
1 change: 1 addition & 0 deletions packages/python-client/plugin_remote.py
3 changes: 3 additions & 0 deletions packages/python-client/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
python-engineio[asyncio_client]
aiohttp
aiodns
1 change: 1 addition & 0 deletions packages/python-client/rpc.py
1 change: 1 addition & 0 deletions packages/python-client/rpc_reader.py
1 change: 1 addition & 0 deletions packages/python-client/scrypted_python
101 changes: 101 additions & 0 deletions packages/python-client/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import asyncio
import engineio
import os
import aiohttp
import rpc_reader
import plugin_remote
from plugin_remote import SystemManager, MediaManager
from scrypted_python.scrypted_sdk import ScryptedStatic

class EioRpcTransport(rpc_reader.RpcTransport):
message_queue = asyncio.Queue()

def __init__(self, loop: asyncio.AbstractEventLoop):
super().__init__()
self.eio = engineio.AsyncClient(ssl_verify=False)
self.loop = loop

@self.eio.on("message")
def on_message(data):
self.message_queue.put_nowait(data)

async def read(self):
return await self.message_queue.get()

def writeBuffer(self, buffer, reject):
self.writeBuffer(buffer, reject)

def writeJSON(self, json, reject):
async def send():
try:
await self.eio.send(json)
except Exception as e:
reject(e)
asyncio.run_coroutine_threadsafe(send(), self.loop)


async def connect_scrypted_client(
base_url: str, username: str, password: str, plugin_id: str = "@scrypted/core"
):
login_url = f"{base_url}/login"
login_body = {
"username": username,
"password": password,
}

async with aiohttp.ClientSession() as session:
async with session.post(
login_url, verify_ssl=False, json=login_body
) as response:
login_response = await response.json()

headers = {"Authorization": login_response["authorization"]}

loop = asyncio.get_event_loop()
transport = EioRpcTransport(loop)

await transport.eio.connect(
base_url,
headers=headers,
engineio_path=f"/endpoint/{plugin_id}/engine.io/api/",
)

ret = asyncio.Future[ScryptedStatic](loop=loop)
peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(loop, transport)
peer.params['print'] = print
def callback(api, pluginId, hostInfo):
remote = plugin_remote.PluginRemote(peer, api, pluginId, hostInfo, loop)
wrapped = remote.setSystemState
async def remoteSetSystemState(systemState):
await wrapped(systemState)
async def resolve():
sdk = ScryptedStatic()
sdk.api = api
sdk.remote = remote
sdk.systemManager = SystemManager(api, remote.systemState)
sdk.mediaManager = MediaManager(await api.getMediaManager())
ret.set_result(sdk)
asyncio.run_coroutine_threadsafe(resolve(), loop)
remote.setSystemState = remoteSetSystemState
return remote
peer.params['getRemote'] = callback
asyncio.run_coroutine_threadsafe(peerReadLoop(), loop)

sdk = await ret
return sdk

async def main():
sdk = await connect_scrypted_client(
"https://localhost:10443",
os.environ["SCRYPTED_USERNAME"],
os.environ["SCRYPTED_PASSWORD"],
)

for id in sdk.systemManager.getSystemState():
device = sdk.systemManager.getDeviceById(id)
print(device.name)
os._exit(0)

loop = asyncio.new_event_loop()
asyncio.run_coroutine_threadsafe(main(), loop)
loop.run_forever()

0 comments on commit 488d68e

Please sign in to comment.