You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

90 lines
3.3 KiB

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import copy
from Filter import Filter
from Basis.Logger import logging
from Basis.Process import Process
from Basis.Functions import v6AddBracket
from Basis.Constant import WorkDir, PathEnv
from Basis.Functions import genFlag, getAvailablePort
from Basis.Exception import buildException, filterException
from Builder import Brook
from Builder import VMess
from Builder import VLESS
from Builder import Trojan
from Builder import TrojanGo
from Builder import Hysteria
from Builder import Shadowsocks
from Builder import ShadowsocksR
clientEntry = {
'ss': [Shadowsocks.load, '.json'],
'ssr': [ShadowsocksR.load, '.json'],
'vmess': [VMess.load, '.json'],
'vless': [VLESS.load, '.json'],
'trojan': [Trojan.load, '.json'],
'trojan-go': [TrojanGo.load, '.json'],
'brook': [Brook.load, ''],
'hysteria': [Hysteria.load, '.json'],
}
class Builder(object):
""" Build the proxy client process and expose socks5 port.
Arguments:
proxyType: Proxy node type.
proxyInfo: Proxy node information.
bindAddr: Socks5 proxy bind address.
taskId: Task ID, defaults to 12 random characters length.
Attributes:
id, proxyType, proxyInfo, socksAddr, socksPort, output
"""
output = None # output capture of proxy client (after process exit)
def __loadClient(self):
logging.info('[%s] Builder load %s client at %s -> %s' % (
self.id, self.proxyType,
'socks5://%s:%i' % (v6AddBracket(self.socksAddr), self.socksPort), self.proxyInfo
))
configFile = os.path.join( # config file path
WorkDir, self.id + clientEntry[self.proxyType][1] # workDir + taskId + file suffix
)
logging.debug('[%s] Builder config file -> %s' % (self.id, configFile))
command, fileContent, envVar = clientEntry[self.proxyType][0](self.proxyInfo, { # load client boot info
'addr': self.socksAddr, # specify socks5 info
'port': self.socksPort,
}, configFile)
envVar['PATH'] = PathEnv # add PATH env (some programs need it)
self.__process = Process(WorkDir, taskId = self.id, cmd = command, env = envVar, file = { # start process
'path': configFile,
'content': fileContent
})
def __init__(self, proxyType: str, proxyInfo: dict, bindAddr: str, taskId: str = '') -> None: # init proxy client
self.id = genFlag(length = 12) if taskId == '' else taskId # load task ID
if proxyType not in clientEntry:
logging.error('[%s] Builder receive unknown proxy type %s' % (self.id, proxyType))
raise buildException('Unknown proxy type')
self.proxyType = proxyType # proxy type -> ss / ssr / vmess ...
self.proxyInfo = Filter(proxyType, proxyInfo) # filter input proxy info
self.proxyInfo = copy.copy(proxyInfo) # connection info
self.socksAddr = bindAddr
self.socksPort = getAvailablePort() # random port for socks5 exposed
self.__loadClient()
def status(self) -> bool: # check if the sub process is still running
return self.__process.status()
def destroy(self) -> None: # kill sub process and remove config file
logging.debug('[%s] Builder destroy' % self.id)
self.__process.quit()
self.output = self.__process.output