/**
* Copyright 2019 The Knights Of Unity, created by Pawel Stolarczyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using System.Threading.Tasks;
using DemoGame.Scripts.Session;
using Nakama;
using UnityEngine;
namespace DemoGame.Scripts.DataStorage
{
///
/// Abstract class used to store and retrieve data from Nakama server.
/// This class utilizes Nakama's Storage Engine, documentation of which
/// can be found here: https://heroiclabs.com/docs/storage-collections/.
///
/// The data model to be serialized into Json and stored on Nakama server.
public abstract class DataStorage : MonoBehaviour where T : class
{
#region Properties
///
/// The name of collection data handled by this class will be stored in.
///
public abstract string StorageCollection { get; }
///
/// Determines who can change value of our data object on the server.
///
public abstract StorageWritePermission WritePermission { get; }
///
/// Determines who can read value of our data object on the server.
///
public abstract StorageReadPermission ReadPermission { get; }
#endregion
#region Methods
///
/// The key name under which data handled by this class can be found.
///
public abstract string StorageKey(T data);
///
/// Converts given data into Json string and sends it to Nakama server.
///
public virtual async Task StoreDataAsync(T data)
{
string json = Nakama.TinyJson.JsonWriter.ToJson(data);
string key = StorageKey(data);
return await StoreDataAsync(key, json);
}
///
/// Stores given under specified in Nakama storage system.
///
public virtual async Task StoreDataAsync(string key, string data)
{
Client client = NakamaSessionManager.Instance.Client;
ISession session = NakamaSessionManager.Instance.Session;
WriteStorageObject storageObject = new WriteStorageObject();
storageObject.Collection = StorageCollection;
storageObject.Key = key;
storageObject.Value = data;
storageObject.PermissionRead = (int)ReadPermission;
storageObject.PermissionWrite = (int)WritePermission;
try
{
// Method Client.WriteStorageObjectsAsync allows us to send multiple WriteStorageObjects at once, but in this
// demo we only ever need to send one at the time
IApiStorageObjectAcks sentObjects = await client.WriteStorageObjectsAsync(session, storageObject);
Debug.Log("Successfully send " + typeof(T).Name + " data: " + (sentObjects.Acks.Count() == 1 ? "true" : "false"));
return true;
}
catch (Exception e)
{
Debug.LogWarning("An exception has occured while sending user data: " + e);
return false;
}
}
///
/// Sends request to read data from the server and converts it from Json to .
/// Uses local as target user we want to get data of.
///
public virtual async Task LoadDataAsync(string key)
{
return await LoadDataAsync(NakamaSessionManager.Instance.Account.User.Id, key);
}
///
/// Sends request to read data from the server and converts it from Json to .
///
public virtual async Task LoadDataAsync(string userId, string key)
{
string json = await LoadDataJsonAsync(userId, key);
if (json == null)
{
Debug.Log("Couldn't retrieve data with key " + key);
return null;
}
else
{
T obj = Nakama.TinyJson.JsonParser.FromJson(json);
return obj;
}
}
///
/// Sends request to read data from the server and returns json.
///
public virtual async Task LoadDataJsonAsync(string userId, string key)
{
Client client = NakamaSessionManager.Instance.Client;
ISession session = NakamaSessionManager.Instance.Session;
StorageObjectId storageObject = new StorageObjectId();
storageObject.Collection = StorageCollection;
storageObject.Key = key;
storageObject.UserId = userId;
try
{
IApiStorageObjects receivedObjects = await client.ReadStorageObjectsAsync(session, storageObject);
// Method Client.ReadStorageObjectsAsync returns an enumerable of json strings, and because we
// passed only a single StorageObjectId, we expect to receive only one string
if (receivedObjects.Objects.Count() > 0)
{
string json = receivedObjects.Objects.ElementAt(0).Value;
return json;
}
else
{
Debug.Log("No " + typeof(T).Name + " data in " + StorageCollection + "." + key + " found for this user");
return null;
}
}
catch (Exception e)
{
Debug.LogWarning("An exception has occured while receiving user data: " + e);
return null;
}
}
#endregion
}
}