<commit_before>#!/usr/bin/env python
'''
    Stratum mining proxy
    Copyright (C) 2012 <NAME> <<EMAIL>>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import argparse
import time
import os
import sys
import socket
import threading

def parse_args():
    parser = argparse.ArgumentParser(description='This proxy allows you to run getwork-based miners against Stratum mining pool.')
    parser.add_argument('-o', '--host', dest='host', type=str, default='stratum.bitcoin.cz', help='Hostname of Stratum mining pool')
    parser.add_argument('-p', '--port', dest='port', type=int, default=3333, help='Port of Stratum mining pool')
    parser.add_argument('-sh', '--stratum-host', dest='stratum_host', type=str, default='0.0.0.0', help='On which network interface listen for stratum miners. Use "localhost" for listening on internal IP only.')
    parser.add_argument('-sp', '--stratum-port', dest='stratum_port', type=int, default=3333, help='Port on which port listen for stratum miners.')
    parser.add_argument('-cs', '--custom-stratum', dest='custom_stratum', type=str, help='Override URL provided in X-Stratum header')
    parser.add_argument('-cu', '--custom-user', dest='custom_user', type=str, help='Use this username for submitting shares')
    parser.add_argument('-cp', '--custom-password', dest='custom_password', type=str, help='Use this password for submitting shares')
    parser.add_argument('-xp', '--control-port', dest='control_port', type=int, default=3999, help='Control port')
    parser.add_argument('--dirty-ping', dest='dirty_ping', action='store_true', help='Use dirty ping method to check if the pool is alive (not recommended).')
    parser.add_argument('--timeout', dest='pool_timeout', type=int, default=120, help='Set pool timeout (in seconds).')
    parser.add_argument('--blocknotify', dest='blocknotify_cmd', type=str, default='', help='Execute command when the best block changes (%%s in BLOCKNOTIFY_CMD is replaced by block hash)')
    parser.add_argument('--sharenotify', dest='sharestats_module', type=str, default=None, help='Execute a python snippet when a share is accepted. Use absolute path (i.e /root/snippets/log.py)')
    parser.add_argument('--socks', dest='proxy', type=str, default='', help='Use socks5 proxy for upstream Stratum connection, specify as host:port')
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='Enable low-level debugging messages')
    parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help='Make output more quiet')
    parser.add_argument('-i', '--pid-file', dest='pid_file', type=str, help='Store process pid to the file')
    parser.add_argument('-l', '--log-file', dest='log_file', type=str, help='Log to specified file')
    parser.add_argument('-st', '--scrypt-target', dest='scrypt_target', action='store_true', help='Calculate targets for scrypt algorithm')
    return parser.parse_args()

from stratum import settings
settings.LOGLEVEL='INFO'

if __name__ == '__main__':
    # We need to parse args & setup Stratum environment
    # before any other imports
    args = parse_args()
    if args.quiet:
        settings.DEBUG = False
        settings.LOGLEVEL = 'WARNING'
    elif args.verbose:
        settings.DEBUG = True
        settings.LOGLEVEL = 'DEBUG'
    if args.log_file:
        settings.LOGFILE = args.log_file

from twisted.internet import reactor, defer
from stratum.socket_transport import SocketTransportFactory, SocketTransportClientFactory
from stratum.services import ServiceEventHandler
from twisted.web.server import Site

from mining_libs import stratum_listener
from mining_libs import client_service
from mining_libs import jobs
from mining_libs import version
from mining_libs import utils
from mining_libs import share_stats
import zmq
import stratum.logger

class StratumServer():
    shutdown = False
    log = None
    backup = ['mine.coinshift.com',3333]
    def __init__(self,args,st_listen):
        if args.pid_file:
            fp = file(args.pid_file, 'w')
            fp.write(str(os.getpid()))
            fp.close()
        self.log = stratum.logger.get_logger('proxy-%s'%args.stratum_port)
        st_listen.log = stratum.logger.get_logger('proxy-%s'%args.stratum_port)
        stp = StratumProxy(st_listen)
        stp.set_pool(args.host,args.port,args.custom_user,args.custom_password)
        stp.connect()
        threading.Thread(target=self.control,args=[stp,st_listen,args.control_port]).start()
        threading.Thread(target=self.watcher,args=[stp,st_listen]).start()

        # Setup stratum listener
        if args.stratum_port > 0:
            st_listen.StratumProxyService._set_stratum_proxy(stp)
            st_listen.StratumProxyService._set_sharestats_module(args.sharestats_module)
            reactor_listen = reactor.listenTCP(args.stratum_port, SocketTransportFactory(debug=False, event_handler=ServiceEventHandler), interface=args.stratum_host)
            reactor.addSystemEventTrigger('before', 'shutdown', self.on_shutdown, stp.f)
            self.log.warning("PROXY IS LISTENING ON ALL IPs ON PORT %d (stratum)" % (args.stratum_port))

    def on_shutdown(self,f):
        self.shutdown = True
        '''Clean environment properly'''
        self.log.info("Shutting down proxy...")
        f.is_reconnecting = False # Don't let stratum factory to reconnect again
        time.sleep(1)
        for thread in threading.enumerate():
            if thread.isAlive():
                try:
                    thread._Thread__stop()
                except:
                    self.log.error(str(thread.getName()) + ' could not be terminated')

    def control(self,stp,stl,port):
        z = zmq.Context()
        s = z.socket(zmq.REQ)
        self.log.info("Control port is %s" %port)
        s.bind("tcp://127.0.0.1:%s" %port)
        while not self.shutdown:
            s.send('READY')
            msg = s.recv()
            self.log.info("Control message received: %s" %msg)
            margs = msg.split()
            if margs[0] == 'setpool':
                # host, port, user, passw
                #stl.MiningSubscription.reconnect_all()
                if len(margs) == 3: stp.reconnect(margs[1],int(margs[2]))<commit_msg>Fix thread destroy when program exists<commit_after>#!/usr/bin/env python
'''
    Stratum mining proxy
    Copyright (C) 2012 <NAME> <<EMAIL>>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import argparse
import time
import os
import sys
import socket
import threading

def parse_args():
    parser = argparse.ArgumentParser(description='This proxy allows you to run getwork-based miners against Stratum mining pool.')
    parser.add_argument('-o', '--host', dest='host', type=str, default='stratum.bitcoin.cz', help='Hostname of Stratum mining pool')
    parser.add_argument('-p', '--port', dest='port', type=int, default=3333, help='Port of Stratum mining pool')
    parser.add_argument('-sh', '--stratum-host', dest='stratum_host', type=str, default='0.0.0.0', help='On which network interface listen for stratum miners. Use "localhost" for listening on internal IP only.')
    parser.add_argument('-sp', '--stratum-port', dest='stratum_port', type=int, default=3333, help='Port on which port listen for stratum miners.')
    parser.add_argument('-cs', '--custom-stratum', dest='custom_stratum', type=str, help='Override URL provided in X-Stratum header')
    parser.add_argument('-cu', '--custom-user', dest='custom_user', type=str, help='Use this username for submitting shares')
    parser.add_argument('-cp', '--custom-password', dest='custom_password', type=str, help='Use this password for submitting shares')
    parser.add_argument('-xp', '--control-port', dest='control_port', type=int, default=3999, help='Control port')
    parser.add_argument('--dirty-ping', dest='dirty_ping', action='store_true', help='Use dirty ping method to check if the pool is alive (not recommended).')
    parser.add_argument('--timeout', dest='pool_timeout', type=int, default=120, help='Set pool timeout (in seconds).')
    parser.add_argument('--blocknotify', dest='blocknotify_cmd', type=str, default='', help='Execute command when the best block changes (%%s in BLOCKNOTIFY_CMD is replaced by block hash)')
    parser.add_argument('--sharenotify', dest='sharestats_module', type=str, default=None, help='Execute a python snippet when a share is accepted. Use absolute path (i.e /root/snippets/log.py)')
    parser.add_argument('--socks', dest='proxy', type=str, default='', help='Use socks5 proxy for upstream Stratum connection, specify as host:port')
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='Enable low-level debugging messages')
    parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help='Make output more quiet')
    parser.add_argument('-i', '--pid-file', dest='pid_file', type=str, help='Store process pid to the file')
    parser.add_argument('-l', '--log-file', dest='log_file', type=str, help='Log to specified file')
    parser.add_argument('-st', '--scrypt-target', dest='scrypt_target', action='store_true', help='Calculate targets for scrypt algorithm')
    return parser.parse_args()

from stratum import settings
settings.LOGLEVEL='INFO'

if __name__ == '__main__':
    # We need to parse args & setup Stratum environment
    # before any other imports
    args = parse_args()
    if args.quiet:
        settings.DEBUG = False
        settings.LOGLEVEL = 'WARNING'
    elif args.verbose:
        settings.DEBUG = True
        settings.LOGLEVEL = 'DEBUG'
    if args.log_file:
        settings.LOGFILE = args.log_file

from twisted.internet import reactor, defer
from stratum.socket_transport import SocketTransportFactory, SocketTransportClientFactory
from stratum.services import ServiceEventHandler
from twisted.web.server import Site

from mining_libs import stratum_listener
from mining_libs import client_service
from mining_libs import jobs
from mining_libs import version
from mining_libs import utils
from mining_libs import share_stats
import zmq
import stratum.logger

class StratumServer():
    shutdown = False
    log = None
    backup = ['mine.coinshift.com',3333]
    def __init__(self,args,st_listen):
        if args.pid_file:
            fp = file(args.pid_file, 'w')
            fp.write(str(os.getpid()))
            fp.close()
        self.log = stratum.logger.get_logger('proxy-%s'%args.stratum_port)
        st_listen.log = stratum.logger.get_logger('proxy-%s'%args.stratum_port)
        stp = StratumProxy(st_listen)
        stp.set_pool(args.host,args.port,args.custom_user,args.custom_password)
        stp.connect()
        z = zmq.Context()
        control = threading.Thread(target=self.control,args=[stp,st_listen,args.control_port,z])
        watcher = threading.Thread(target=self.watcher,args=[stp,st_listen])
        control.daemon = True
        watcher.daemon = True
        control.start()
        watcher.start()
        # Setup stratum listener
        if args.stratum_port > 0:
            st_listen.StratumProxyService._set_stratum_proxy(stp)
            st_listen.StratumProxyService._set_sharestats_module(args.sharestats_module)
            reactor_listen = reactor.listenTCP(args.stratum_port, SocketTransportFactory(debug=False, event_handler=ServiceEventHandler), interface=args.stratum_host)
            reactor.addSystemEventTrigger('before', 'shutdown', self.on_shutdown, stp.f, z)
            self.log.warning("PROXY IS LISTENING ON ALL IPs ON PORT %d (stratum)" % (args.stratum_port))

    def on_shutdown(self,f,z):
        self.shutdown = True
        '''Clean environment properly'''
        self.log.info("Shutting down proxy...")
        f.is_reconnecting = False # Don't let stratum factory to reconnect again
        z.destroy()
        time.sleep(1)
        for thread in threading.enumerate():
            if thread.isAlive():
                try:
                    thread._Thread__stop()
                except:
                    self.log.error('Thread could not be terminated')

    def control(self,stp,stl,port,z):
        s = z.socket(zmq.REQ)
        self.log.info("Control port is %s" %port)
        s.bind("tcp://127.0.0.1:%s" %port)
        while not self.shutdown:
            try:
                s.send('READY')
            except Exception as e:
                if self.shutdown: break
                else: log.error("ZMQ error: %s" %e)

            msg = s.recv()
            self.log.info("Control message received: %s" %msg)
            margs = msg.split()
            if margs[0] == 'setpool':
                # host, port, user, passw
                #stl.MiningSubscription.reconnect_all()
                if len(margs) == 3: stp.reconnect(margs[1],int(margs[2]))
{'fraction_non_alphanumeric': 0.12167572204746926, 'fraction_numerical': 0.005862167572204747, 'mean_word_length': 3.479346781940442, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2919955', 'n_tokens_mistral': 4208, 'n_tokens_neox': 4059, 'n_words': 1145}