# Buggy code
def render_GET(self, request):
    """
    .. http:get:: /torrentinfo

    A GET request to this endpoint will return information from a torrent found at a provided URI.
    This URI can either represent a file location, a magnet link or a HTTP(S) url.
    - torrent: the URI of the torrent file that should be downloaded. This parameter is required.

        **Example request**:

            .. sourcecode:: none

                curl -X GET http://localhost:8085/torrentinfo?torrent=file:/home/me/test.torrent

        **Example response**:

            .. sourcecode:: javascript

                {"metainfo": <torrent metainfo dictionary>}
    """

    def on_got_metainfo(metainfo):
        if not isinstance(metainfo, dict) or "info" not in metainfo:
            self._logger.warning("Received metainfo is not a valid dictionary")
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            request.write(json.twisted_dumps({"error": "invalid response"}))
            self.finish_request(request)
            return

        # Add the torrent to GigaChannel as a free-for-all entry, so others can search it
        self.session.lm.mds.TorrentMetadata.add_ffa_from_tdef(
            TorrentDef.load_from_dict(metainfo)
        )

        # TODO(Martijn): store the stuff in a database!!!
        # TODO(Vadim): this means cache the downloaded torrent in a binary storage, like LevelDB
        infohash = hashlib.sha1(bencode(metainfo["info"])).digest()

        # Check if the torrent is already in the downloads
        metainfo["download_exists"] = infohash in self.session.lm.downloads
        encoded_metainfo = hexlify(json.dumps(metainfo, ensure_ascii=False))

        request.write(json.twisted_dumps({"metainfo": encoded_metainfo}))
        self.finish_request(request)

    def on_metainfo_timeout(_):
        if not request.finished:
            request.setResponseCode(http.REQUEST_TIMEOUT)
            request.write(json.twisted_dumps({"error": "timeout"}))
        # If the above request.write failed, the request will have already been finished
        if not request.finished:
            self.finish_request(request)

    def on_lookup_error(failure):
        failure.trap(ConnectError, DNSLookupError, HttpError, ConnectionLost)
        request.setResponseCode(http.INTERNAL_SERVER_ERROR)
        request.write(
            json.twisted_dumps({"error": unichar_string(failure.getErrorMessage())})
        )
        self.finish_request(request)

    def _on_loaded(response):
        if response.startswith("magnet"):
            _, infohash, _ = parse_magnetlink(response)
            if infohash:
                self.session.lm.ltmgr.get_metainfo(
                    response,
                    callback=metainfo_deferred.callback,
                    timeout=20,
                    timeout_callback=on_metainfo_timeout,
                    notify=True,
                )
                return
        metainfo_deferred.callback(bdecode(response))

    def on_file():
        try:
            filename = url2pathname(
                uri[5:].encode("utf-8") if isinstance(uri, text_type) else uri[5:]
            )
            metainfo_deferred.callback(bdecode(fix_torrent(filename)))
            return NOT_DONE_YET
        except TypeError:
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            return json.twisted_dumps({"error": "error while decoding torrent file"})

    def on_magnet(mlink=None):
        infohash = parse_magnetlink(mlink or uri)[1]
        if infohash is None:
            request.setResponseCode(http.BAD_REQUEST)
            return json.twisted_dumps({"error": "missing infohash"})

        self.session.lm.ltmgr.get_metainfo(
            mlink or uri,
            callback=metainfo_deferred.callback,
            timeout=20,
            timeout_callback=on_metainfo_timeout,
            notify=True,
        )
        return NOT_DONE_YET

    metainfo_deferred = Deferred()
    metainfo_deferred.addCallback(on_got_metainfo)

    if b"uri" not in request.args or not request.args[b"uri"]:
        request.setResponseCode(http.BAD_REQUEST)
        return json.twisted_dumps({"error": "uri parameter missing"})

    uri = cast_to_unicode_utf8(request.args[b"uri"][0])

    if uri.startswith("file:"):
        return on_file()
    elif uri.startswith("http"):
        http_get(uri.encode("utf-8")).addCallback(_on_loaded).addErrback(
            on_lookup_error
        )
    elif uri.startswith("magnet"):
        return on_magnet()
    else:
        request.setResponseCode(http.BAD_REQUEST)
        return json.twisted_dumps({"error": "invalid uri"})

    return NOT_DONE_YET


# Traceback (RuntimeError)
Traceback (most recent call last):
File "TriblerGUI\event_request_manager.py", line 114, in on_read_data
RuntimeError: [Failure instance: Traceback: <class 'pony.orm.core.TransactionIntegrityError'>: Object TorrentMetadata[new:47] cannot be stored in the database. IntegrityError: UNIQUE constraint failed: ChannelNode.public_key, ChannelNode.id_
Tribler\Core\Modules\restapi\torrentinfo_endpoint.py:135:render_GET
Tribler\Core\Modules\restapi\torrentinfo_endpoint.py:109:on_file
lib\site-packages\twisted\internet\defer.py:459:callback
lib\site-packages\twisted\internet\defer.py:567:_startRunCallbacks
--- <exception caught here> ---
lib\site-packages\twisted\internet\defer.py:653:_runCallbacks
Tribler\Core\Modules\restapi\torrentinfo_endpoint.py:70:on_got_metainfo
<auto generated wrapper of add_ffa_from_tdef() function>:2:add_ffa_from_tdef
lib\site-packages\pony\orm\core.py:543:new_func
lib\site-packages\pony\orm\core.py:528:new_func
Tribler\Core\Modules\MetadataStore\OrmBindings\torrent_metadata.py:98:add_ffa_from_tdef
Tribler\Core\Modules\MetadataStore\OrmBindings\channel_node.py:213:from_dict
Tribler\Core\Modules\MetadataStore\OrmBindings\torrent_metadata.py:77:__init__
Tribler\Core\Modules\MetadataStore\OrmBindings\torrent_metadata.py:82:add_tracker
lib\site-packages\pony\orm\core.py:3950:get
lib\site-packages\pony\orm\core.py:4053:_find_one_
lib\site-packages\pony\orm\core.py:4112:_find_in_db_
lib\site-packages\pony\orm\core.py:934:_exec_sql
lib\site-packages\pony\orm\core.py:1797:prepare_connection_for_query_execution
lib\site-packages\pony\orm\core.py:1883:flush
lib\site-packages\pony\orm\core.py:5357:_save_
lib\site-packages\pony\orm\core.py:5201:_save_created_
lib\site-packages\pony\utils\utils.py:106:throw
]

# Fixed code
def render_GET(self, request):
    """
    .. http:get:: /torrentinfo

    A GET request to this endpoint will return information from a torrent found at a provided URI.
    This URI can either represent a file location, a magnet link or a HTTP(S) url.
    - torrent: the URI of the torrent file that should be downloaded. This parameter is required.

        **Example request**:

            .. sourcecode:: none

                curl -X GET http://localhost:8085/torrentinfo?torrent=file:/home/me/test.torrent

        **Example response**:

            .. sourcecode:: javascript

                {"metainfo": <torrent metainfo dictionary>}
    """

    def on_got_metainfo(metainfo):
        if not isinstance(metainfo, dict) or "info" not in metainfo:
            self._logger.warning("Received metainfo is not a valid dictionary")
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            request.write(json.twisted_dumps({"error": "invalid response"}))
            self.finish_request(request)
            return

        # Add the torrent to GigaChannel as a free-for-all entry, so others can search it
        self.session.lm.mds.TorrentMetadata.add_ffa_from_dict(
            tdef_to_metadata_dict(TorrentDef.load_from_dict(metainfo))
        )

        # TODO(Martijn): store the stuff in a database!!!
        # TODO(Vadim): this means cache the downloaded torrent in a binary storage, like LevelDB
        infohash = hashlib.sha1(bencode(metainfo["info"])).digest()

        # Check if the torrent is already in the downloads
        metainfo["download_exists"] = infohash in self.session.lm.downloads
        encoded_metainfo = hexlify(json.dumps(metainfo, ensure_ascii=False))

        request.write(json.twisted_dumps({"metainfo": encoded_metainfo}))
        self.finish_request(request)

    def on_metainfo_timeout(_):
        if not request.finished:
            request.setResponseCode(http.REQUEST_TIMEOUT)
            request.write(json.twisted_dumps({"error": "timeout"}))
        # If the above request.write failed, the request will have already been finished
        if not request.finished:
            self.finish_request(request)

    def on_lookup_error(failure):
        failure.trap(ConnectError, DNSLookupError, HttpError, ConnectionLost)
        request.setResponseCode(http.INTERNAL_SERVER_ERROR)
        request.write(
            json.twisted_dumps({"error": unichar_string(failure.getErrorMessage())})
        )
        self.finish_request(request)

    def _on_loaded(response):
        if response.startswith("magnet"):
            _, infohash, _ = parse_magnetlink(response)
            if infohash:
                self.session.lm.ltmgr.get_metainfo(
                    response,
                    callback=metainfo_deferred.callback,
                    timeout=20,
                    timeout_callback=on_metainfo_timeout,
                    notify=True,
                )
                return
        metainfo_deferred.callback(bdecode(response))

    def on_file():
        try:
            filename = url2pathname(
                uri[5:].encode("utf-8") if isinstance(uri, text_type) else uri[5:]
            )
            metainfo_deferred.callback(bdecode(fix_torrent(filename)))
            return NOT_DONE_YET
        except TypeError:
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            return json.twisted_dumps({"error": "error while decoding torrent file"})

    def on_magnet(mlink=None):
        infohash = parse_magnetlink(mlink or uri)[1]
        if infohash is None:
            request.setResponseCode(http.BAD_REQUEST)
            return json.twisted_dumps({"error": "missing infohash"})

        self.session.lm.ltmgr.get_metainfo(
            mlink or uri,
            callback=metainfo_deferred.callback,
            timeout=20,
            timeout_callback=on_metainfo_timeout,
            notify=True,
        )
        return NOT_DONE_YET

    metainfo_deferred = Deferred()
    metainfo_deferred.addCallback(on_got_metainfo)

    if b"uri" not in request.args or not request.args[b"uri"]:
        request.setResponseCode(http.BAD_REQUEST)
        return json.twisted_dumps({"error": "uri parameter missing"})

    uri = cast_to_unicode_utf8(request.args[b"uri"][0])

    if uri.startswith("file:"):
        return on_file()
    elif uri.startswith("http"):
        http_get(uri.encode("utf-8")).addCallback(_on_loaded).addErrback(
            on_lookup_error
        )
    elif uri.startswith("magnet"):
        return on_magnet()
    else:
        request.setResponseCode(http.BAD_REQUEST)
        return json.twisted_dumps({"error": "invalid uri"})

    return NOT_DONE_YET