def _load_ticket(self, stream_slug, destination_uuid): stream = Stream.get_by(slug=stream_slug) if not destination_uuid: return Ticket.get_by(stream=stream, destination=Node.me()) node = Node.get_by(uuid=destination_uuid) return Ticket.query.filter_by(stream=stream, destination=node).first()
def test_delete(self): node = Node.me() ticket = TicketFactory(destination=node) self.http_client.fetch(HTTPRequest( self.get_url(ticket.absolute_url()), 'DELETE'), self.stop) response = self.wait() eq_(response.code, 200) eq_(Ticket.get_by(id=ticket.id), None) ok_(Stream.get_by(slug=ticket.stream.slug))
def test_get_tickets(self): response = self.fetch("/tickets") eq_(response.code, 200) result = json.loads(response.body) ok_("tickets" in result) eq_(len(result["tickets"]), 3) for ticket in result["tickets"]: source = Node.get_by(uuid=ticket["source"]) destination = Node.get_by(uuid=ticket["destination"]) ok_(Ticket.get_by(stream=Stream.get_by(slug=ticket["stream"]), source=source, destination=destination))
def test_delete(self): node = Node.me() ticket = TicketFactory(destination=node) self.http_client.fetch( HTTPRequest(self.get_url(ticket.absolute_url()), 'DELETE'), self.stop) response = self.wait() eq_(response.code, 200) eq_(Ticket.get_by(id=ticket.id), None) ok_(Stream.get_by(slug=ticket.stream.slug))
def _offer_ourselves(cls, stream, destination): tickets = Ticket.query.filter_by(source=Node.me()) if (tickets.count() >= settings.OUTGOING_STREAM_LIMIT or Node.me().upstream and tickets.count() * settings.STREAM_BITRATE > Node.me().upstream): log.info("Can't stream %s to %s, already at limit", stream, destination) raise HTTPError(412) ticket = Ticket.get_by(stream=stream, destination=Node.me()) if ticket: new_ticket = Ticket(stream=stream, destination=destination, source_port=ticket.source_port, hops=ticket.hops + 1) log.info( "We are receiving %s and have room to forward -- " "created %s to potentially forward to %s", stream, new_ticket, destination) return new_ticket
def _handle_ticket(self, ticket): # reload to get a new database session ticket = Ticket.get_by(id=ticket.id) if ticket.source == Node.me(): source_ip = "127.0.0.1" else: source_ip = ticket.source.ip_address try: port = self.create_tunnel(ticket.id, source_ip, ticket.source_port, self.tunnels) except Exception, e: log.warning("Couldn't create a tunnel for %s: %s", ticket, e)
def handle_ticket_request(cls, stream, destination): log.debug("Trying to create a ticket to serve %s to %s", stream, destination) new_ticket = cls._already_streaming(stream, destination) if new_ticket: log.info("%s already has a ticket for %s (%s)", destination, stream, new_ticket) if not new_ticket.source == Node.me(): log.info("Refreshing with source %s to be sure", new_ticket.source) existing_ticket = cls._request_stream_from_node( stream, new_ticket.source, destination) else: existing_ticket = new_ticket if existing_ticket: existing_ticket.refreshed = datetime.datetime.now() # In case we lost the tunnel, just make sure it exists existing_ticket.queue_tunnel_creation() session.commit() return existing_ticket log.info( "%s didn't confirm our old ticket %s, must get a new " "one", new_ticket.source, new_ticket) if stream.source != Node.me(): new_ticket = cls._offer_ourselves(stream, destination) if new_ticket: log.info("We can stream %s to %s, created %s", stream, destination, new_ticket) # In case we lost the tunnel, just make sure it exists new_ticket.queue_tunnel_creation() elif Node.me().supernode or destination == Node.me(): log.info( "Propagating the request for streaming %s to %s to " "our other known nodes", stream, destination) new_ticket = cls._request_stream_from_others( stream, destination) else: raise HTTPError(412) else: new_ticket = Ticket(stream=stream, source_port=stream.source_port, destination=destination) log.info("%s is the source of %s, created %s", Node.me(), stream, new_ticket) session.commit() return new_ticket
def _offer_ourselves(cls, stream, destination): tickets = Ticket.query.filter_by(source=Node.me()) if (tickets.count() >= settings.OUTGOING_STREAM_LIMIT or Node.me().upstream and tickets.count() * settings.STREAM_BITRATE > Node.me().upstream): log.info("Can't stream %s to %s, already at limit", stream, destination) raise HTTPError(412) ticket = Ticket.get_by(stream=stream, destination=Node.me()) if ticket: new_ticket = Ticket(stream=stream, destination=destination, source_port=ticket.source_port, hops=ticket.hops + 1) log.info("We are receiving %s and have room to forward -- " "created %s to potentially forward to %s", stream, new_ticket, destination) return new_ticket
def close_expired_tunnels(self): for ticket_id, tunnel in self.tunnels.items(): if not Ticket.get_by(id=ticket_id): self.destroy_tunnel(ticket_id, self.tunnels)
def _already_streaming(cls, stream, destination): return Ticket.get_by(stream=stream, destination=destination)
def _cleanup_unconfirmed_tickets(self): query = Ticket.unconfirmed() query = Ticket.old(query=query) for ticket in query: log.info("Expiring unconfirmed ticket %s", ticket) ticket.delete()
except RequestFailed, e: if e.response.status_int == 412: log.debug("%s didn't have room to forward %s to us", node, stream) else: if existing_ticket: return existing_ticket if ticket_data: source = Node.get_by(uuid=ticket_data['source']) if not source: source_node_data = NodesAPI(node.uri()).get( Node.absolute_url(source)) source = Node.from_dict(source_node_data) return Ticket(stream=stream, source=source, source_port=ticket_data['source_port'], destination=destination, hops=ticket_data['hops'] + 1) @classmethod def _request_stream_from_watchers(cls, stream, destination, unconfirmed_tickets=None): tickets = [] for ticket in Ticket.query.filter_by(stream=stream): if cls._already_seeding(ticket): return [ticket] else: if not cls._already_ticketed(unconfirmed_tickets, ticket.destination):