Search the Community
Showing results for tags 'http'.
Found 2 results
-
Accessing Player Data from API Endpoint
Spiderswine posted a topic in ARMA 3 - MISSION EDITING & SCRIPTING
Hey Guys, i love playing Arma, but there is one thing that always bothered the hell out me... Why we have no way to save player data like custom weapon configs, player outfits etc with our account and access them on multiple multiplayer servers like "King of the Hill" or "Altis Life"? Over the past months i've tried to figure out a way to make this happen. I found the wonderful Add On https://github.com/playnet-public/ArmA3URLFetch, which gives us the possibility to access API Endpoints from your local machine in multiplayer missions. The last days i developed an open django api endpoint, which can be requested by the player in the mission and there fore, there can be exchanged data, without the need of a local database. Of course, there's the question on how to authenticate the unique player in the mission. I'm trying to rebuild an OAUTH like workflow, where the local server acts as an authentication provider, by calling the api endpoint as well. Here's the workflow: In my opinion, this new approach gives mission creators a very powerful tool... Creators can now access every possible player information through one endpoint from multiple servers: Here's a multiple server setup: This gives mission creators the ability to share player information across every server of their mission and maybe host a mission website to access player information outside of Arma. At the moment i've developed a "proof of concept" iteration to ask for feedback if there is a need for such a system. I'm looking forward to your feedback and i would love to implement such a system in an upcoming multiplayer scenario. Here's an example example multiplayer mission. Here's the open django api endpoint. Best Regards, Luke PS: Sorry for the bad paint pictures, i'm broke 😉 Here is how its done: (authentication stuff is still in work...) Call the authentication in the initPlayerLocal.sqf and give player action (just for testing purposes) player addAction ["Handle Request", { [] spawn it_fnc_handleRequest }]; // handle the authentication [] spawn it_fnc_handleAuthentication; define the handleAuthentication function _cliendid = [ "http://192.168.0.102:8000/api/auth", "GET", ["uid=xyz"], true ] call a3uf_common_fnc_addClient; [ _cliendid, ["Content-Type: application/json"] ] call a3uf_common_fnc_setClientHeaders; _response = [ _cliendid ] call a3uf_common_fnc_clientRequest; _test = parseSimpleArray _response; _next = _test select 1; _u = _next select 0; _auth_token = _u select 1; diag_log "AUTH TOKEN"; diag_log _auth_token; _token_string = format["token=%1", _auth_token]; _cliendid = [ "http://192.168.0.102:8000/api/check", "GET", ["uid=xyz", _token_string], true ] call a3uf_common_fnc_addClient; [ _cliendid, ["Content-Type: application/json"] ] call a3uf_common_fnc_setClientHeaders; _response = [ _cliendid ] call a3uf_common_fnc_clientRequest; _test = parseSimpleArray _response; _next = _test select 1; _u = _next select 0; access_token = _u select 1; diag_log "ACCESS TOKEN"; diag_log access_token; define the handleRequest function _cliendid = ["http://192.168.0.102:8000/api/user", "GET", [], true] call a3uf_common_fnc_addClient; _auth_string = format ["Authorization: Bearer %1", access_token]; [_cliendid, ["Content-Type: application/json", _auth_string]] call a3uf_common_fnc_setClientHeaders; _response = [_cliendid] call a3uf_common_fnc_clientRequest; _test = parseSimpleArray _response; _next = _test select 1; _u = _next select 0; _name = _u select 1; hint format["Hello %1", _name]; diag_log "REQUEST"; diag_log _auth_string ; diag_log _response; define endpoints in views.py # api endpoint for user to access saved informations @api_view(["GET"]) def user(request): print(request.headers) token = request.headers.get("Authorization").split(" ")[1] # find the player by given access token try: player = Player.objects.get(token=token) # get the player # except User.DoesNotExist: except: # player with given token not found, return error return Response({'error': 'Player with token not found'}, status=HTTP_400_BAD_REQUEST) return Response({"name": player.name}) -
Extension to make http requests, currently supporting: GET POST PATCH DELETE PUT First parameter is the mode. Second is the method. Third is the url. Fourth is the authorization, if no authorization needed just pass null Fifth is the request body, only used by POST, PATCH and PUT, if no body needed just pass {} GET request example: "ArmaRequests" callExtension "0|GET|http://headers.jsontest.com/|null"; waitUntil {sleep 1; "ArmaRequests" callExtension "2" == "OK"}; _response = "ArmaRequests" callExtension "1"; _parsedResponse = parseSimpleArray _response; _code = _parsedResponse select 0; _data = _parsedResponse select 1; //Response => [["X-Cloud-Trace-Context","47e3637379c2b3d638285b973e0e4f96/4228286279360018440"],["Host","headers.jsontest.com"]] POST request example: "ArmaRequests" callExtension '0|POST|url|Bot ksZc83aS|{"Number": 4, "String": "String"}'; waitUntil {sleep 1; "ArmaRequests" callExtension "2" == "OK"}; _response = "ArmaRequests" callExtension "1"; _parsedResponse = parseSimpleArray _response; _code = _parsedResponse select 0; _data = _parsedResponse select 1; Every response comes with a status code 0: All data received 1: There's still data to receive 9: Error The codes you can use are 0: New request 1: Receive data 2: Get extension status 3: Parse JSON //Example: "ArmaRequests" callExtensions '3|{"age": 80}'; Due to string length limitations, if the response exceeds that limit it will be sent in chunks with status code 1, to receive the chunk use _fullResponse = ""; // _chunkResponse = "ArmaRequests" callExtension "1"; _parsedChunkResponse = parseSimpleArray _chunkResponse; _code = _chunkResponse select 0; _data = _chunkResponse select 1; _fullResponse = _fullResponse + _data; //You must repeat the receiving process until it responds with a code 0 When there's no more data left, it will respond with a code 0. JSON responses are automatically parsed into arrays, all common variables type are supported. Example code _fullResponse = ""; "ArmaRequests" callExtension "0|GET|http://headers.jsontest.com/|null"; //Send request waitUntil {sleep 1; "ArmaRequests" callExtension "2" == "OK"}; _response = "ArmaRequests" callExtension "1"; _parsedResponse = parseSimpleArray _response; //Parse response _code = _parsedResponse select 0; //Save code and data _data = _parsedResponse select 1; if (_code != 9) then { //Check if is a error _fullResponse = _data; //Assign the data in the full response while {_code == 1} do { //if there's more data receive it _chunkResponse = "ArmaRequests" callExtension "1"; //Receive next chunk data _parsedChunkResponse = parseSimpleArray _chunkResponse; //Parse the chunk data _code = _parsedChunkResponse select 0; //Update the status code _data = _parsedChunkResponse select 1; //Save the data if (_code == 9) exitWith {hint "Error : " + _data;}; //Check if is a error _fullResponse = _fullResponse + _data; //Append the chunk to the full response }; hint str _fullResponse; } else { hint "Error during request " + _data; }; There's also a callback version "ArmaRequestsCallback" callExtension "callbackFunction|Method|url|authorization?|body?"; Example using callback version and normal version TAG_fnc_DiscordMessageSent = { params["_data"]; //[["id","651314298001424405"],["type",0],["content","Hello"],["channel_id","649607925760786442"],["author",[["id","629121190182780929"],["username","Fantasia"],["avatar",null],["discriminator","2964"],["bot",true]]],["attachments",[]],["embeds",[]],["mentions",[]],["mention_roles",[]],["pinned",false],["mention_everyone",false],["tts",false],["timestamp","2019-12-03T06:50:29.478000+00:00"],["edited_timestamp",null],["flags",0],["nonce",null]] _content = (_data select 2) select 1; _username = (((_data select 4) select 1) select 1) select 1; _channelId = (_data select 3) select 1; "ArmaRequests" callExtension format["0|GET|https://discordapp.com/api/v6/channels/%1|Bot TOKEN|{}", _channelId]; waitUntil {sleep 1; "ArmaRequests" callExtension "2" == "OK"}; _channelData = (parseSimpleArray ("ArmaRequests" callExtension "1")) select 1; _channelName = (_channelData select 3) select 1; _guildId = (_channelData select 7) select 1; "ArmaRequests" callExtension format["0|GET|https://discordapp.com/api/v6/guilds/%1|Bot TOKEN|{}", _guildId]; waitUntil {sleep 1; "ArmaRequests" callExtension "2" == "OK"}; _guildData = (parseSimpleArray ("ArmaRequests" callExtension "1")) select 1; _guildName = (_guildData select 1) select 1; hint format["Sent %1 as %2 in the channel %3 of the guild %4", _content, _username, _channelName, _guildName]; }; addMissionEventHandler ["ExtensionCallback", { params["_name", "_function", "_data"]; if (_name == "ArmaRequestsCallback_JSON") then { [parseSimpleArray _data] spawn (missionNamespace getVariable [_function, { diag_log format["ArmaRequestsCallback: Tried to call %1, but isn't defined", _function]; }]); }; if (_name == "ArmaRequestsCallback_Error") then { hint "Request error: " + _data; }; if (_name == "ArmaRequestsCallback_TEXT") then { systemChat _data; }; }]; "ArmaRequestsCallback" callExtension "TAG_fnc_DiscordMessageSent|POST|https://discordapp.com/api/v6/channels/649607925760786442/messages|Bot BOT|{""content"": ""Hello"", ""tts"": false}"; Download link: https://drive.google.com/file/d/1-9oW3PhArHbs15AS4c6R5UQuuk6usInC/view