Skip to content

Commit

Permalink
Merge pull request #301 from doronz88/feature/rpclocal
Browse files Browse the repository at this point in the history
cli: add `rpclocal`
  • Loading branch information
doronz88 authored Jul 13, 2023
2 parents 27de79a + d5c7707 commit f5bbf31
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/macos-pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

strategy:
matrix:
python-version: [ 3.7, 3.8, 3.9, "3.10", 3.11 ]
python-version: [ 3.8, 3.9, "3.10", 3.11 ]
os: [ macos-latest ]

steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

strategy:
matrix:
python-version: [ 3.7, 3.8, 3.9, "3.10", 3.11 ]
python-version: [ 3.8, 3.9, "3.10", 3.11 ]
os: [ ubuntu-latest, macos-latest, windows-latest ]

steps:
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ The python client utilizes the ability to call native functions in order to prov

and much more...

## Installation
## Local installation

```shell
# install the package
python3 -m pip install -U rpcclient

# enter shell
rpclocal
```

## Remote installation

Download and execute the latest server artifact, according to your platform and arch from here:

Expand Down
6 changes: 3 additions & 3 deletions src/rpcclient/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "rpcclient"
version = "3.16.2"
description = "rpcclient for connecting with the rpcserver"
readme = "README.md"
requires-python = ">=3.7"
requires-python = ">=3.8"
license = { file = "LICENSE" }
keywords = ["ios", "macos", "linux", "automation", "remote-shell", "remote-control", "ipython"]
authors = [
Expand All @@ -18,7 +18,6 @@ classifiers = [
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -36,7 +35,8 @@ docs = ["toml", "myst_parser", "sphinx", "sphinx-rtd-theme"]
"Bug Reports" = "https://github.com/doronz88/rpc-project/issues"

[project.scripts]
rpcclient = "rpcclient.__main__:cli"
rpcclient = "rpcclient.__main__:rpcclient"
rpclocal = "rpcclient.__main__:rpclocal"

[tool.setuptools.packages.find]
exclude = ["docs*", "tests*"]
Expand Down
13 changes: 10 additions & 3 deletions src/rpcclient/rpcclient/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import click
import coloredlogs

from rpcclient.client_factory import create_tcp_client
from rpcclient.client_factory import create_local, create_tcp_client
from rpcclient.protocol import DEFAULT_PORT

coloredlogs.install(level=logging.DEBUG)
Expand All @@ -16,12 +16,19 @@
logging.getLogger('humanfriendly.prompts').disabled = True


@click.command()
def rpclocal() -> None:
""" connect to local machine """
create_local().interactive()


@click.command()
@click.argument('hostname')
@click.option('-p', '--port', type=click.INT, default=DEFAULT_PORT)
@click.option('-r', '--rebind-symbols', is_flag=True, help='reload all symbols upon connection')
@click.option('-l', '--load-all-libraries', is_flag=True, help='load all libraries')
def cli(hostname: str, port: int, rebind_symbols: bool, load_all_libraries: bool):
def rpcclient(hostname: str, port: int, rebind_symbols: bool, load_all_libraries: bool):
""" connect to remote host """
client = create_tcp_client(hostname, port=port)
if load_all_libraries:
client.load_all_libraries(rebind_symbols=False)
Expand All @@ -31,4 +38,4 @@ def cli(hostname: str, port: int, rebind_symbols: bool, load_all_libraries: bool


if __name__ == '__main__':
cli()
rpcclient()
44 changes: 42 additions & 2 deletions src/rpcclient/rpcclient/client_factory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import logging
import os
import subprocess
import tempfile
import typing
from pathlib import Path
from socket import socket
from zipfile import ZipFile

import requests

from rpcclient.client import Client
from rpcclient.exceptions import FailedToConnectError, InvalidServerVersionMagicError
Expand All @@ -9,6 +16,12 @@
from rpcclient.macos.client import MacosClient
from rpcclient.protocol import DEFAULT_PORT, SERVER_MAGIC_VERSION, protocol_handshake_t

PROJECT_URL = 'https://github.com/doronz88/rpc-project/archive/refs/heads/master.zip'
RPCSERVER_SUBDIR = 'rpc-project-master/src/rpcserver'
HOMEDIR = Path('~/.rpc-project').expanduser()

logger = logging.getLogger(__name__)


def recvall(sock, size: int) -> bytes:
buf = b''
Expand All @@ -21,7 +34,34 @@ def recvall(sock, size: int) -> bytes:
return buf


def create_tcp_client(hostname: str, port: int = DEFAULT_PORT):
def create_local() -> typing.Union[Client, IosClient, MacosClient, LinuxClient]:
if not HOMEDIR.exists():
with tempfile.TemporaryDirectory() as temp_dir:
local_zip = Path(temp_dir) / 'master.zip'
local_zip.write_bytes(requests.get(PROJECT_URL).content)
ZipFile(local_zip).extractall(HOMEDIR)
os.chdir(HOMEDIR / RPCSERVER_SUBDIR)
cwd = os.getcwd()

assert 0 == os.system('make')

server = socket()
server.bind(('127.0.0.1', 0))
available_port = server.getsockname()[1]
server.close()

proc = subprocess.Popen(['./rpcserver', '-p', str(available_port)], cwd=cwd)
logger.info(f'server launched at pid {proc.pid}')

while True:
try:
return create_tcp_client('127.0.0.1', available_port)
except FailedToConnectError:
pass


def create_tcp_client(hostname: str, port: int = DEFAULT_PORT) -> \
typing.Union[Client, IosClient, MacosClient, LinuxClient]:
def tcp_connect() -> socket:
sock = socket()
try:
Expand All @@ -34,7 +74,7 @@ def tcp_connect() -> socket:
return create_client(tcp_connect)


def create_client(create_socket_cb: typing.Callable):
def create_client(create_socket_cb: typing.Callable) -> typing.Union[Client, IosClient, MacosClient, LinuxClient]:
sock = create_socket_cb()
handshake = protocol_handshake_t.parse(recvall(sock, protocol_handshake_t.sizeof()))

Expand Down

0 comments on commit f5bbf31

Please sign in to comment.