diff --git a/Makefile b/Makefile index e784b9c..3aa5bc2 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,4 @@ ifneq (,$(wildcard ./.env)) export endif -x: - set - include make/ocaml/main.mk diff --git a/lib/api/community/community_event.mli b/lib/api/community/community_event.mli index 76093bd..6642103 100644 --- a/lib/api/community/community_event.mli +++ b/lib/api/community/community_event.mli @@ -1 +1,11 @@ +(** Community event endpoints + + Represents all endpoints in [/community/CommunityEvent/*] + - [GET /community/CommunityEvent/getAvailableCommunityEvents] + + (explain the concept of a community event here) *) + +(** [get g d s] retrieves a list of currently available community events in the + game [g] on domain [d]. The request is sent with the method [s]. *) + val get : Data.Game.t -> string -> Data.Requester.Json.t -> Models.Response.Community.Community_event.t option Lwt.t diff --git a/lib/api/community/news.mli b/lib/api/community/news.mli index 2cbafec..8416aa7 100644 --- a/lib/api/community/news.mli +++ b/lib/api/community/news.mli @@ -1 +1,14 @@ +(** Community news endpoints + + Represents all endpoints in [/community/news/*] + - [GET /community/news/getNews] + + News are collections of text with an associated (optional) image. + News items are valid only until their expirytime is exceeded. + Although some news items have expired they may still be present + in the response.*) + +(** [get g d s] retrieves a list of currently available news in the + game [g] on domain [d]. The request is sent with the method [s]. *) + val get : Data.Game.t -> string -> Data.Requester.Json.t -> Models.Response.Community.News.t option Lwt.t diff --git a/lib/api/game/advertisement.ml b/lib/api/game/advertisement.ml index e69de29..e389c68 100644 --- a/lib/api/game/advertisement.ml +++ b/lib/api/game/advertisement.ml @@ -0,0 +1,29 @@ +open Lwt.Syntax +open Data.Sort + +let find_observable ?(start = 1) ?(count = 100) ?(sort = Descending) game domain send = + let should_descend = match sort with Ascending -> 0 | Descending -> 1 in + let base_url = Uri.make ~scheme:"https" ~host:domain ~path:"/game/advertisement/findObservableAdvertisements" () in + let url = + Uri.with_query' + base_url + [ "title", Data.Game.to_str game + ; "start", string_of_int start + ; "count", string_of_int count + ; "desc", string_of_int should_descend + ; "sortOrder", string_of_int should_descend + ; "dataChecksum", "0" + ; "modDLLFile", "INVALID" + ; "modName", "INVALID" + ; "modVersion", "INVALID" + ; "modDLLChecksum", "0" + ; "dataChecksum", "-888" + ; "appBinaryChecksum", "113358" + ; "versionFlags", "56950784" + ] + in + let* json = send url in + match json with + | Some j -> Lwt.return @@ Some (Models.Response.Game.Observable_advertisements.from_json j) + | None -> Lwt.return None +;; diff --git a/lib/client.ml b/lib/client.ml index 5e60e07..4b8e29f 100644 --- a/lib/client.ml +++ b/lib/client.ml @@ -36,16 +36,35 @@ let get_json ?(cookie = None) (url : Uri.t) = in let* resp, body = Cohttp_lwt_unix.Client.get ~headers url_with_params in let status = Cohttp.Response.status resp in + let* body_str = Cohttp_lwt.Body.to_string body in + let curl_command = + Printf.sprintf + "curl -i -H 'Cookie: %s' '%s'" + (match cookie with + | Some c -> + Printf.sprintf + "ApplicationGatewayAffinity=%s; ApplicationGatewayAffinityCORS=%s; reliclink=%s" + c.application_gateway_affinity + c.application_gateway_affinity_cors + c.reliclink + | None -> "") + (Uri.to_string url_with_params) + in + let* _ = Lwt_io.printl curl_command in if Cohttp.Code.code_of_status status = 200 - then - let* body_str = Cohttp_lwt.Body.to_string body in + then ( let json = Yojson.Basic.from_string body_str in - Lwt.return (Some json) + Lwt.return (Some json)) else ( (* TODO: Find out what to do with this later. What's the return type? Do we have Result? *) let url_str = Uri.to_string url_with_params in let* _ = - Lwt_io.printl @@ Printf.sprintf "HTTP Error: %s for URL: %s" (Cohttp.Code.string_of_status status) url_str + Lwt_io.printl + @@ Printf.sprintf + "HTTP Error: %s for URL: %s\nResponse: %s" + (Cohttp.Code.string_of_status status) + url_str + body_str in Lwt.return None) ;; diff --git a/lib/data/platform/cookie.ml b/lib/data/platform/cookie.ml index 43c9561..0736fb6 100644 --- a/lib/data/platform/cookie.ml +++ b/lib/data/platform/cookie.ml @@ -59,7 +59,8 @@ let get_cookie_value cookies name = |> List.tl |> String.concat "=" with - | Not_found -> failwith @@ Printf.sprintf "Cookie '%s' not found in '%s'" name (String.concat ";" cookies) + | Not_found -> + failwith @@ Printf.sprintf "Invalid credentials. Cookie '%s' not found in '%s'" name (String.concat ";" cookies) ;; let extract_session_id body_str = diff --git a/lib/data/sort.ml b/lib/data/sort.ml new file mode 100644 index 0000000..8622b7c --- /dev/null +++ b/lib/data/sort.ml @@ -0,0 +1,3 @@ +type t = + | Ascending + | Descending diff --git a/lib/models/response/game/news.ml b/lib/models/response/game/news.ml index 3e3f596..e2f87fe 100644 --- a/lib/models/response/game/news.ml +++ b/lib/models/response/game/news.ml @@ -4,7 +4,7 @@ type t = ; tail : Yojson.Basic.t list } -let to_json n = `List ([ `Int n.id; `List (List.map Stub.Game.News.to_json n.news) ] @ n.tail) +let to_json n = `List ([ `Int n.status; `List (List.map Stub.Game.News.to_json n.news) ] @ n.tail) let from_json json = match json with diff --git a/lib/models/response/game/observable_advertisements.ml b/lib/models/response/game/observable_advertisements.ml index 975859f..2fb62ef 100644 --- a/lib/models/response/game/observable_advertisements.ml +++ b/lib/models/response/game/observable_advertisements.ml @@ -4,11 +4,13 @@ type t = ; tail : Yojson.Basic.t list } -let to_json a = `List ([ `Int a.id; `List (List.map Stub.Game.Observable_advertisement.to_json a.news) ] @ a.tail) +let to_json a = + `List ([ `Int a.status; `List (List.map Stub.Game.Observable_advertisement.to_json a.advertisements) ] @ a.tail) +;; let from_json json = match json with | `List (`Int status :: `List items :: tail) -> { status; advertisements = List.map Stub.Game.Observable_advertisement.from_json items; tail } - | _ -> failwith "Unexpected JSON format for the news response" + | _ -> failwith "Unexpected JSON format for the observable advertisements response" ;; diff --git a/lib/models/stub/game/news.ml b/lib/models/stub/game/news.ml index f8ee75f..00cc6dc 100644 --- a/lib/models/stub/game/news.ml +++ b/lib/models/stub/game/news.ml @@ -1,5 +1,5 @@ type t = - { id : int + { status : int ; image_url : string option ; title : string ; subtitle : string option @@ -14,7 +14,7 @@ type t = let from_json json = match json with | `List - [ id + [ status ; image_url ; title ; subtitle @@ -25,7 +25,7 @@ let from_json json = ; start_time ; end_time ] -> - { id = Yojson.Basic.Util.to_int id + { status = Yojson.Basic.Util.to_int status ; image_url = Yojson.Basic.Util.to_string_option image_url ; title = Yojson.Basic.Util.to_string title ; subtitle = Yojson.Basic.Util.to_string_option subtitle @@ -41,7 +41,7 @@ let from_json json = let to_json n = `List - [ `Int n.id + [ `Int n.status ; (match n.image_url with Some url -> `String url | None -> `Null) ; `String n.title ; (match n.subtitle with Some sub -> `String sub | None -> `Null) diff --git a/lib/models/stub/game/observable_advertisement.ml b/lib/models/stub/game/observable_advertisement.ml index a7461e9..223d81b 100644 --- a/lib/models/stub/game/observable_advertisement.ml +++ b/lib/models/stub/game/observable_advertisement.ml @@ -13,7 +13,7 @@ type t = ; int5 : int ; slotinfo : string ; int6 : int - ; metadata : Yojson.Basic.t + ; metadata : Yojson.Basic.t list ; int7 : int ; int8 : int ; int9 : int @@ -28,42 +28,84 @@ type t = let from_json json = match json with | `List - [ id - ; image_url + [ match_id + ; int1 + ; string1 + ; host_relic_link_id + ; int2 ; title - ; subtitle ; description - ; short_description - ; long_description - ; category - ; start_time - ; end_time + ; int3 + ; map + ; options + ; int4 + ; int5 + ; slotinfo + ; int6 + ; metadata + ; int7 + ; int8 + ; int9 + ; int10 + ; int11 + ; int12 + ; time_started + ; server + ; unknown ] -> - { id = Yojson.Basic.Util.to_int id - ; image_url = Yojson.Basic.Util.to_string_option image_url + { match_id = Yojson.Basic.Util.to_int match_id + ; int1 = Yojson.Basic.Util.to_int int1 + ; string1 = Yojson.Basic.Util.to_string string1 + ; host_relic_link_id = Yojson.Basic.Util.to_int host_relic_link_id + ; int2 = Yojson.Basic.Util.to_int int2 ; title = Yojson.Basic.Util.to_string title - ; subtitle = Yojson.Basic.Util.to_string_option subtitle ; description = Yojson.Basic.Util.to_string description - ; short_description = Yojson.Basic.Util.to_string short_description - ; long_description = Yojson.Basic.Util.to_string long_description - ; category = Yojson.Basic.Util.to_string category - ; start_time = Yojson.Basic.Util.to_int start_time - ; end_time = Yojson.Basic.Util.to_int end_time + ; int3 = Yojson.Basic.Util.to_int int3 + ; map = Yojson.Basic.Util.to_string map + ; options = Yojson.Basic.Util.to_string options (* TODO: Parse this*) + ; int4 = Yojson.Basic.Util.to_int int4 + ; int5 = Yojson.Basic.Util.to_int int5 + ; slotinfo = Yojson.Basic.Util.to_string slotinfo (* TODO: Parse this*) + ; int6 = Yojson.Basic.Util.to_int int6 + ; metadata = Yojson.Basic.Util.to_list metadata + ; int7 = Yojson.Basic.Util.to_int int7 + ; int8 = Yojson.Basic.Util.to_int int8 + ; int9 = Yojson.Basic.Util.to_int int9 + ; int10 = Yojson.Basic.Util.to_int int10 + ; int11 = Yojson.Basic.Util.to_int int11 + ; int12 = Yojson.Basic.Util.to_int int12 + ; time_started = Yojson.Basic.Util.to_int time_started + ; server = Yojson.Basic.Util.to_string server + ; unknown = Yojson.Basic.Util.to_int_option unknown } - | _ -> failwith "Unexpected news item format" + | _ -> failwith "Unexpected observable advertisement format" ;; let to_json n = `List - [ `Int n.id - ; (match n.image_url with Some url -> `String url | None -> `Null) + [ `Int n.match_id + ; `Int n.int1 + ; `String n.string1 + ; `Int n.host_relic_link_id + ; `Int n.int2 ; `String n.title - ; (match n.subtitle with Some sub -> `String sub | None -> `Null) ; `String n.description - ; `String n.short_description - ; `String n.long_description - ; `String n.category - ; `Int n.start_time - ; `Int n.end_time + ; `Int n.int3 + ; `String n.map + ; `String n.options + ; `Int n.int4 + ; `Int n.int5 + ; `String n.slotinfo + ; `Int n.int6 + ; `List n.metadata + ; `Int n.int7 + ; `Int n.int8 + ; `Int n.int9 + ; `Int n.int10 + ; `Int n.int11 + ; `Int n.int12 + ; `String n.server + ; `Int n.time_started + ; (match n.unknown with Some u -> `Int u | None -> `Null) ] ;; diff --git a/tests/integration/test.ml b/tests/integration/test.ml index 097047e..32c4e9e 100644 --- a/tests/integration/test.ml +++ b/tests/integration/test.ml @@ -2,6 +2,8 @@ open Relic_sdk open Alcotest_lwt open Lwt.Syntax +let vgetenv k = try Sys.getenv k with Not_found -> failwith @@ Printf.sprintf "Environment variable %s not found" k + let setup_community () = let open Test_state.Community in let domain = "aoe-api.worldsedgelink.com" in @@ -21,7 +23,7 @@ let setup_community () = let setup_game () = let open Test_state.Game in let open Data.Platform.Steam_login in - let login = Some { alias = Sys.getenv "STEAM_USER_ALIAS"; app_ticket = Sys.getenv "STEAM_APP_TICKET" } in + let login = Some { alias = vgetenv "STEAM_USER_ALIAS"; app_ticket = vgetenv "STEAM_APP_TICKET" } in let domain = "aoe-api.worldsedgelink.com" in let game = Data.Game.Age2 in let endpoint = Api.Community.Leaderboard.get_leaderboard_2 ~count:1 in @@ -52,7 +54,12 @@ let () = `Slow (Test_case.Community.Achievements.test_get_user_achievements_no_user setup_data_community) ] ) - ; "Game", [ test_case "News" `Slow (Test_case.Game.News.test_get_news setup_data_game) ] + ; ( "Game" + , [ test_case + "Advertisements" + `Slow + (Test_case.Game.Advertisements.test_get_observable_advertisements setup_data_game) + ] ) ] in Alcotest_lwt.run "Relic SDK" suite diff --git a/tests/integration/test_case/game/advertisements.ml b/tests/integration/test_case/game/advertisements.ml new file mode 100644 index 0000000..50c62d3 --- /dev/null +++ b/tests/integration/test_case/game/advertisements.ml @@ -0,0 +1,21 @@ +open Relic_sdk +open Test_state.Game +open Lwt.Syntax + +let test_get_observable_advertisements test_state _ () = + let open Data.Sort in + let endpoint_asc = Api.Game.Advertisement.find_observable ~sort:Ascending ~count:2 in + let endpoint_dsc = Api.Game.Advertisement.find_observable ~sort:Descending ~count:2 in + let* lobbies_asc = Client.get endpoint_asc test_state.client in + let* lobbies_dsc = Client.get endpoint_dsc test_state.client in + match lobbies_asc, lobbies_dsc with + | Some a, Some d -> + let* _ = Lwt_io.printf "Yepge %d\n" (List.length a.advertisements) in + let id_asc = (List.hd a.advertisements).match_id in + let id_dsc = (List.hd d.advertisements).match_id in + Alcotest.(check int) "Different match IDs" id_asc id_dsc; + if id_asc = id_dsc + then Lwt.fail_with "Expected different advertisement IDs in ascending and descending order" + else Lwt.return_unit + | _ -> Lwt.fail_with "No observable advertisements response" +;; diff --git a/tests/integration/test_state/game.ml b/tests/integration/test_state/game.ml index e19afc8..ede9f68 100644 --- a/tests/integration/test_state/game.ml +++ b/tests/integration/test_state/game.ml @@ -2,5 +2,5 @@ open Relic_sdk type t = { client : Client.t - ; test_member : Models.Stub.Avatar.t + ; test_member : Models.Stub.Community.Avatar.t } diff --git a/tests/unit/test_cases/api.ml b/tests/unit/test_cases/api.ml index f535496..94a6b97 100644 --- a/tests/unit/test_cases/api.ml +++ b/tests/unit/test_cases/api.ml @@ -36,7 +36,10 @@ let test_find_clans () = let requester = Mock.Json_file.create_requester "findClan.json" in let* client = Client.create "aoe-api.worldsedgelink.com" Data.Game.Age2 in let endpoint = - Api.Community.Clan.find ~name:"My name" ~join_policies:[ Models.Stub.Join_policy.Open ] ~tags:[ "My tag" ] + Api.Community.Clan.find + ~name:"My name" + ~join_policies:[ Models.Stub.Community.Join_policy.Open ] + ~tags:[ "My tag" ] in let* response = Client.get endpoint client ~requester in match response with