## Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending#from__future__importannotationsfromabcimportABC,abstractmethodfromtypingimportOptionalfromuuidimportuuid4frompydeephaven.dherrorimportDHErrorfromdeephaven_core.protoimportticket_pb2
[docs]classTicket(ABC):"""A Ticket references an object on the server. """_ticket_bytes:bytes@abstractmethoddef__init__(self,ticket_bytes:bytes):self._ticket_bytes=ticket_bytes@propertydefbytes(self)->bytes:""" Returns the ticket as raw bytes. """returnself._ticket_bytes@propertydefpb_ticket(self)->ticket_pb2.Ticket:""" Returns the ticket as a gRPC protobuf ticket. """returnticket_pb2.Ticket(ticket=self._ticket_bytes)
[docs]classSharedTicket(Ticket):""" A SharedTicket is a ticket that can be shared with other sessions. """def__init__(self,ticket_bytes:bytes):"""Initializes a SharedTicket. Args: ticket_bytes (bytes): the raw bytes for the ticket """ifnotticket_bytes:raiseDHError('SharedTicket: ticket_bytes is None')elifnotticket_bytes.startswith(b'h'):raiseDHError(f'SharedTicket: ticket {ticket_bytes} is not a shared ticket')super().__init__(ticket_bytes)
[docs]@classmethoddefrandom_ticket(cls)->SharedTicket:"""Generates a random shared ticket. To minimize the probability of collision, the ticket is made from a generated UUID. Returns: a SharedTicket """bytes_=uuid4().int.to_bytes(16,byteorder='little',signed=False)returncls(ticket_bytes=b'h'+bytes_)
[docs]classExportTicket(Ticket):"""An ExportTicket is a ticket that references an object exported from the server such as a table or a plugin widget. An exported server object will remain available on the server until the ticket is released or the session is closed. Many types of server objects are exportable and can be fetched to the client as an export ticket or as an instance of wrapper class (such as :class:`~.table.Table`, :class:`~.plugin_client.PluginClient`, etc.) that wraps the export ticket. An export ticket can be published to a :class:`.SharedTicket` so that the exported server object can be shared with other sessions. Note: Users should not create ExportTickets directly. They are managed by the Session and are automatically created when exporting objects from the server via. :meth:`.Session.open_table`, :meth:`.Session.fetch`, and any operations that return a Table. """def__init__(self,ticket_bytes:bytes):"""Initializes an ExportTicket. Args: ticket_bytes (bytes): the raw bytes for the ticket """ifnotticket_bytes:raiseDHError('ExportTicket: ticket is None')elifnotticket_bytes.startswith(b'e'):raiseDHError(f'ExportTicket: ticket {ticket_bytes} is not an export ticket')super().__init__(ticket_bytes)
[docs]@classmethoddefexport_ticket(cls,ticket_no:int)->ExportTicket:"""Creates an export ticket from a ticket number. Args: ticket_no (int): the export ticket number Returns: an ExportTicket """ticket_bytes=ticket_no.to_bytes(4,byteorder='little',signed=True)returncls(b'e'+ticket_bytes)
[docs]classScopeTicket(Ticket):"""A ScopeTicket is a ticket that references a scope variable on the server. Scope variables are variables in the global scope of the server and are accessible to all sessions. Scope variables can be fetched to the client as an export ticket or a Deephaven :class:`~.table.Table` that wraps the export ticket. """def__init__(self,ticket_bytes:bytes):"""Initializes a ScopeTicket. Args: ticket_bytes (bytes): the raw bytes for the ticket """ifnotticket_bytes:raiseDHError('ScopeTicket: ticket is None')elifnotticket_bytes.startswith(b's/'):raiseDHError(f'ScopeTicket: ticket {ticket_bytes} is not a scope ticket')super().__init__(ticket_bytes)
[docs]@classmethoddefscope_ticket(cls,name:str)->ScopeTicket:"""Creates a scope ticket that references a scope variable by name. Args: name (str): the name of the scope variable Returns: a ScopeTicket """ifnotname:raiseDHError('scope_ticket: name must be a non-empty string')returncls(ticket_bytes=f's/{name}'.encode(encoding='ascii'))
[docs]classApplicationTicket(Ticket):"""An ApplicationTicket is a ticket that references a field of an application on the server. Please refer to the documentation on 'Application Mode' for detailed information on applications and their use cases."""def__init__(self,ticket_bytes:bytes):"""Initializes an ApplicationTicket. Args: ticket_bytes (bytes): the raw bytes for the ticket """ifnotticket_bytes:raiseDHError('ApplicationTicket: ticket is None')elifnotticket_bytes.startswith(b'a/'):raiseDHError(f'ApplicationTicket: ticket {ticket_bytes} is not an application ticket')eliflen(ticket_bytes.split(b'/'))!=4:raiseDHError(f'ApplicationTicket: ticket {ticket_bytes} is not in the correct format')self.app_id=ticket_bytes.split(b'/')[1].decode(encoding='ascii')self.field=ticket_bytes.split(b'/')[3].decode(encoding='ascii')super().__init__(ticket_bytes)
[docs]@classmethoddefapp_ticket(cls,app_id:str,field:str)->ApplicationTicket:"""Creates an application ticket that references a field of an application. Args: app_id (str): the application id field (str): the name of the application field Returns: an ApplicationTicket """ifnotapp_id:raiseDHError('app_ticket: app_id must be a non-empty string')ifnotfield:raiseDHError('app_ticket: field must be a non-empty string')returncls(ticket_bytes=f'a/{app_id}/f/{field}'.encode(encoding='ascii'))
def_ticket_from_proto(ticket:ticket_pb2.Ticket)->Ticket:"""Creates a Ticket from a gRPC protobuf ticket. Args: ticket (ticket_pb2.Ticket): the gRPC protobuf ticket Returns: a Ticket Raises: DHError: if the ticket type is unknown """ticket_bytes=ticket.ticketifticket_bytes.startswith(b'h'):returnSharedTicket(ticket_bytes)elifticket_bytes.startswith(b'e'):returnExportTicket(ticket_bytes)elifticket_bytes.startswith(b's/'):returnScopeTicket(ticket_bytes)elifticket_bytes.startswith(b'a/'):returnApplicationTicket(ticket_bytes)else:raiseDHError(f'Unknown ticket type: {ticket_bytes}')
[docs]classServerObject:""" A ServerObject is a typed ticket that represents objects existing on the server that can be referenced by the client. It is presently used to enable client API users to send and receive references to server-side plugins. """type:Optional[str]"""The type of the object. May be None, indicating that the instance cannot be connected to or otherwise directly used from the client."""ticket:Ticket"""The ticket that points to the object on the server."""def__init__(self,type:Optional[str],ticket:Ticket):self.type=typeself.ticket=ticket@propertydefpb_ticket(self)->ticket_pb2.Ticket:"""Returns the ticket as a gRPC protobuf ticket object."""returnself.ticket.pb_ticket@propertydefpb_typed_ticket(self)->ticket_pb2.TypedTicket:"""Returns a protobuf typed ticket, suitable for use in communicating with an ObjectType plugin on the server. """returnticket_pb2.TypedTicket(type=self.type,ticket=self.pb_ticket)
def_server_object_from_proto(typed_ticket:ticket_pb2.TypedTicket)->ServerObject:""" Creates a ServerObject from a gRPC protobuf typed ticket object. """returnServerObject(type=typed_ticket.type,ticket=_ticket_from_proto(typed_ticket.ticket))