Skip to content
Snippets Groups Projects
Commit 02857de3 authored by Johannes Hitzinger's avatar Johannes Hitzinger
Browse files

started with connection.py

right now separating stuff with docker
parent 6cca1a8e
No related branches found
No related tags found
No related merge requests found
# this is a dummy for a Distributed Hash Table offered and used by the Bittorrent network, for simplicity and keeping a closed test environment i have decided against using a real DHT
import ipaddress
import socket
from fastapi import APIRouter
import uvicorn
from fastapi import APIRouter, FastAPI
import jsonpickle
from collections import defaultdict
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
try:
# doesn't even have to be reachable
s.connect(('10.254.254.254', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
class DHTdummy:
def __init__(self):
self.peers_ip: defaultdict[str:set[ipaddress.IPv4Address]] = defaultdict(set)
......@@ -12,12 +29,19 @@ class DHTdummy:
self.fastRouter.add_api_route("/getPeersFor/{pool}", self.getPeersFor, methods=["GET"])
self.fastRouter.add_api_route("/addPeerTo/{pool}", self.addPeerTo, methods=["PUT"])
async def getPeersFor(self, pool:str):
async def getPeersFor(self, pool: str):
return jsonpickle.encode(self.peers_ip[pool])
async def addPeerTo(self, pool:str, ip:str):
async def addPeerTo(self, pool: str, ip: str):
if ip:
if pool in self.peers_ip:
self.peers_ip[pool].add(ipaddress.IPv4Address(ip))
else:
self.peers_ip[pool] = {ipaddress.IPv4Address(ip)}
\ No newline at end of file
self.peers_ip[pool] = {ipaddress.IPv4Address(ip)}
if __name__ == "__main__":
fast_app = FastAPI()
dht = DHTdummy()
fast_app.include_router(dht.fastRouter)
uvicorn.run(fast_app, host=get_ip(), port=8000)
@startuml
class Participant{
- secretKey
+ publicKey
+ publicIP
+ updateRemoteParticipants(new_rps)
+ findOffers(power, time)
+ findRequests(power, time)
}
class RemoteParticipant{
+ publicKey
+ publicIP
+ updateExchanges(new_exs)
}
abstract class Exchange{
power: Watt
pricePerWatt: Euro
}
class Trade {
+ power: Watt
+ pricePerWatt: Euro
+ signature_offer
+ signature_request
+ verify_trade()
}
class Offer
class Request
Exchange <|-- Offer
Exchange <|-- Request
Participant "0..n" - RemoteParticipant
RemoteParticipant "0..n" - Exchange
Trade "1..1" - "n..1" Offer
Trade "1..1" - "n..1" Request
Trade "2" - Trade
@enduml
\ No newline at end of file
import jsonpickle
from dilithium import Dilithium
import dilithium.dilithium
import numpy
from random import randint
import jsonpickle
from fastapi import APIRouter
import logging
logger = logging.getLogger(__name__)
class Connection:
def __init__(self, cap: float):
self.dil = Dilithium(dilithium.dilithium.DEFAULT_PARAMETERS["dilithium3"])
self.__secretKey, self.__publicKey = self.dil.keygen(
[randint(0, numpy.iinfo('uint32').max), randint(0, numpy.iinfo('uint32').max),
randint(0, numpy.iinfo('uint32').max), randint(0, numpy.iinfo('uint32').max)])
self.fastRouter = APIRouter()
self.adjacentConnections: set[Connection] = set()
self.availableCapacity = cap
self.usedCapacity = 0
self.fastRouter.add_api_route("/addConnection", self.addConnection, methods=["POST"])
self.fastRouter.add_api_route("/getConnections", self.getConnections, methods=["GET"])
self.fastRouter.add_api_route("/announceTrade", self.announceTrade, methods=["POST"])
async def addConnection(self, con: 'Connection'):
self.adjacentConnections.add(jsonpickle.decode(con))
async def getConnections(self):
return jsonpickle.encode(self.adjacentConnections)
async def announceTrade(self, trade: 'Trade'):
pass
FROM python:3.12
# Or any preferred Python version.
ADD main.py exchange.py offer.py participant.py request.py trade.py remoteparticipant.py DHTdummy.py settings.py .
RUN pip install numpy pint fastapi uvicorn dilithium jsonpickle requests httpx apscheduler
CMD ["python", "./main.py"]
ADD main.py exchange.py offer.py participant.py request.py trade.py remoteparticipant.py DHTdummy.py settings.py connection.py .
RUN pip install numpy pint fastapi uvicorn dilithium jsonpickle requests httpx apscheduler rustworkx
CMD ["python", "./DHTdummy.py"]
# Or enter the name of your unique directory and parameter set.
\ No newline at end of file
......@@ -16,25 +16,25 @@ services:
ipv4_address: 172.20.0.2
ports:
- 8002:8000
build: .
build: ./DHTdummy/dockerfile
test3:
networks:
network1:
ipv4_address: 172.20.0.3
ports:
- 8003:8000
build: .
build: /home/jonny0815/git/dismagr/participant/dockerfile
test4:
networks:
network1:
ipv4_address: 172.20.0.4
ports:
- 8004:8000
build: .
build: /home/jonny0815/git/dismagr/participant/dockerfile
test5:
networks:
network1:
ipv4_address: 172.20.0.5
ports:
- 8005:8000
build: .
\ No newline at end of file
build: /home/jonny0815/git/dismagr/participant/dockerfile
\ No newline at end of file
# from main import ureg, Q_
import locale
import time
from contextlib import asynccontextmanager
from datetime import datetime, timedelta
from random import randint
......@@ -8,7 +9,12 @@ import ipaddress
import asyncio
import httpx
import rustworkx as rx
import jsonpickle
import uvicorn
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from dilithium import Dilithium
import dilithium.dilithium
......@@ -18,10 +24,11 @@ from offer import Offer
from request import Request
from exchange import Exchange
from trade import Trade
from connection import Connection
from remoteparticipant import RemoteParticipant
from fastapi import APIRouter
from fastapi import APIRouter, FastAPI
import logging
logger = logging.getLogger(__name__)
......@@ -44,8 +51,8 @@ def get_pub_ip():
class Participant:
def __init__(self, nid: str, dht_ep: set[ipaddress.IPv4Address],
ip: ipaddress = get_pub_ip()):
def __init__(self, nid: str, dht_ep: set[ipaddress.IPv4Address], conIP: ipaddress.IPv4Address,
ip: ipaddress = get_pub_ip(), ):
self.dil = Dilithium(dilithium.dilithium.DEFAULT_PARAMETERS["dilithium3"])
self.__secretKey, self.__publicKey = self.dil.keygen(
[randint(0, numpy.iinfo('uint32').max), randint(0, numpy.iinfo('uint32').max),
......@@ -55,11 +62,13 @@ class Participant:
self.__dht_network_id = nid
self.publicIP: ipaddress.IPv4Address = ipaddress.IPv4Address(
ip) # set to current ipv4, confirm before each new round
self.connection: Connection = self.buildOwnConnection(conIP)
self.grid = rx.PyGraph()
self.knownIPs: set[ipaddress.IPv4Address] = set()
self.remoteParticipants: set[RemoteParticipant] = set()
self.availableExchanges: set[
Exchange] = set() # known available exchanges from other participants for next turns
self.nextExchange: Request|Offer # own exchange for next turn, either offering or requesting energy
self.nextExchange: Request | Offer # own exchange for next turn, either offering or requesting energy
self.activeTrades: set[Trade] = set() # own active trades for this turn
self.__tradeHistory: list[Trade] = [] # every own past trade
# self.__currentPower = Q_(0, ureg.watt) # real time power exchange with the grid
......@@ -106,13 +115,12 @@ class Participant:
def update_remoteparticipants(self, new_rps: set[RemoteParticipant], target_rps: set[RemoteParticipant]):
for new_rp in new_rps:
for rp in target_rps:
if new_rp.publicKey == rp.publicKey: # found same participant
rp.
if new_rp.publicKey == rp.publicKey: # found same participant
pass # TODO
async def requestremoteParticipants(self) -> None:
all_remoteparticipants: set[RemoteParticipant] = set()
if len(self.remoteParticipants) == 0: # initial discovery via dht
if len(self.remoteParticipants) == 0: # initial discovery via dht
await self.dht_update_peers()
for ip in self.knownIPs:
try:
......@@ -129,8 +137,40 @@ class Participant:
self.remoteParticipants.update(all_remoteparticipants)
self.knownIPs.clear()
return
else: # continued peer updates without dht, periodic dht discovery should still happen to discover new users
else: # continued peer updates without dht, periodic dht discovery should still happen to discover new users
pass # TODO
async def get_knownIPs(self):
return jsonpickle.encode(self.knownIPs)
def buildOwnConnection(self, conIP: ipaddress.IPv4Address) -> Connection:
return Connection(0) # TODO get remoteConnection from Connection with conIP
if __name__ == "__main__":
jobstores = {
'default': MemoryJobStore()
}
scheduler = AsyncIOScheduler(jobstores=jobstores, timezone='Europe/Berlin')
logging.basicConfig(
level=logging.INFO,
handlers=[
logging.StreamHandler()
]
)
logger = logging.getLogger('uvicorn')
@asynccontextmanager
async def lifespan(app: FastAPI):
scheduler.start()
yield
scheduler.shutdown()
fast_app = FastAPI(lifespan=lifespan)
part = Participant(nid="test_network", dht_ep={ipaddress.IPv4Address('172.20.0.2')},
conIP=ipaddress.IPv4Address('172.20.1.1'))
scheduler.add_job(part.requestremoteParticipants, 'interval', seconds=20, id='1', name='requestRemoteParticipants' )
fast_app.include_router(part.fastRouter)
uvicorn.run(fast_app, host=get_pub_ip(), port=8000)
FROM python:3.12
# Or any preferred Python version.
ADD main.py exchange.py offer.py participant.py request.py trade.py remoteparticipant.py DHTdummy.py settings.py connection.py .
RUN pip install numpy pint fastapi uvicorn dilithium jsonpickle requests httpx apscheduler rustworkx
CMD ["python", "./participant.py"]
# Or enter the name of your unique directory and parameter set.
\ No newline at end of file
......@@ -19,7 +19,7 @@ class RemoteParticipant:
for ex in self.nextExchanges:
# both exchanges origin from same participant and are within the next minute
if new_ex.pubicKey == ex.pubicKey and new_ex.is_min_next() and ex.is_min_next():
ex.
pass
......
......@@ -11,6 +11,7 @@ let
python-pkgs.requests
python-pkgs.httpx
python-pkgs.apscheduler
python-pkgs.rustworkx
(python-pkgs.callPackage ./dilithium.nix { })
]);
in
......
#from main import ureg,Q_
# from main import ureg,Q_
import locale
import time
import offer
import request
import rustworkx as rx
class Trade:
def __init__(self, o: offer.Offer, r: request.Request, p: float, ppw: float):
def __init__(self, o: offer.Offer, r: request.Request, p: float, ppw: float, route: rx.PyGraph):
self.__timestamp = time.time_ns()
self.__offer: offer.Offer = o
self.__request: request.Request = r
#self.__power = Q_(p, ureg.watt)
self.__route = route
# self.__power = Q_(p, ureg.watt)
self.__pricePerWatt = locale.currency(ppw)
self.sig_off: bytes
self.sig_req: bytes
\ No newline at end of file
self.sig_req: bytes
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment