from abc import ABC from typing import TypeVar, Generic, List, Optional from tudelft.utilities.listener.Listenable import Listenable from uri.uri import URI from geniusweb.references.Reference import Reference INTYPE = TypeVar('INTYPE') OUTTYPE = TypeVar('OUTTYPE') class ConnectionEnd(Listenable[INTYPE], Generic[INTYPE,OUTTYPE]): ''' One end of a general two-way connection. incoming data is reported through the {@link Listenable} channel, sending events of the INTYPE.

The connection mechanism assumed here is fundamentally asymmetric. One side is "Connectable", the other side is a ConnectionEnd created (usually from a {@link Reference}. This matches the typical client-server system (web architecture).

If an internal error occurs, eg a socket failure, timeout, or parser error, a null event is sent into the Listenable. {@link #getError()} can be called to find out about the error. @param the type of incoming messages (incoming for the user of this connection end). Incoming messages are received through Listener#not. Incoming messages are usually asynchronous. @param the type of outgoing messages (outgoing for the user of this connection end). Outgoing messages can be sent directly with #send. ''' def send(self,data:OUTTYPE ): ''' Send data out (and flush the output so that there are no excessive delays in sending the data). This call is assumed to return immediately (never block, eg on synchronized, Thread.sleep, IO, etc). When this is called multiple times in sequence, the data should arrive at the receiver end in the same order. @param data the data to be sent. @throws ConnectionError if the data failed to be sent. ''' def getReference(self) -> Reference: ''' @return Reference that was used to create this connection ''' def getRemoteURI(self)->URI: ''' @return the URI of the remote endpoint that makes up the connection. This is a URI that uniquely identifies the remote object. ''' def close(self): ''' Close the connection. Should return immediately (not block). Before really closing, this should attempt to send out possibly cached messages before closing the connection. ''' def getError(self) -> Optional[Exception]: ''' @return the latest internal error, or null if no error occured. If the channel is closed, this is set to {@link SocketException} "Socket closed", even if the close was a "normal" termination eg when {@link #close()} was called. '''