Skip to content

Commit

Permalink
🏗️ ✨ Add VMess AEAD CLI module with working server impl
Browse files Browse the repository at this point in the history
client impl is WIP.
  • Loading branch information
mnixry committed Mar 21, 2024
1 parent 869b88b commit 0b365bc
Showing 1 changed file with 168 additions and 0 deletions.
168 changes: 168 additions & 0 deletions src/vmess_aead/cli/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import asyncio
import contextlib
import logging
import uuid
from typing import Annotated

from vmess_aead.cli.server import VMessServerProtocol
from vmess_aead.enums import VMessBodySecurity

try:
import click
import typer
from rich.logging import RichHandler
except ImportError as e:
raise ImportError(
"Please install the extra dependencies for the CLI: pip install vmess-aead[cli]"
) from e

app = typer.Typer()


UUIDType = Annotated[
uuid.UUID,
typer.Option(
envvar="USER_ID",
help="User ID to identify the client or server.",
),
]
_DEFAULT_USER_ID = uuid.UUID("b831381d-6324-4d53-ad4f-8cda48b30811")

ListenPortType = Annotated[
int,
typer.Option(
envvar="LISTEN_PORT",
help="Port to listen or connect.",
click_type=click.IntRange(0x0000, 0xFFFF, min_open=True),
),
]

ListenAddrType = Annotated[
str,
typer.Option(
envvar="LISTEN_ADDR",
help="Address to listen.",
),
]

EnableUDPType = Annotated[
bool,
typer.Option(
envvar="ENABLE_UDP",
help="Enable UDP relay.",
),
]


@app.command()
def server(
user_id: UUIDType = _DEFAULT_USER_ID,
listen_port: ListenPortType = 10086,
listen_addr: ListenAddrType = "0.0.0.0",
enable_udp: EnableUDPType = True,
):
async def server_main():
loop = asyncio.get_running_loop()
server = await loop.create_server(
lambda: VMessServerProtocol(user_id, enable_udp=enable_udp),
host=listen_addr,
port=listen_port,
)
logging.info("Listening on %s:%d", listen_addr, listen_port)

async with server:
with contextlib.suppress(KeyboardInterrupt):
await server.serve_forever()
return

asyncio.run(server_main())


ServerPortType = Annotated[
int,
typer.Option(
envvar="SERVER_PORT",
help="Port to connect.",
click_type=click.IntRange(0x0000, 0xFFFF, min_open=True),
),
]

ServerAddrType = Annotated[
str,
typer.Option(
envvar="SERVER_ADDR",
help="Address to connect.",
),
]

LocalProtocolType = Annotated[
str,
typer.Option(
envvar="LOCAL_PROTOCOL",
help="Local proxy protocol to use.",
click_type=click.Choice(["SOCKS5", "HTTP"], case_sensitive=False),
),
]

ConnectionTimeoutType = Annotated[
float,
typer.Option(
envvar="CONNECTION_TIMEOUT",
help="Connection timeout to the server, in seconds.",
click_type=click.FloatRange(0, min_open=True),
),
]

VMessProtocolSecurityType = Annotated[
str,
typer.Option(
envvar="SECURITY",
help="Security protocol to use.",
click_type=click.Choice(
[security.name for security in VMessBodySecurity],
case_sensitive=False,
),
),
]


@app.command()
def client(
server_addr: ServerAddrType,
server_port: ServerPortType,
user_id: UUIDType,
listen_port: ListenPortType = 1080,
listen_addr: ListenAddrType = "127.0.0.1",
enable_udp: EnableUDPType = False,
local_protocol: LocalProtocolType = "SOCKS5",
connection_timeout: ConnectionTimeoutType = 10,
security: VMessProtocolSecurityType = "AES_128_GCM",
):
pass


LogLevelType = Annotated[
str,
typer.Option(
envvar="LOG_LEVEL",
click_type=click.Choice(
[*logging.getLevelNamesMapping().keys()],
case_sensitive=False,
),
help="Logging level, set lower than INFO may reduce performance.",
),
]


@app.callback()
def main(log_level: LogLevelType = "DEBUG"):
logging.basicConfig(
level=log_level,
format="%(message)s",
datefmt="[%X]",
handlers=[RichHandler(rich_tracebacks=True)],
)


if __name__ == "__main__":
app()

0 comments on commit 0b365bc

Please sign in to comment.