{ "author": "", "category": "Network", "extensionNamespace": "", "fullName": "THNK Framework - P2P adapter", "helpPath": "https://thnk.cloud/", "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iMzIuNDU0MTdtbSIKICAgaGVpZ2h0PSIzMi4zMjUxMTVtbSIKICAgdmlld0JveD0iMCAwIDMyLjQ1NDE3IDMyLjMyNTExNSIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnMTY0NDUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuNSAoMjA2MGVjMWY5ZiwgMjAyMC0wNC0wOCkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlAyUC5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMxNjQzOSIgLz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iMC4zNSIKICAgICBpbmtzY2FwZTpjeD0iLTU4OC42NjkzMSIKICAgICBpbmtzY2FwZTpjeT0iLTE2MS43NzAzMSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0ibW0iCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTA1MyIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTE2NDQyIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiCiAgICAgaWQ9ImxheWVyMSIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtOTAuMzYyMjA3LC03My43MDY0OSkiPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOm9wZW49InRydWUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDAwLjc0MjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDAwLjc0MjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL21pZGhpbC9QaWN0dXJlcy9USE5LL1BORy9JY29ucy9QMlAucG5nIgogICAgICAgZD0ibSAtMTAwLjM4MDM4LDc5LjQzNzIxOCBhIDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSAtNy4zOTA0MSw0LjgwNDEyIDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSAtMTYuMTg3MDQsLTAuMTg2NjkxIDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSAtNi4zNzY1OSwtNC45NjI4OTkiCiAgICAgICBzb2RpcG9kaTplbmQ9IjMuMzAyNzI0MyIKICAgICAgIHNvZGlwb2RpOnN0YXJ0PSI2LjE5MTIyNjEiCiAgICAgICBzb2RpcG9kaTpyeT0iNS4wMzU1OTQiCiAgICAgICBzb2RpcG9kaTpyeD0iMTUuMTA2Nzc4IgogICAgICAgc29kaXBvZGk6Y3k9Ijc5Ljg5OTYzNSIKICAgICAgIHNvZGlwb2RpOmN4PSItMTE1LjQyMzMzIgogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTEwNS41MDQ3KSIKICAgICAgIGlkPSJwYXRoMTMxNi03LTgtNi03LTAtODMtOS04LTUtMi03LTYtOS0yOS03LTgtMiIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzIxMjUyOTtzdHJva2Utd2lkdGg6My4wOTYwMzM4MTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOm9wZW49InRydWUiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDAwLjc0MjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDAwLjc0MjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL21pZGhpbC9QaWN0dXJlcy9USE5LL1BORy9JY29ucy9QMlAucG5nIgogICAgICAgZD0ibSAxNDEuMDc2ODYsNjEuMTk4MyBhIDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSAtNy4zOTA0MSw0LjgwNDEyIDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSAtMTYuMTg3MDQsLTAuMTg2NjkxIDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSAtNi4zNzY1OSwtNC45NjI4OTkiCiAgICAgICBzb2RpcG9kaTplbmQ9IjMuMzAyNzI0MyIKICAgICAgIHNvZGlwb2RpOnN0YXJ0PSI2LjE5MTIyNjEiCiAgICAgICBzb2RpcG9kaTpyeT0iNS4wMzU1OTQiCiAgICAgICBzb2RpcG9kaTpyeD0iMTUuMTA2Nzc4IgogICAgICAgc29kaXBvZGk6Y3k9IjYxLjY2MDcxNyIKICAgICAgIHNvZGlwb2RpOmN4PSIxMjYuMDMzOTEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgxNC40OTUyOTkpIgogICAgICAgaWQ9InBhdGgxMzE2LTctOC02LTctMC04My05LTgtNS0yLTctNi05LTI5LTctOC0yLTYiCiAgICAgICBzdHlsZT0ib3BhY2l0eToxO3ZlY3Rvci1lZmZlY3Q6bm9uZTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMyMTI1Mjk7c3Ryb2tlLXdpZHRoOjMuMDk2MDMzODE7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQwMC43NDIxIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQwMC43NDIxIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS9taWRoaWwvUGljdHVyZXMvVEhOSy9QTkcvSWNvbnMvUDJQLnBuZyIKICAgICAgIGQ9Im0gMjUuODIyNjc1LDEzNy45MzMyNSBhIDE1LjY0OTQ2NCw1LjIxNjQ4ODggMCAwIDEgLTcuNjU1ODk0LDQuOTc2NyAxNS42NDk0NjQsNS4yMTY0ODg4IDAgMCAxIC0xNi43Njg1MzU4LC0wLjE5MzQgMTUuNjQ5NDY0LDUuMjE2NDg4OCAwIDAgMSAtNi42MDU2NTcyLC01LjE0MTE4IgogICAgICAgc29kaXBvZGk6ZW5kPSIzLjMwMjcyNDMiCiAgICAgICBzb2RpcG9kaTpzdGFydD0iNi4xOTEyMjYxIgogICAgICAgc29kaXBvZGk6cnk9IjUuMjE2NDg4OCIKICAgICAgIHNvZGlwb2RpOnJ4PSIxNS42NDk0NjQiCiAgICAgICBzb2RpcG9kaTpjeT0iMTM4LjQxMjI4IgogICAgICAgc29kaXBvZGk6Y3g9IjEwLjIzOTMzNCIKICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgIHRyYW5zZm9ybT0icm90YXRlKC00NS41MDQ3KSIKICAgICAgIGlkPSJwYXRoMTMxNi03LTgtNi03LTAtODMtOS04LTUtMi03LTYtOS0yOS03LTgtMi05IgogICAgICAgc3R5bGU9Im9wYWNpdHk6MTt2ZWN0b3ItZWZmZWN0Om5vbmU7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMjEyNTI5O3N0cm9rZS13aWR0aDozLjIwNzI1MzY5O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICA8Y2lyY2xlCiAgICAgICByPSI0LjEwMTA0MTgiCiAgICAgICBjeT0iOTguMTQ3NDYxIgogICAgICAgY3g9Ijk3LjM4NjA0IgogICAgICAgaWQ9InBhdGg1NDk3LTYtNS01LTAtNCIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6IzIxMjUyOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6My41O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS9taWRoaWwvUGljdHVyZXMvVEhOSy9QTkcvSWNvbnMvUDJQLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0MDAuNzQyMSIgLz4KICAgIDxjaXJjbGUKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUvbWlkaGlsL1BpY3R1cmVzL1RITksvUE5HL0ljb25zL1AyUC5wbmciCiAgICAgICByPSIxMy40NjE5NDIiCiAgICAgICBjeT0iLTc5LjczMDA0OSIKICAgICAgIGN4PSItMTE0LjUzMTQ2IgogICAgICAgaWQ9InBhdGgyNDM5LTgtNC0wLTAtNC03LTgtNi05LTgtOCIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6I2Y4ZjlmYTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6My4zMTUzMjEyMTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTAuMjU4ODE5MDQsLTAuOTY1OTI1ODMsLTAuOTY1OTI1ODMsMC4yNTg4MTkwNCwwLDApIiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUvbWlkaGlsL1BpY3R1cmVzL1RITksvUE5HL0ljb25zL1AyUC5wbmciCiAgICAgICBkPSJtIC0xMzAuNDc5MTcsNzkuNDg2NDQyIGEgMTUuMTA2Nzc4LDUuMDM1NTk0IDAgMCAxIDE0LjY0NTI5LC00LjYyMDU0MSAxNS4xMDY3NzgsNS4wMzU1OTQgMCAwIDEgMTUuMzc2NzksNC4zNDg0NzQiCiAgICAgICBzb2RpcG9kaTplbmQ9IjYuMTQ2Njc4NCIKICAgICAgIHNvZGlwb2RpOnN0YXJ0PSIzLjIyMzczOTUiCiAgICAgICBzb2RpcG9kaTpyeT0iNS4wMzU1OTQiCiAgICAgICBzb2RpcG9kaTpyeD0iMTUuMTA2Nzc4IgogICAgICAgc29kaXBvZGk6Y3k9Ijc5Ljg5OTYzNSIKICAgICAgIHNvZGlwb2RpOmN4PSItMTE1LjQyMzMzIgogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTEwNS41MDQ3KSIKICAgICAgIGlkPSJwYXRoMTMxNi03LTgtNi03LTAtODMtOS02LTgtMS0zLTAtNi00LTQtMS0yIgogICAgICAgc3R5bGU9Im9wYWNpdHk6MTt2ZWN0b3ItZWZmZWN0Om5vbmU7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMjEyNTI5O3N0cm9rZS13aWR0aDozLjA5NjAzMzgxO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUvbWlkaGlsL1BpY3R1cmVzL1RITksvUE5HL0ljb25zL1AyUC5wbmciCiAgICAgICBkPSJtIDExMC45NzgwOCw2MS4yNDc1MjQgYSAxNS4xMDY3NzgsNS4wMzU1OTQgMCAwIDEgOC42MDE1MiwtNC4xMzk2NjUgMTUuMTA2Nzc4LDUuMDM1NTk0IDAgMCAxIDE1LjA1NTkxLDAuNDEzMjQ4IDE1LjEwNjc3OCw1LjAzNTU5NCAwIDAgMSA2LjQ1NDIxLDQuNTUyOTA3IgogICAgICAgc29kaXBvZGk6ZW5kPSIwLjA4MjE2NzY0NyIKICAgICAgIHNvZGlwb2RpOnN0YXJ0PSIzLjIyMzczOTUiCiAgICAgICBzb2RpcG9kaTpyeT0iNS4wMzU1OTQiCiAgICAgICBzb2RpcG9kaTpyeD0iMTUuMTA2Nzc4IgogICAgICAgc29kaXBvZGk6Y3k9IjYxLjY2MDcxNyIKICAgICAgIHNvZGlwb2RpOmN4PSIxMjYuMDMzOTEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgxNC40OTUyOTkpIgogICAgICAgaWQ9InBhdGgxMzE2LTctOC02LTctMC04My05LTYtOC0xLTMtMC02LTQtNC0xLTItNCIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzIxMjUyOTtzdHJva2Utd2lkdGg6My4wOTYwMzM4MTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgc29kaXBvZGk6b3Blbj0idHJ1ZSIgLz4KICAgIDxwYXRoCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNDAwLjc0MjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDAwLjc0MjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL21pZGhpbC9QaWN0dXJlcy9USE5LL1BORy9JY29ucy9QMlAucG5nIgogICAgICAgZD0ibSAtNS4zNTczNTcxLDEzNy45ODQyNCBhIDE1LjY0OTQ2NCw1LjIxNjQ4ODggMCAwIDEgOC45MTA1MTQ1LC00LjI4ODM3IDE1LjY0OTQ2NCw1LjIxNjQ4ODggMCAwIDEgMTUuNTk2NzcxNiwwLjQyODA5IDE1LjY0OTQ2NCw1LjIxNjQ4ODggMCAwIDEgNi42ODYwNyw0LjcxNjQ2IgogICAgICAgc29kaXBvZGk6ZW5kPSIwLjA4MjE2NzY0NyIKICAgICAgIHNvZGlwb2RpOnN0YXJ0PSIzLjIyMzczOTUiCiAgICAgICBzb2RpcG9kaTpyeT0iNS4yMTY0ODg4IgogICAgICAgc29kaXBvZGk6cng9IjE1LjY0OTQ2NCIKICAgICAgIHNvZGlwb2RpOmN5PSIxMzguNDEyMjgiCiAgICAgICBzb2RpcG9kaTpjeD0iMTAuMjM5MzM0IgogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTQ1LjUwNDcpIgogICAgICAgaWQ9InBhdGgxMzE2LTctOC02LTctMC04My05LTYtOC0xLTMtMC02LTQtNC0xLTItNSIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzIxMjUyOTtzdHJva2Utd2lkdGg6My4yMDcyNTM2OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgc29kaXBvZGk6b3Blbj0idHJ1ZSIgLz4KICAgIDxjaXJjbGUKICAgICAgIHI9IjQuMTAxMDQxOCIKICAgICAgIGN5PSI4Ny42OTUzMTIiCiAgICAgICBjeD0iMTEyLjA4NTUiCiAgICAgICBpZD0icGF0aDU0OTctNi01LTUtMCIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7dmVjdG9yLWVmZmVjdDpub25lO2ZpbGw6IzIxMjUyOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6My41O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS9taWRoaWwvUGljdHVyZXMvVEhOSy9QTkcvSWNvbnMvUDJQLnBuZyIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0MDAuNzQyMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0MDAuNzQyMSIgLz4KICAgIDxjaXJjbGUKICAgICAgIHI9IjQuMTAxMDQxOCIKICAgICAgIGN5PSI5NC44NjM3NyIKICAgICAgIGN4PSI5NC40NjMyNDkiCiAgICAgICBpZD0icGF0aDU0OTctNi01LTUtMC03IgogICAgICAgc3R5bGU9Im9wYWNpdHk6MTt2ZWN0b3ItZWZmZWN0Om5vbmU7ZmlsbDojMjEyNTI5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozLjU7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL21pZGhpbC9QaWN0dXJlcy9USE5LL1BORy9JY29ucy9QMlAucG5nIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQwMC43NDIxIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQwMC43NDIxIiAvPgogIDwvZz4KPC9zdmc+Cg==", "name": "THNK_P2P", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/lan.svg", "shortDescription": "The P2P networking support module for the THNK framework.", "version": "1.0.0", "description": "Allows to host a THNK server on a P2P connection, and for other peers to connect to it via the server's P2P ID.", "tags": [ "THNK", "adapter", "network", "p2p", "peer", "ICE" ], "authorIds": [ "ZgrsWuRTAkXgeuPV9bo0zuEcA2w1" ], "dependencies": [], "eventsFunctions": [ { "fullName": "", "functionType": "Action", "name": "onFirstSceneLoaded", "sentence": "", "events": [ { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": "// Load THNK P2P Adapter (https://github.com/arthuro555/THNK)\n\"use strict\";\n(() => {\n // code/adapters/p2p.ts\n if(!window.THNK)window.THNK={};let THNK=window.THNK;\n ((THNK2) => {\n const logger = new gdjs.Logger(\"THNK - P2P Adapter\");\n class P2PConnectionAwaiter extends gdjs.AsyncTask {\n peerID;\n constructor(peerID) {\n super();\n this.peerID = peerID;\n }\n update() {\n return !!gdjs.evtTools.p2p.getConnectionInstance(this.peerID);\n }\n }\n class P2PClientAdapter extends THNK2.ClientAdapter {\n peerID;\n connection = null;\n constructor(peerID) {\n super();\n this.peerID = peerID;\n }\n boundPreEventsCallback = () => this.preEventsCallback();\n preEventsCallback() {\n if (!gdjs.evtTools.p2p.getConnectionInstance(this.peerID)) {\n this.onDisconnection();\n }\n }\n async prepare(runtimeScene) {\n this.connection = gdjs.evtTools.p2p.getConnectionInstance(\n this.peerID\n );\n if (!this.connection) {\n gdjs.evtTools.p2p.connect(this.peerID);\n this.connection = await new Promise(\n (resolve) => {\n runtimeScene.getAsyncTasksManager().addTask(\n new P2PConnectionAwaiter(this.peerID),\n () => resolve(\n gdjs.evtTools.p2p.getConnectionInstance(\n this.peerID\n )\n )\n );\n }\n );\n }\n this.connection.on(\n \"data\",\n (data) => this.onMessage(new Uint8Array(data))\n );\n gdjs.registerRuntimeScenePreEventsCallback(this.boundPreEventsCallback);\n }\n close() {\n gdjs.evtTools.p2p.disconnectFromPeer(this.peerID);\n gdjs._unregisterCallback(this.boundPreEventsCallback);\n }\n doSendMessage(message) {\n if (!this.connection) {\n return logger.error(\n \"Tried to send a message on an unestablished connection!\"\n );\n }\n this.connection.send(\n message.buffer.slice(message.buffer.byteLength - message.byteLength)\n );\n }\n }\n THNK2.P2PClientAdapter = P2PClientAdapter;\n class P2PServerAdapter extends THNK2.ServerAdapter {\n boundPreEventsCallback = () => this.preEventsCallback();\n preEventsCallback() {\n if (gdjs.evtTools.p2p.onConnection()) {\n const connectedPeer = gdjs.evtTools.p2p.getConnectedPeer();\n this.onConnection(connectedPeer);\n const connectionInstance = gdjs.evtTools.p2p.getConnectionInstance(\n connectedPeer\n );\n connectionInstance.on(\"data\", (data) => {\n this.onMessage(connectedPeer, new Uint8Array(data));\n });\n }\n if (gdjs.evtTools.p2p.onDisconnect()) {\n const disconnectedPeer = gdjs.evtTools.p2p.getDisconnectedPeer();\n this.onDisconnection(disconnectedPeer);\n }\n }\n async prepare() {\n gdjs.registerRuntimeScenePreEventsCallback(this.boundPreEventsCallback);\n }\n close() {\n gdjs._unregisterCallback(this.boundPreEventsCallback);\n }\n doSendMessageTo(userID, message) {\n const connection = gdjs.evtTools.p2p.getConnectionInstance(userID);\n if (connection) {\n connection.send(\n message.buffer.slice(message.buffer.byteLength - message.byteLength)\n );\n }\n }\n getServerID() {\n return gdjs.evtTools.p2p.getCurrentId();\n }\n }\n THNK2.P2PServerAdapter = P2PServerAdapter;\n })(THNK || (THNK = {}));\n})();\n", "parameterObjects": "", "useStrict": true, "eventsSheetExpanded": true } ], "parameters": [], "objectGroups": [] }, { "description": "Starts a scene as a remote scene server that connected P2P peers can join. The current game will also switch and connect to the game. If you switch to another scene or start another remote scene over P2P, the local server will be shut down and connected peers disconnected.", "fullName": "Start a remote scene over P2P", "functionType": "Action", "name": "StartServer", "sentence": "Start scene _PARAM1_ over P2P", "events": [ { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": [ "THNK.server.startServer(\r", " new THNK.P2PServerAdapter(),\r", " runtimeScene,\r", " eventsFunctionContext.getArgument(\"scene\")\r", ");\r", "" ], "parameterObjects": "", "useStrict": true, "eventsSheetExpanded": false } ], "parameters": [ { "description": "The scene to start as a THNK P2P server", "name": "scene", "type": "sceneName" } ], "objectGroups": [] }, { "description": "Connect to a remote scene hosted by a P2P server.", "fullName": "Connect to a P2P remote scene", "functionType": "Action", "name": "ConnectToServer", "sentence": "Connect to scene on _PARAM1_", "events": [ { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": [ "THNK.client.startClient(\r", " runtimeScene,\r", " new THNK.P2PClientAdapter(eventsFunctionContext.getArgument(\"PeerID\"))\r", ");\r", "" ], "parameterObjects": "", "useStrict": true, "eventsSheetExpanded": false } ], "parameters": [ { "description": "Name of the P2P peer to connect to", "name": "PeerID", "type": "string" } ], "objectGroups": [] }, { "description": "Check if the current scene is running with the P2P client adapter.", "fullName": "P2P client adapter in use", "functionType": "Condition", "name": "IsP2PClientInUse", "sentence": "P2P client is running", "events": [ { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": [ "eventsFunctionContext.returnValue = runtimeScene.thnkClient && runtimeScene.thnkClient.adapter instanceof THNK.P2PClientAdapter;\r", "" ], "parameterObjects": "", "useStrict": true, "eventsSheetExpanded": false } ], "parameters": [], "objectGroups": [] }, { "description": "Check if the current scene is running with the P2P server adapter.", "fullName": "P2P server adapter in use", "functionType": "Condition", "name": "IsP2PServerInUse", "sentence": "P2P server is running", "events": [ { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": [ "eventsFunctionContext.returnValue = runtimeScene.thnkServer && runtimeScene.thnkServer.adapter instanceof THNK.P2PServerAdapter;\r", "" ], "parameterObjects": "", "useStrict": true, "eventsSheetExpanded": false } ], "parameters": [], "objectGroups": [] }, { "description": "the P2P ID of the server", "fullName": "Server P2P ID", "functionType": "ExpressionAndCondition", "name": "ServerID", "sentence": "The P2P ID of the server", "events": [ { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": [ "eventsFunctionContext.returnValue =", " (runtimeScene.thnkServer && runtimeScene.thnkServer.adapter instanceof THNK.P2PServerAdapter)", " ? gdjs.evtTools.p2p.getCurrentId()", " : runtimeScene.thnkClient", " ? runtimeScene.thnkClient.adapter.peerID || \"\"", " : \"\"" ], "parameterObjects": "", "useStrict": true, "eventsSheetExpanded": false } ], "expressionType": { "type": "string" }, "parameters": [], "objectGroups": [] } ], "eventsBasedBehaviors": [], "eventsBasedObjects": [] }