Ejemplo n.º 1
0
        /// <summary>
        /// Caution: Non atomic operation!
        /// Save the key/value pair in the DataStore.
        /// This method will split the payload into multiple smaller packages, in order to overcome
        /// GameJolts 1MB limit. These packages will be appended via the update operation.
        /// If one or more parts are already uploaded and then an error occurs (for e.g. no network connection),
        /// this method will stop uploading further packages. If this happens the DataStore might contain
        /// incomplete data, therefore you might want to delete the entry or try uploading again.
        /// By using the <paramref name="progress"/> callback, you could also try to continue from the last position.
        /// </summary>
        /// <param name="key">The key name.</param>
        /// <param name="value">The value to store.</param>
        /// <param name="global">A boolean indicating whether the key is global (<c>true</c>) or private to the user (<c>false</c>).</param>
        /// <param name="callback">A callback function accepting a single parameter, a boolean indicating success.</param>
        /// <param name="progress">A callback function accepting a single parameter, the number of already uploaded bytes.
        /// This callback is called after each successfull segment upload.</param>
        /// <param name="maxSegmentSize">Maximum segment size. The data to upload is split into segments of at most this size.</param>
        public static void SetSegmented(string key, string value, bool global, Action <bool> callback,
                                        Action <int> progress = null, int maxSegmentSize = SoftLimit)
        {
            if (callback == null)
            {
                throw new ArgumentNullException();
            }
            if (maxSegmentSize < 10 || maxSegmentSize > SoftLimit)
            {
                throw new ArgumentOutOfRangeException();
            }

            int encodedKeySize = GetEncodedSize(key);

            if (encodedKeySize >= KeySizeLimit)
            {
                LogHelper.Error("Failed to upload data, because the key is too long.");
                callback(false);
                return;
            }
            maxSegmentSize = Math.Min(maxSegmentSize, SoftLimit - encodedKeySize);
            var segments    = new Queue <string>();
            int encodedSize = Segmentate(Encoding.ASCII.GetBytes(value), maxSegmentSize, segments);

            if (encodedKeySize + encodedSize > HardLimit)
            {
                LogHelper.Error("Dataset is larger than 16MB!");
                callback(false);
                return;
            }
            const int keyLimit = SoftLimit * 3 / 4;

            if (encodedKeySize > keyLimit)
            {
                LogHelper.Warning("Key is very long, only {0} bytes left for the data. " +
                                  "Therefore many segments may be needed to upload the data." +
                                  "Consider using smaller keys.", SoftLimit - key.Length);
            }

            // set first segment
            var dataSend = 0;
            var segment  = segments.Dequeue();
            var payload  = new Dictionary <string, string> {
                { "key", key }, { "data", segment }
            };

            Action <string> completedAction = null;

            completedAction = response => {
                if (response == null)                  // request failed
                {
                    callback(false);
                }
                else                     // request succeeded
                {
                    dataSend += segment.Length;
                    if (progress != null)
                    {
                        progress(dataSend);
                    }
                    if (dataSend >= value.Length)                      // data uploaded completely
                    {
                        callback(true);
                    }
                    else                         // append next segment
                    {
                        segment = segments.Dequeue();
                        Update(key, segment, DataStoreOperation.Append, global, completedAction);
                    }
                }
            };

            Request.Post(Constants.ApiDatastoreSet, null, payload,
                         response => completedAction(response.Success ? segment : null), !global);
        }