|
import os |
|
from pathlib import Path |
|
import json |
|
import aiohttp |
|
import asyncio |
|
from layoutx import app |
|
from layoutx.store import create_store |
|
from layoutx.view import View, ResizeOption |
|
|
|
home = str(Path.home()) |
|
ngrok_home = Path(home) / ".ngrok2" |
|
|
|
if not Path(ngrok_home).exists(): |
|
Path(ngrok_home).mkdir( exist_ok=True ) |
|
|
|
with open(Path(ngrok_home) / "ngrok.yml", "w") as authToken: |
|
authToken.write("authtoken: xxx") |
|
authToken.write("\n") |
|
authToken.write("region: eu") |
|
|
|
processes = [] |
|
|
|
store = create_store({},{ |
|
"ipv4": "0.0.0.0", |
|
"ipv6": "::0", |
|
"hostname": "", |
|
"vnc_status": False |
|
}) |
|
|
|
async def _read_stream(stream, cb): |
|
while True: |
|
line = await stream.readline() |
|
if line and cb: |
|
cb(line) |
|
else: |
|
break |
|
|
|
async def _stream_subprocess(cmd, stdout_cb, stderr_cb): |
|
global processes |
|
|
|
process = await asyncio.create_subprocess_exec(*cmd, |
|
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) |
|
|
|
processes.append(process) |
|
|
|
await asyncio.wait([ |
|
_read_stream(process.stdout, stdout_cb), |
|
_read_stream(process.stderr, stderr_cb) |
|
]) |
|
return await process.wait() |
|
|
|
|
|
async def execute(cmd, stdout_cb, stderr_cb): |
|
rc = await _stream_subprocess( |
|
cmd, |
|
stdout_cb, |
|
stderr_cb, |
|
) |
|
return rc |
|
|
|
async def sendMessage(text): |
|
session = aiohttp.ClientSession() |
|
await session.post("https://api.telegram.org/botxxx/sendMessage", data={ "chat_id": 0, "text": text }) |
|
await session.close() |
|
|
|
async def get_ngrok(): |
|
await asyncio.sleep(5) |
|
session = aiohttp.ClientSession() |
|
async with session.get("http://127.0.0.1:4040/api/tunnels") as r: |
|
ngrok = json.loads(await r.text()) |
|
hostname = ngrok["tunnels"][0]["public_url"] |
|
await sendMessage(hostname) |
|
store.dispatch("SET_VALUE", { "path": ["hostname"], "value": hostname }) |
|
await session.close() |
|
|
|
class AppView(View): |
|
geometry = "400x110+200+200" |
|
title = "Remote Helper" |
|
resizable = ResizeOption.NONE |
|
template= """\ |
|
Box |
|
Box(orient="horizontal") |
|
Label Hostname: |
|
Label {hostname} |
|
Box(orient="horizontal") |
|
Label IPv4: |
|
Label {ipv4} |
|
Box(orient="horizontal") |
|
Label IPv6: |
|
Label {ipv6} |
|
Box(orient="horizontal") |
|
Label VNC: |
|
Label {vnc_status} |
|
Button(if="{not vnc_status}" command="{contact_max}") Create remote |
|
Button(if="{vnc_status}" command="{stop}") Stop |
|
""" |
|
async def contact_max(self): |
|
#await execute( |
|
# ["./ngrok", "tcp", "5900"], |
|
# lambda x: print("STDOUT: %s" % x), |
|
# lambda x: print("STDERR: %s" % x), |
|
#) |
|
store.dispatch("SET_VALUE", { "path": ["vnc_status"], "value": True }) |
|
await asyncio.gather( execute( |
|
["x0vncserver", "-rfbauth", "pass"], |
|
None, |
|
None, |
|
), execute( |
|
["./ngrok", "tcp", "5900"], |
|
lambda x: print("STDOUT: %s" % x), |
|
lambda x: print("STDERR: %s" % x), |
|
), get_ngrok()) |
|
store.dispatch("SET_VALUE", { "path": ["vnc_status"], "value": False }) |
|
|
|
async def stop(self): |
|
global processes |
|
|
|
for p in processes: |
|
p.kill() |
|
|
|
processes = [] |
|
|
|
|
|
loop = asyncio.get_event_loop() |
|
|
|
|
|
async def get_ipv4(): |
|
session = aiohttp.ClientSession() |
|
async with session.get("https://api.ipify.org?format=json") as resp: |
|
store.dispatch("SET_VALUE", { "path": ["ipv4"], "value": json.loads(await resp.text())["ip"] }) |
|
await session.close() |
|
|
|
async def get_ipv6(): |
|
session = aiohttp.ClientSession() |
|
async with session.get("https://api6.ipify.org?format=json") as resp: |
|
store.dispatch("SET_VALUE", { "path": ["ipv6"], "value": json.loads(await resp.text())["ip"] }) |
|
await session.close() |
|
|
|
|
|
loop.create_task(get_ipv4()) |
|
loop.create_task(get_ipv6()) |
|
|
|
if __name__ == "__main__": |
|
app.setup(store, AppView, style="black", loop=loop) |
|
app.run() |