qwj / python-proxy

HTTP/HTTP2/HTTP3/Socks4/Socks5/Shadowsocks/ShadowsocksR/SSH/Redirect/Pf TCP/UDP asynchronous tunnel proxy implemented in Python 3 asyncio.
MIT License
1.93k stars 323 forks source link

pyinstaller build for windows run infinity process #145

Open PieceOfGood opened 2 years ago

PieceOfGood commented 2 years ago

When I bulild this code to pproxy.exe:

import sys
import asyncio
import pproxy

server = pproxy.Server('http+socks4+socks5://:' + sys.argv[1])
tmpl = "http://{}:{}#{}:{}" if len(addr_params := sys.argv[2].split(":")) == 4 else "http://{}:{}"
remote = pproxy.Connection(tmpl.format(*addr_params))

loop = asyncio.get_event_loop()
handler = loop.run_until_complete(server.start_server({"rserver": [remote], "verbose": print}))

try:
    loop.run_forever()
except KeyboardInterrupt:
    print('exit!')

handler.close()
loop.run_until_complete(handler.wait_closed())
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()

This exe always starts two processes pproxy.exe and one of them always remains hanging after completion.. Whereas just running the code always starts one Python interpreter and closes it gracefully on completion.

Next example also behaves correctly when run natively.

import pproxy
import asyncio
from multiprocessing import Process

def proxy_func(local_port: str, remote_proxy_addr: str) -> None:
    server = pproxy.Server('http+socks4+socks5://:' + local_port)
    tmpl = "http://{}:{}#{}:{}" if len(addr_params := remote_proxy_addr.split(":")) == 4 else "http://{}:{}"
    remote = pproxy.Connection(tmpl.format(*addr_params))

    loop = asyncio.get_event_loop()
    handler = loop.run_until_complete(server.start_server({"rserver": [remote], "verbose": print}))

    try:
        loop.run_forever()
    except KeyboardInterrupt:
        print('exit!')

    handler.close()
    loop.run_until_complete(handler.wait_closed())
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()

async def main() -> None:
    proc = Process(target=proxy_func, args=("8080", "192.168.0.1:3128"))
    proc.start()

    await asyncio.sleep(5)
    proc.terminate()
    print("DONE")

if __name__ == '__main__':
    asyncio.run(main())

But if his build on pyinstaller to test.exe, it doesn't terminate after 5 seconds but starts running an infinite amount test.exe.

I am redirecting browser requests through proxies that require authorization, and since browsers don't support such proxies, I have to use an intermediary.

In principle, native launch solves the problem, but when I need to distribute code in conditions where this is unacceptable, then I have to endure these difficulties.

Could you suggest how it would be possible to build the proxy into an executable file in order to use it for such a simple purpose?