diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a4c3d..89bd917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Changed - Use native Defold json encode and decode functions +- Updated gRPC API bindings to version 3.19.0 +- Updated Real-Time API bindings to verison 1.30.0 ### Added - Added optional native b64 encode and decode using extension-crypt if it exists diff --git a/README.md b/README.md index 2e9411d..16d5f17 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +![](https://img.shields.io/badge/Nakama%20gRPC%20-3.19.0-green) +![](https://img.shields.io/badge/Nakama%20RT%20-1.30.0-green) + # Nakama Defold/Lua client > Lua client for Nakama server written in Lua 5.1. diff --git a/codegen/README.md b/codegen/README.md index d14fd56..39047c5 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -11,5 +11,5 @@ go run rest.go /path/to/nakama/apigrpc/apigrpc.swagger.json > ../nakama/nakama.l Generate the RealTime API: ```shell -python realtime.py /path/to/nakama-common/rtapi/realtime.proto > ../nakama/socket.lua +python realtime.py /path/to/nakama-common > ../nakama/socket.lua ``` diff --git a/codegen/generate.sh b/codegen/generate.sh index d584564..22329fb 100755 --- a/codegen/generate.sh +++ b/codegen/generate.sh @@ -1,4 +1,20 @@ #!/usr/bin/env bash -go run rest.go ../../nakama/apigrpc/apigrpc.swagger.json > ../nakama/nakama.lua -python realtime.py ../../nakama-common/ ../nakama/socket.lua +NAKAMA=../../nakama +NAKAMA_APIGRPC=${NAKAMA}/apigrpc +NAKAMA_COMMON=../../nakama-common/ + +go run rest.go ${NAKAMA_APIGRPC}/apigrpc.swagger.json > ../nakama/nakama.lua +python realtime.py ${NAKAMA_COMMON} ../nakama/socket.lua + +pushd ${NAKAMA} +NAKAMA_GRPC_VERISON=$(git describe --tags --abbrev=0) +popd + +pushd ${NAKAMA_COMMON} +NAKAMA_COMMON_VERISON=$(git describe --tags --abbrev=0) +popd + + +echo "Nakama gRPC version: ${NAKAMA_GRPC_VERISON}" +echo "Nakama real-time version: ${NAKAMA_COMMON_VERISON}" diff --git a/codegen/rest.go b/codegen/rest.go index e1ceb72..69872d5 100644 --- a/codegen/rest.go +++ b/codegen/rest.go @@ -225,14 +225,14 @@ end {{- $varName := varName $parameter.Name $parameter.Type $parameter.Schema.Ref }} {{- $varName := $varName | pascalToSnake }} {{- $varComment := varComment $parameter.Name $parameter.Type $parameter.Schema.Ref $parameter.Items.Type }} -{{- if and (eq $parameter.Name "body") $parameter.Schema.Ref }} +{{- if and (eq $parameter.In "body") $parameter.Schema.Ref }} {{- bodyFunctionArgsDocs $parameter.Schema.Ref }} {{- end }} -{{- if and (eq $parameter.Name "body") $parameter.Schema.Type }} --- @param body ({{ $parameter.Schema.Type }}) {{ $parameter.Description }} +{{- if and (eq $parameter.In "body") $parameter.Schema.Type }} +-- @param body ({{ $parameter.Schema.Type }}) {{ $parameter.Description | stripNewlines }} {{- end }} -{{- if ne $parameter.Name "body" }} --- @param {{ $varName }} ({{ $parameter.Schema.Type }}) {{ $parameter.Description }} +{{- if ne $parameter.In "body" }} +-- @param {{ $varName }} ({{ $parameter.Schema.Type }}) {{ $parameter.Description | stripNewlines }} {{- end }} {{- end }} @@ -247,11 +247,11 @@ function M.{{ $operation.OperationId | pascalToSnake | removePrefix }}(client {{- $varName := varName $parameter.Name $parameter.Type $parameter.Schema.Ref }} {{- $varName := $varName | pascalToSnake }} {{- $varComment := varComment $parameter.Name $parameter.Type $parameter.Schema.Ref $parameter.Items.Type }} - {{- if and (eq $parameter.Name "body") $parameter.Schema.Ref }} + {{- if and (eq $parameter.In "body") $parameter.Schema.Ref }} {{- bodyFunctionArgs $parameter.Schema.Ref}} {{- end }} - {{- if and (eq $parameter.Name "body") $parameter.Schema.Type }}, {{ $parameter.Name }} {{- end }} - {{- if ne $parameter.Name "body" }}, {{ $varName }} {{- end }} + {{- if and (eq $parameter.In "body") $parameter.Schema.Type }}, {{ $parameter.Name }} {{- end }} + {{- if ne $parameter.In "body" }}, {{ $varName }} {{- end }} {{- end }}, callback, retry_policy, cancellation_token) assert(client, "You must provide a client") {{- range $parameter := $operation.Parameters }} @@ -259,7 +259,7 @@ function M.{{ $operation.OperationId | pascalToSnake | removePrefix }}(client {{- if eq $parameter.In "body" }} {{- bodyFunctionArgsAssert $parameter.Schema.Ref}} {{- end }} - {{- if and (eq $parameter.Name "body") $parameter.Schema.Type }} + {{- if and (eq $parameter.In "body") $parameter.Schema.Type }} assert({{- if $parameter.Required }}body and {{ end }}type(body) == "{{ $parameter.Schema.Type }}", "Argument 'body' must be of type '{{ $parameter.Schema.Type }}'") {{- end }} @@ -553,7 +553,7 @@ func main() { sort.Strings(keys) for _,key := range keys { info := props[key] - output = output + "-- @param " + key + " (" + info.Type + ") " + info.Description + "\n" + output = output + "-- @param " + key + " (" + info.Type + ") " + stripNewlines(info.Description) + "\n" } return } diff --git a/example/example.script b/example/example.script index a71f6fa..a503278 100644 --- a/example/example.script +++ b/example/example.script @@ -6,8 +6,12 @@ local nakama_session = require "nakama.session" local function email_login(client, email, password, username) - local session = client.authenticate_email(email, password, nil, true, username) - if session.token then + local account_api_account_email = { + email = email, + password = password, + } + local session = client.authenticate_email(account_api_account_email, true, username) + if session and session.token then nakama_session.store(session) client.set_bearer_token(session.token) return true diff --git a/nakama/nakama.lua b/nakama/nakama.lua index a954b6f..56ac702 100644 --- a/nakama/nakama.lua +++ b/nakama/nakama.lua @@ -49,9 +49,11 @@ M.APISTOREENVIRONMENT_PRODUCTION = "PRODUCTION" -- - APPLE_APP_STORE: Apple App Store -- - GOOGLE_PLAY_STORE: Google Play Store -- - HUAWEI_APP_GALLERY: Huawei App Gallery +-- - FACEBOOK_INSTANT_STORE: Facebook Instant Store M.APISTOREPROVIDER_APPLE_APP_STORE = "APPLE_APP_STORE" M.APISTOREPROVIDER_GOOGLE_PLAY_STORE = "GOOGLE_PLAY_STORE" M.APISTOREPROVIDER_HUAWEI_APP_GALLERY = "HUAWEI_APP_GALLERY" +M.APISTOREPROVIDER_FACEBOOK_INSTANT_STORE = "FACEBOOK_INSTANT_STORE" -- -- The low level client for the Nakama API. @@ -225,6 +227,28 @@ function M.healthcheck(client, callback, retry_policy, cancellation_token) end) end +--- delete_account +-- Delete the current user's account. +-- @param client Nakama client. +-- @param callback Optional callback function +-- A coroutine is used and the result is returned if no callback function is provided. +-- @param retry_policy Optional retry policy used specifically for this call or nil +-- @param cancellation_token Optional cancellation token for this call +-- @return The result. +function M.delete_account(client, callback, retry_policy, cancellation_token) + assert(client, "You must provide a client") + + local url_path = "/v2/account" + + local query_params = {} + + local post_data = nil + + return http(client, callback, url_path, query_params, "DELETE", post_data, retry_policy, cancellation_token, function(result) + return result + end) +end + --- get_account -- Fetch the current user's account. -- @param client Nakama client. @@ -422,6 +446,8 @@ end -- @param client Nakama client. -- @param email (string) A valid RFC-5322 email address. -- @param password (string) A password for the user account. +-- +--Ignored with unlink operations. -- @param vars (object) Extra information that will be bundled in the session token. -- @param create_bool () Register the account if the user does not already exist. @@ -786,6 +812,8 @@ end -- @param client Nakama client. -- @param email (string) A valid RFC-5322 email address. -- @param password (string) A password for the user account. +-- +--Ignored with unlink operations. -- @param vars (object) Extra information that will be bundled in the session token. -- @param callback Optional callback function @@ -1129,6 +1157,8 @@ end -- @param client Nakama client. -- @param email (string) A valid RFC-5322 email address. -- @param password (string) A password for the user account. +-- +--Ignored with unlink operations. -- @param vars (object) Extra information that will be bundled in the session token. -- @param callback Optional callback function @@ -1588,8 +1618,8 @@ end -- @param name_str () List groups that contain this value in their names. -- @param cursor_str () Optional pagination cursor. -- @param limit_int () Max number of groups to return. Between 1 and 100. --- @param lang_tag_str () Language tag filter. --- @param members_int () Number of group members. +-- @param lang_tag_str () Language tag filter +-- @param members_int () Number of group members -- @param open_bool () Optional Open/Closed filter. -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. @@ -1694,27 +1724,16 @@ end -- Update fields in a given group. -- @param client Nakama client. -- @param group_id_str () The ID of the group to update. --- @param avatarUrl (string) Avatar URL. --- @param description (string) Description string. --- @param groupId (string) The ID of the group to update. --- @param langTag (string) Lang tag. --- @param name (string) Name. --- @param open (boolean) Open is true if anyone should be allowed to join, or false if joins must be approved by a group admin. - +-- @param body (object) -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. -- @param retry_policy Optional retry policy used specifically for this call or nil -- @param cancellation_token Optional cancellation token for this call -- @return The result. -function M.update_group(client, group_id_str, avatarUrl, description, groupId, langTag, name, open, callback, retry_policy, cancellation_token) +function M.update_group(client, group_id_str, body, callback, retry_policy, cancellation_token) assert(client, "You must provide a client") - assert(not avatarUrl or type(avatarUrl) == "string", "Argument 'avatarUrl' must be 'nil' or of type 'string'") - assert(not description or type(description) == "string", "Argument 'description' must be 'nil' or of type 'string'") - assert(not groupId or type(groupId) == "string", "Argument 'groupId' must be 'nil' or of type 'string'") - assert(not langTag or type(langTag) == "string", "Argument 'langTag' must be 'nil' or of type 'string'") - assert(not name or type(name) == "string", "Argument 'name' must be 'nil' or of type 'string'") - assert(not open or type(open) == "boolean", "Argument 'open' must be 'nil' or of type 'boolean'") + assert(body and type(body) == "object", "Argument 'body' must be of type 'object'") local url_path = "/v2/group/{groupId}" url_path = url_path:gsub("{groupId}", uri_encode(group_id_str)) @@ -1722,14 +1741,7 @@ function M.update_group(client, group_id_str, avatarUrl, description, groupId, l local query_params = {} local post_data = nil - post_data = json.encode({ - avatarUrl = avatarUrl, - description = description, - groupId = groupId, - langTag = langTag, - name = name, - open = open, - }) + post_data = json.encode(body) return http(client, callback, url_path, query_params, "PUT", post_data, retry_policy, cancellation_token, function(result) return result @@ -1982,6 +1994,41 @@ function M.validate_purchase_apple(client, persist, receipt, callback, retry_pol end) end +--- validate_purchase_facebook_instant +-- Validate FB Instant IAP Receipt +-- @param client Nakama client. +-- @param persist (boolean) +-- @param signedRequest (string) Base64 encoded Facebook Instant signedRequest receipt data payload. + +-- @param callback Optional callback function +-- A coroutine is used and the result is returned if no callback function is provided. +-- @param retry_policy Optional retry policy used specifically for this call or nil +-- @param cancellation_token Optional cancellation token for this call +-- @return The result. +function M.validate_purchase_facebook_instant(client, persist, signedRequest, callback, retry_policy, cancellation_token) + assert(client, "You must provide a client") + assert(not persist or type(persist) == "boolean", "Argument 'persist' must be 'nil' or of type 'boolean'") + assert(not signedRequest or type(signedRequest) == "string", "Argument 'signedRequest' must be 'nil' or of type 'string'") + + + local url_path = "/v2/iap/purchase/facebookinstant" + + local query_params = {} + + local post_data = nil + post_data = json.encode({ + persist = persist, + signedRequest = signedRequest, + }) + + return http(client, callback, url_path, query_params, "POST", post_data, retry_policy, cancellation_token, function(result) + if not result.error and api_validate_purchase_response then + result = api_validate_purchase_response.create(result) + end + return result + end) +end + --- validate_purchase_google -- Validate Google IAP Receipt -- @param client Nakama client. @@ -2296,12 +2343,13 @@ end -- @param owner_id_str () The owner to retrieve records around. -- @param limit_int () Max number of records to return. Between 1 and 100. -- @param expiry_str () Expiry in seconds (since epoch) to begin fetching records from. +-- @param cursor_str () A next or previous page cursor. -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. -- @param retry_policy Optional retry policy used specifically for this call or nil -- @param cancellation_token Optional cancellation token for this call -- @return The result. -function M.list_leaderboard_records_around_owner(client, leaderboard_id_str, owner_id_str, limit_int, expiry_str, callback, retry_policy, cancellation_token) +function M.list_leaderboard_records_around_owner(client, leaderboard_id_str, owner_id_str, limit_int, expiry_str, cursor_str, callback, retry_policy, cancellation_token) assert(client, "You must provide a client") local url_path = "/v2/leaderboard/{leaderboardId}/owner/{ownerId}" @@ -2311,6 +2359,7 @@ function M.list_leaderboard_records_around_owner(client, leaderboard_id_str, own local query_params = {} query_params["limit"] = limit_int query_params["expiry"] = expiry_str + query_params["cursor"] = cursor_str local post_data = nil @@ -2388,6 +2437,8 @@ end -- @param client Nakama client. -- @param limit_int () The number of notifications to get. Between 1 and 100. -- @param cacheable_cursor_str () A cursor to page through notifications. May be cached by clients to get from point in time forwards. +-- +--value from NotificationList.cacheable_cursor. -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. -- @param retry_policy Optional retry policy used specifically for this call or nil @@ -2454,7 +2505,7 @@ end -- @param retry_policy Optional retry policy used specifically for this call or nil -- @param cancellation_token Optional cancellation token for this call -- @return The result. -function M.rpc_func(client, id_str, body, http_key_str, callback, retry_policy, cancellation_token) +function M.rpc_func(client, id_str, payload, http_key_str, callback, retry_policy, cancellation_token) assert(client, "You must provide a client") assert(body and type(body) == "string", "Argument 'body' must be of type 'string'") @@ -2608,6 +2659,8 @@ end -- @param user_id_str () ID of the user. -- @param limit_int () The number of storage objects to list. Between 1 and 100. -- @param cursor_str () The cursor to page through results from. +-- +--value from StorageObjectList.cursor. -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. -- @param retry_policy Optional retry policy used specifically for this call or nil @@ -2641,6 +2694,8 @@ end -- @param user_id_str () ID of the user. -- @param limit_int () The number of storage objects to list. Between 1 and 100. -- @param cursor_str () The cursor to page through results from. +-- +--value from StorageObjectList.cursor. -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. -- @param retry_policy Optional retry policy used specifically for this call or nil @@ -2704,6 +2759,30 @@ function M.list_tournaments(client, category_start_int, category_end_int, start_ end) end +--- delete_tournament_record +-- Delete a tournament record. +-- @param client Nakama client. +-- @param tournament_id_str () The tournament ID to delete from. +-- @param callback Optional callback function +-- A coroutine is used and the result is returned if no callback function is provided. +-- @param retry_policy Optional retry policy used specifically for this call or nil +-- @param cancellation_token Optional cancellation token for this call +-- @return The result. +function M.delete_tournament_record(client, tournament_id_str, callback, retry_policy, cancellation_token) + assert(client, "You must provide a client") + + local url_path = "/v2/tournament/{tournamentId}" + url_path = url_path:gsub("{tournamentId}", uri_encode(tournament_id_str)) + + local query_params = {} + + local post_data = nil + + return http(client, callback, url_path, query_params, "DELETE", post_data, retry_policy, cancellation_token, function(result) + return result + end) +end + --- list_tournament_records -- List tournament records. -- @param client Nakama client. @@ -2856,12 +2935,13 @@ end -- @param owner_id_str () The owner to retrieve records around. -- @param limit_int () Max number of records to return. Between 1 and 100. -- @param expiry_str () Expiry in seconds (since epoch) to begin fetching records from. +-- @param cursor_str () A next or previous page cursor. -- @param callback Optional callback function -- A coroutine is used and the result is returned if no callback function is provided. -- @param retry_policy Optional retry policy used specifically for this call or nil -- @param cancellation_token Optional cancellation token for this call -- @return The result. -function M.list_tournament_records_around_owner(client, tournament_id_str, owner_id_str, limit_int, expiry_str, callback, retry_policy, cancellation_token) +function M.list_tournament_records_around_owner(client, tournament_id_str, owner_id_str, limit_int, expiry_str, cursor_str, callback, retry_policy, cancellation_token) assert(client, "You must provide a client") local url_path = "/v2/tournament/{tournamentId}/owner/{ownerId}" @@ -2871,6 +2951,7 @@ function M.list_tournament_records_around_owner(client, tournament_id_str, owner local query_params = {} query_params["limit"] = limit_int query_params["expiry"] = expiry_str + query_params["cursor"] = cursor_str local post_data = nil