-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommunity.py
100 lines (73 loc) · 3.24 KB
/
community.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from binascii import unhexlify
from collections import defaultdict
from pyipv8.ipv8.community import Community
from pyipv8.ipv8.keyvault.crypto import default_eccrypto
from pyipv8.ipv8.lazy_community import lazy_wrapper, lazy_wrapper_wd
from pyipv8.ipv8.messaging.lazy_payload import vp_compile, VariablePayload
from pyipv8.ipv8.messaging.payload_headers import BinMemberAuthenticationPayload
from pyipv8.ipv8.peer import Peer
from pyipv8.ipv8.peerdiscovery.network import Network
@vp_compile
class ChatMessage(VariablePayload):
msg_id = 1
names = ["message"]
format_list = ["varlenH"]
@vp_compile
class FwdMessage(VariablePayload):
msg_id = 2
names = ["forwarded"]
format_list = ["varlenH"]
class IPv8ChatCommunity(Community):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.message_callback = lambda public_key_bin, message: None
self.fwd_map = defaultdict(set)
self.add_message_handler(ChatMessage, self._on_message)
self.add_message_handler(FwdMessage, self.on_fwd_message)
async def unload(self):
await super().unload()
self.endpoint.close()
def set_message_callback(self, callback):
self.message_callback = callback
def send_message(self, message: str):
try:
payload = ChatMessage(message[:250].encode())
for peer in self.get_peers():
self.ez_send(peer, payload)
except:
import traceback
traceback.print_exc()
self.logger.error("Failed to send message!")
def fwd_message(self, data):
msg_sig = data[-32:]
fwd_group = set(self.get_peers()) - self.fwd_map[msg_sig]
for peer in fwd_group:
fwd = self.fwd_map[msg_sig]
fwd.add(peer)
self.fwd_map[msg_sig] = fwd
self.ez_send(peer, FwdMessage(data))
def on_message(self, peer_pk, payload, data):
message = payload.message.decode()
msg_sig = data[-32:]
if msg_sig not in self.fwd_map:
self.message_callback(peer_pk, message)
self.fwd_message(data)
@lazy_wrapper_wd(ChatMessage)
def _on_message(self, peer, payload, data):
self.on_message(peer.public_key.key_to_bin(), payload, data)
@lazy_wrapper(FwdMessage)
def on_fwd_message(self, peer, payload):
auth, _ = self.serializer.unpack_serializable(BinMemberAuthenticationPayload, payload.forwarded, offset=23)
signature_valid, remainder = self._verify_signature(auth, payload.forwarded)
fwdpayload, = self.serializer.unpack_serializable_list([ChatMessage], remainder, offset=23)
self.on_message(auth.public_key_bin, fwdpayload, payload.forwarded)
def send_ping(self, peer):
self.send_introduction_request(peer)
async def produce_community(ipv8, prefix):
assert isinstance(prefix, str)
assert len(prefix) == 40
b_prefix = unhexlify(prefix)
my_peer = Peer(default_eccrypto.generate_key("curve25519"))
endpoint = await ipv8.produce_anonymized_endpoint()
community_instance = type("IPv8ChatCommunity-%s" % prefix, (IPv8ChatCommunity, ), {"community_id": b_prefix})
return community_instance(my_peer, endpoint, Network(), max_peers=200, anonymize=True)