Wrote some docstrings #6
|
@ -20,7 +20,7 @@ cd MiNode
|
||||||
|
|
||||||
It is worth noting that the `start.sh` script no longer tries to do a
|
It is worth noting that the `start.sh` script no longer tries to do a
|
||||||
`git pull` in order to update to the latest version.
|
`git pull` in order to update to the latest version.
|
||||||
Is is now done by the `update.sh` script.
|
It is now done by the `update.sh` script.
|
||||||
|
|
||||||
## Command line
|
## Command line
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Common reusable code for all the I2P entities"""
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
|
||||||
def receive_line(s):
|
def receive_line(s):
|
||||||
|
"""Receive a line from the socket *s*"""
|
||||||
data = b''
|
data = b''
|
||||||
while b'\n' not in data:
|
while b'\n' not in data:
|
||||||
d = s.recv(4096)
|
d = s.recv(4096)
|
||||||
|
@ -36,6 +38,7 @@ class I2PThread(threading.Thread):
|
||||||
|
|
||||||
|
|
||||||
def pub_from_priv(priv):
|
def pub_from_priv(priv):
|
||||||
|
"""Returns the public key for the private key *priv*"""
|
||||||
priv = base64.b64decode(priv, altchars=b'-~')
|
priv = base64.b64decode(priv, altchars=b'-~')
|
||||||
# 256 for public key + 128 for signing key + 3 for certificate header
|
# 256 for public key + 128 for signing key + 3 for certificate header
|
||||||
# + value of bytes priv[385:387]
|
# + value of bytes priv[385:387]
|
||||||
|
@ -44,6 +47,7 @@ def pub_from_priv(priv):
|
||||||
|
|
||||||
|
|
||||||
def b32_from_pub(pub):
|
def b32_from_pub(pub):
|
||||||
|
"""Converts the public key *pub* to base32 host name"""
|
||||||
return base64.b32encode(
|
return base64.b32encode(
|
||||||
hashlib.sha256(base64.b64decode(pub, b'-~')).digest()
|
hashlib.sha256(base64.b64decode(pub, b'-~')).digest()
|
||||||
).replace(b'=', b'').lower() + b'.b32.i2p'
|
).replace(b'=', b'').lower() + b'.b32.i2p'
|
||||||
|
|
|
@ -62,6 +62,7 @@ class Manager(threading.Thread):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clean_objects():
|
def clean_objects():
|
||||||
|
"""Remove expired objects"""
|
||||||
for vector in set(shared.objects):
|
for vector in set(shared.objects):
|
||||||
# FIXME: no need to check is_valid() here
|
# FIXME: no need to check is_valid() here
|
||||||
if shared.objects[vector].is_expired():
|
if shared.objects[vector].is_expired():
|
||||||
|
@ -176,7 +177,7 @@ class Manager(threading.Thread):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_data():
|
def load_data():
|
||||||
"""Loads initial nodes and data, stored in files between sessions"""
|
"""Load initial nodes and data, stored in files between sessions"""
|
||||||
try:
|
try:
|
||||||
with open(
|
with open(
|
||||||
os.path.join(shared.data_directory, 'objects.pickle'), 'br'
|
os.path.join(shared.data_directory, 'objects.pickle'), 'br'
|
||||||
|
@ -229,6 +230,7 @@ class Manager(threading.Thread):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def pickle_objects():
|
def pickle_objects():
|
||||||
|
"""Save objects into a file objects.pickle in the data directory"""
|
||||||
try:
|
try:
|
||||||
with open(
|
with open(
|
||||||
os.path.join(shared.data_directory, 'objects.pickle'), 'bw'
|
os.path.join(shared.data_directory, 'objects.pickle'), 'bw'
|
||||||
|
@ -241,6 +243,7 @@ class Manager(threading.Thread):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def pickle_nodes():
|
def pickle_nodes():
|
||||||
|
"""Save nodes into files in the data directory"""
|
||||||
if len(shared.node_pool) > 10000:
|
if len(shared.node_pool) > 10000:
|
||||||
shared.node_pool = set(random.sample(
|
shared.node_pool = set(random.sample(
|
||||||
tuple(shared.node_pool), 10000))
|
tuple(shared.node_pool), 10000))
|
||||||
|
@ -270,6 +273,7 @@ class Manager(threading.Thread):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def publish_i2p_destination():
|
def publish_i2p_destination():
|
||||||
|
"""Make and publish a special object, containing the I2P destination"""
|
||||||
if shared.i2p_session_nick and not shared.i2p_transient:
|
if shared.i2p_session_nick and not shared.i2p_transient:
|
||||||
logging.info('Publishing our I2P destination')
|
logging.info('Publishing our I2P destination')
|
||||||
dest_pub_raw = base64.b64decode(
|
dest_pub_raw = base64.b64decode(
|
||||||
|
|
|
@ -4,11 +4,28 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
from . import shared, structure
|
from . import shared, structure
|
||||||
|
|
||||||
|
|
||||||
class Header():
|
class IMessage(ABC):
|
||||||
|
"""A base for typical message"""
|
||||||
|
@abstractmethod
|
||||||
|
def __repr__(self):
|
||||||
|
"""Make a printable form"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def to_bytes(self):
|
||||||
|
"""Serialize to bytes the full message"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@abstractmethod
|
||||||
|
def from_message(cls, m):
|
||||||
|
"""Parse from message"""
|
||||||
|
|
||||||
|
|
||||||
|
class Header(structure.IStructure):
|
||||||
"""Message header structure"""
|
"""Message header structure"""
|
||||||
def __init__(self, command, payload_length, payload_checksum):
|
def __init__(self, command, payload_length, payload_checksum):
|
||||||
self.command = command
|
self.command = command
|
||||||
|
@ -24,7 +41,6 @@ class Header():
|
||||||
base64.b16encode(self.payload_checksum).decode())
|
base64.b16encode(self.payload_checksum).decode())
|
||||||
|
|
||||||
def to_bytes(self):
|
def to_bytes(self):
|
||||||
"""Serialize to bytes"""
|
|
||||||
b = b''
|
b = b''
|
||||||
b += shared.magic_bytes
|
b += shared.magic_bytes
|
||||||
b += self.command.ljust(12, b'\x00')
|
b += self.command.ljust(12, b'\x00')
|
||||||
|
@ -34,7 +50,6 @@ class Header():
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bytes(cls, b):
|
def from_bytes(cls, b):
|
||||||
"""Parse from bytes"""
|
|
||||||
magic_bytes, command, payload_length, payload_checksum = struct.unpack(
|
magic_bytes, command, payload_length, payload_checksum = struct.unpack(
|
||||||
'>4s12sL4s', b)
|
'>4s12sL4s', b)
|
||||||
|
|
||||||
|
@ -46,7 +61,7 @@ class Header():
|
||||||
return cls(command, payload_length, payload_checksum)
|
return cls(command, payload_length, payload_checksum)
|
||||||
|
|
||||||
|
|
||||||
class Message():
|
class Message(structure.IStructure):
|
||||||
"""Common message structure"""
|
"""Common message structure"""
|
||||||
def __init__(self, command, payload):
|
def __init__(self, command, payload):
|
||||||
self.command = command
|
self.command = command
|
||||||
|
@ -61,7 +76,6 @@ class Message():
|
||||||
base64.b16encode(self.payload_checksum).decode())
|
base64.b16encode(self.payload_checksum).decode())
|
||||||
|
|
||||||
def to_bytes(self):
|
def to_bytes(self):
|
||||||
"""Serialize to bytes"""
|
|
||||||
b = Header(
|
b = Header(
|
||||||
self.command, self.payload_length, self.payload_checksum
|
self.command, self.payload_length, self.payload_checksum
|
||||||
).to_bytes()
|
).to_bytes()
|
||||||
|
@ -70,7 +84,6 @@ class Message():
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bytes(cls, b):
|
def from_bytes(cls, b):
|
||||||
"""Parse from bytes"""
|
|
||||||
h = Header.from_bytes(b[:24])
|
h = Header.from_bytes(b[:24])
|
||||||
|
|
||||||
payload = b[24:]
|
payload = b[24:]
|
||||||
|
@ -98,7 +111,7 @@ def _payload_read_int(data):
|
||||||
data[varint_length:])
|
data[varint_length:])
|
||||||
|
|
||||||
|
|
||||||
class Version():
|
class Version(IMessage):
|
||||||
"""The version message payload"""
|
"""The version message payload"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self, host, port, protocol_version=shared.protocol_version,
|
self, host, port, protocol_version=shared.protocol_version,
|
||||||
|
@ -179,7 +192,7 @@ class Version():
|
||||||
host, port, protocol_version, services, nonce, user_agent, streams)
|
host, port, protocol_version, services, nonce, user_agent, streams)
|
||||||
|
|
||||||
|
|
||||||
class Inv():
|
class Inv(IMessage):
|
||||||
"""The inv message payload"""
|
"""The inv message payload"""
|
||||||
def __init__(self, vectors):
|
def __init__(self, vectors):
|
||||||
self.vectors = set(vectors)
|
self.vectors = set(vectors)
|
||||||
|
@ -211,7 +224,7 @@ class Inv():
|
||||||
return cls(vectors)
|
return cls(vectors)
|
||||||
|
|
||||||
|
|
||||||
class GetData():
|
class GetData(IMessage):
|
||||||
"""The getdata message payload"""
|
"""The getdata message payload"""
|
||||||
def __init__(self, vectors):
|
def __init__(self, vectors):
|
||||||
self.vectors = set(vectors)
|
self.vectors = set(vectors)
|
||||||
|
@ -243,7 +256,7 @@ class GetData():
|
||||||
return cls(vectors)
|
return cls(vectors)
|
||||||
|
|
||||||
|
|
||||||
class Addr():
|
class Addr(IMessage):
|
||||||
"""The addr message payload"""
|
"""The addr message payload"""
|
||||||
def __init__(self, addresses):
|
def __init__(self, addresses):
|
||||||
self.addresses = addresses
|
self.addresses = addresses
|
||||||
|
@ -273,7 +286,7 @@ class Addr():
|
||||||
return cls(addresses)
|
return cls(addresses)
|
||||||
|
|
||||||
|
|
||||||
class Error():
|
class Error(IMessage):
|
||||||
"""The error message payload"""
|
"""The error message payload"""
|
||||||
def __init__(self, error_text=b'', fatal=0, ban_time=0, vector=b''):
|
def __init__(self, error_text=b'', fatal=0, ban_time=0, vector=b''):
|
||||||
self.error_text = error_text
|
self.error_text = error_text
|
||||||
|
|
|
@ -50,5 +50,10 @@ def _worker(obj):
|
||||||
|
|
||||||
|
|
||||||
def do_pow_and_publish(obj):
|
def do_pow_and_publish(obj):
|
||||||
|
"""
|
||||||
|
Start a worker thread, doing PoW for the given object
|
||||||
|
and putting a new object and its vector into appropriate places in `shared`
|
||||||
|
to advertize to the network.
|
||||||
|
"""
|
||||||
t = threading.Thread(target=_worker, args=(obj, ))
|
t = threading.Thread(target=_worker, args=(obj, ))
|
||||||
t.start()
|
t.start()
|
||||||
|
|
|
@ -6,11 +6,24 @@ import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
from . import shared
|
from . import shared
|
||||||
|
|
||||||
|
|
||||||
class VarInt():
|
class IStructure(ABC):
|
||||||
|
"""A base for typical structure"""
|
||||||
|
@abstractmethod
|
||||||
|
def to_bytes(self):
|
||||||
|
"""Serialize to bytes"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@abstractmethod
|
||||||
|
def from_bytes(cls, b):
|
||||||
|
"""Parse from bytes"""
|
||||||
|
|
||||||
|
|
||||||
|
class VarInt(IStructure):
|
||||||
"""varint object"""
|
"""varint object"""
|
||||||
def __init__(self, n):
|
def __init__(self, n):
|
||||||
self.n = n
|
self.n = n
|
||||||
|
@ -29,6 +42,7 @@ class VarInt():
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def length(b):
|
def length(b):
|
||||||
|
"""Get the varint length"""
|
||||||
if b == 0xfd:
|
if b == 0xfd:
|
||||||
return 3
|
return 3
|
||||||
if b == 0xfe:
|
if b == 0xfe:
|
||||||
|
@ -87,7 +101,7 @@ class Object():
|
||||||
nonce, expires_time, object_type, version, stream_number, payload)
|
nonce, expires_time, object_type, version, stream_number, payload)
|
||||||
|
|
||||||
def to_bytes(self):
|
def to_bytes(self):
|
||||||
"""Serialize to bytes"""
|
"""Serialize to bytes object payload"""
|
||||||
payload = b''
|
payload = b''
|
||||||
payload += self.nonce
|
payload += self.nonce
|
||||||
payload += struct.pack('>QL', self.expires_time, self.object_type)
|
payload += struct.pack('>QL', self.expires_time, self.object_type)
|
||||||
|
@ -151,7 +165,7 @@ class Object():
|
||||||
return hashlib.sha512(self.to_bytes()[8:]).digest()
|
return hashlib.sha512(self.to_bytes()[8:]).digest()
|
||||||
|
|
||||||
|
|
||||||
class NetAddrNoPrefix():
|
class NetAddrNoPrefix(IStructure):
|
||||||
"""Network address"""
|
"""Network address"""
|
||||||
def __init__(self, services, host, port):
|
def __init__(self, services, host, port):
|
||||||
self.services = services
|
self.services = services
|
||||||
|
@ -199,7 +213,7 @@ class NetAddrNoPrefix():
|
||||||
return cls(services, host, port)
|
return cls(services, host, port)
|
||||||
|
|
||||||
|
|
||||||
class NetAddr():
|
class NetAddr(IStructure):
|
||||||
"""Network address with time and stream"""
|
"""Network address with time and stream"""
|
||||||
def __init__(self, services, host, port, stream=shared.stream):
|
def __init__(self, services, host, port, stream=shared.stream):
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
|
|
Loading…
Reference in New Issue
Block a user