diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml new file mode 100644 index 0000000000..681ecd963b --- /dev/null +++ b/docker-compose/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3" +name: pybitmessage +services: + bootstrap: + image: pybitmessage/bootstrap:latest + build: .. + env_file: .env + deploy: + replicas: $THREADS diff --git a/docker-compose/start-loadbalancer.sh b/docker-compose/start-loadbalancer.sh new file mode 100755 index 0000000000..32d5c1523f --- /dev/null +++ b/docker-compose/start-loadbalancer.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +apt -y install curl jq ipvsadm libyajl2 + +EXTIP=$(curl -s telnetmyip.com|jq -r .ip) +if [ ! -e .env ]; then + THREADS=$(nproc --all) + PASSWORD=$(tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo) + cat > .env << EOF +THREADS=$THREADS +PASSWORD=$PASSWORD +EOF +else + . .env +fi + +ipvsadm -C +ipvsadm -A -t ${EXTIP}:8444 -s rr +ipvsadm -A -t ${EXTIP}:8080 -s rr + +docker compose up -d + +CF=/etc/collectd/collectd.conf.d/curl_json.conf.new +CF_LIVE=/etc/collectd/collectd.conf.d/curl_json.conf + +echo "LoadPlugin curl_json" > $CF +echo "" >> $CF + +for i in `seq 1 $THREADS`; do + cont="pybitmessage-bootstrap-${i}" + IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $cont 2>/dev/null) + [ -z "$IP" ] && continue + echo "Adding $IP" + ipvsadm -a -t ${EXTIP}:8444 -r ${IP}:8444 -m + ipvsadm -a -t ${EXTIP}:8080 -r ${IP}:8444 -m + INSTANCE=$(echo $cont|tr - _) + cat >> $CF << EOF + + Plugin "pybitmessagestatus" + Instance "$INSTANCE" + User "api" + Password "$PASSWORD" + Post "{\"jsonrpc\":\"2.0\",\"id\":\"id\",\"method\":\"clientStatus\",\"params\":[]}" + + Type "gauge" + Instance "networkconnections" + + + Type "counter" + Instance "numberofpubkeysprocessed" + + + Type "counter" + Instance "numberofmessagesprocessed" + + + Type "counter" + Instance "numberofbroadcastsprocessed" + + +EOF +done +echo "" >> $CF + +if ! cmp -s $CF $CF_LIVE; then + mv $CF $CF_LIVE + systemctl restart collectd +fi + +ipvsadm -l -n diff --git a/packages/docker/launcher.sh b/packages/docker/launcher.sh index c0e4885586..1a876fec23 100755 --- a/packages/docker/launcher.sh +++ b/packages/docker/launcher.sh @@ -3,13 +3,15 @@ # Setup the environment for docker container APIUSER=${USER:-api} APIPASS=${PASSWORD:-$(tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo)} +IP=$(hostname -i) echo "\napiusername: $APIUSER\napipassword: $APIPASS" -sed -i -e "s|\(apiinterface = \).*|\10\.0\.0\.0|g" \ +sed -i -e "s|\(apiinterface = \).*|\1$IP|g" \ -e "s|\(apivariant = \).*|\1json|g" \ -e "s|\(apiusername = \).*|\1$APIUSER|g" \ -e "s|\(apipassword = \).*|\1$APIPASS|g" \ + -e "s|\(bind = \).*|\1$IP|g" \ -e "s|apinotifypath = .*||g" ${BITMESSAGE_HOME}/keys.dat # Run diff --git a/src/network/__init__.py b/src/network/__init__.py index 42e9d03530..fc804a5402 100644 --- a/src/network/__init__.py +++ b/src/network/__init__.py @@ -14,9 +14,7 @@ def start(config, state): import state from .announcethread import AnnounceThread import connectionpool # pylint: disable=relative-import - from .addrthread import AddrThread from .downloadthread import DownloadThread - from .invthread import InvThread from .networkthread import BMNetworkThread from .knownnodes import readKnownNodes from .receivequeuethread import ReceiveQueueThread @@ -30,7 +28,7 @@ def start(config, state): readKnownNodes() connectionpool.pool.connectToStream(1) for thread in ( - BMNetworkThread(), InvThread(), AddrThread(), + BMNetworkThread(), DownloadThread(), UploadThread() ): thread.daemon = True diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index d7062d2479..93fe766fca 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -70,6 +70,7 @@ def chooseConnection(stream): continue if rating > 1: rating = 1 + return peer try: if 0.05 / (1.0 - rating) > random.random(): # nosec B311 return peer diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 36c91c1854..161c505e49 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -56,7 +56,7 @@ def __init__(self): self.streams = [] self._lastSpawned = 0 self._spawnWait = 2 - self._bootstrapped = False + self._bootstrapped = True trustedPeer = config.safeGet( 'bitmessagesettings', 'trustedpeer') @@ -378,14 +378,13 @@ def loop(self): # pylint: disable=too-many-branches,too-many-statements for i in self.connections(): minTx = time.time() - 20 if i.fullyEstablished: - minTx -= 300 - 20 + minTx -= 60 - 20 if i.lastTx < minTx: - if i.fullyEstablished: - i.append_write_buf(protocol.CreatePacket('ping')) + if i.isOutbound: + i.close_reason = "Thank you for running a server" else: - i.close_reason = "Timeout (%is)" % ( - time.time() - i.lastTx) - i.set_state("close") + i.close_reason = "Have a nice day" + i.set_state("close") for i in ( self.connections() + self.listeningSockets.values() + self.udpSockets.values() diff --git a/src/network/tcp.py b/src/network/tcp.py index a739e256f3..0aabcbdf33 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -171,7 +171,7 @@ def set_connection_fully_established(self): self.streams, self.destination, time.time()) dandelion_ins.maybeAddStem(self, invQueue) self.sendAddr() - self.sendBigInv() + #self.sendBigInv() def sendAddr(self): """Send a partial list of known addresses to peer.""" @@ -195,7 +195,7 @@ def sendAddr(self): (k, v) for k, v in nodes.iteritems() if v["lastseen"] > int(time.time()) - maximumAgeOfNodesThatIAdvertiseToOthers - and v["rating"] >= 0 and not k.host.endswith('.onion') + and v["rating"] > 0.0 and not k.host.endswith('.onion') ] # sent 250 only if the remote isn't interested in it elemCount = min( @@ -300,6 +300,27 @@ def handle_close(self): knownnodes.decreaseRating(self.destination) BMProto.handle_close(self) + def bm_command_object(self): + return True + + def bm_command_getdata(self): + return True + + def bm_command_inv(self): + return True + + def bm_command_dinv(self): + return True + + def bm_command_addr(self): + return True + + def bm_command_portcheck(self): + return True + + @staticmethod + def bm_command_pong(): + return True class Socks5BMConnection(Socks5Connection, TCPConnection): """SOCKS5 wrapper for TCP connections"""