diff --git a/src/MarcSync/MarcSyncv1.0.lua b/src/MarcSync/MarcSyncv1.1.lua similarity index 84% rename from src/MarcSync/MarcSyncv1.0.lua rename to src/MarcSync/MarcSyncv1.1.lua index 4fa246a..0184bfb 100644 --- a/src/MarcSync/MarcSyncv1.0.lua +++ b/src/MarcSync/MarcSyncv1.1.lua @@ -8,31 +8,33 @@ local tokens = { local Utils = require(script.Parent.Utils) local MarcSyncClient = {} +local Types = require(script.Parent.Types) + MarcSyncClient.getVersion = function(self:typeof(MarcSyncClient), clientId: number?):string self:_checkInstallation() local url = "" if clientId then url = "/"..clientId end - local result = Utils.makeHTTPRequest("GET", "https://api.marcsync.dev/v0/utils/version"..url); + local result = Utils.makeHTTPRequest("", "GET", "https://api.marcsync.dev/v0/utils/version"..url, nil, nil, self._options); return result["version"] end MarcSyncClient.createCollection = function(self:typeof(MarcSyncClient), collectionName: string):typeof(require(script.Parent.Objects.Collection).new()) if not self._accessToken then error("[MarcSync] Please set a Token before using MarcSync.") end if not collectionName then error("No CollectionName Provided") end - local result = Utils.makeHTTPRequest("collection", "POST", "https://api.marcsync.dev/v0/collection/"..collectionName, {}, self._accessToken); + local result = Utils.makeHTTPRequest("collection", "POST", "https://api.marcsync.dev/v0/collection/"..collectionName, {}, self._accessToken, self._options); if not result["success"] then error(result["errorMessage"]) end - result = require(script.Parent.Objects.Collection).new(collectionName, self._accessToken) + result = require(script.Parent.Objects.Collection).new(collectionName, self._accessToken, self._options) return result end MarcSyncClient.fetchCollection = function(self:typeof(MarcSyncClient), collectionName: string):typeof(require(script.Parent.Objects.Collection).new()) self:_checkInstallation() if not collectionName then error("No CollectionName Provided") end - local result = Utils.makeHTTPRequest("collection", "GET", "https://api.marcsync.dev/v0/collection/"..collectionName, {}, self._accessToken); + local result = Utils.makeHTTPRequest("collection", "GET", "https://api.marcsync.dev/v0/collection/"..collectionName, {}, self._accessToken, self._options); if not result["success"] then error(result["errorMessage"]) end - result = require(script.Parent.Objects.Collection).new(collectionName, self._accessToken) + result = require(script.Parent.Objects.Collection).new(collectionName, self._accessToken, self._options) return result end @@ -40,15 +42,16 @@ MarcSyncClient.getCollection = function(self:typeof(MarcSyncClient), collectionN if typeof(self) ~= "table" then error("Please use : instead of .") end self:_checkInstallation() if not collectionName then error("No CollectionName Provided") end - return require(script.Parent.Objects.Collection).new(collectionName, self._accessToken) + return require(script.Parent.Objects.Collection).new(collectionName, self._accessToken, self._options) end return { - new = function(accessToken: string):typeof(MarcSyncClient) + new = function(accessToken: string, options: Types.ClientOptions?):typeof(MarcSyncClient) if not accessToken then warn("Token not provided while creating a new MarcSync Object.") end if not tokens[accessToken] then warn("Token provided for creating a new MarcSync Object not Found in Token Table, using it as token instead.") else accessToken = tokens[accessToken] end local self = {} self._accessToken = accessToken + self._options = options or {retryCount = 3} self._checkInstallation = function() if not self then error("Please Setup MarcSync before using MarcSync.") end if not self._accessToken then error("[MarcSync] Please set a Token before using MarcSync.") end diff --git a/src/MarcSync/Objects/Collection.lua b/src/MarcSync/Objects/Collection.lua index 435d7b7..ccb5667 100644 --- a/src/MarcSync/Objects/Collection.lua +++ b/src/MarcSync/Objects/Collection.lua @@ -7,11 +7,11 @@ local Collection = {} Collection.createEntry = function(self:typeof(Collection), data:Types.EntryData):typeof(Entry.new()) if not self._collectionName then error("[MarcSync: Collection] Invalid Object created or trying to access an destroied object.") end - local result = Utils.makeHTTPRequest("entry", "POST", "https://api.marcsync.dev/v0/entries/"..self._collectionName, {["data"]=data}, self._accessToken); + local result = Utils.makeHTTPRequest("entry", "POST", "https://api.marcsync.dev/v0/entries/"..self._collectionName, {["data"]=data}, self._accessToken, self._options); if result["success"] and result["objectId"] then data["_id"] = result["objectId"] - result = require(script.Parent.Entry).new(self._collectionName, data, self._accessToken) + result = require(script.Parent.Entry).new(self._collectionName, data, self._accessToken, self._options) else error(result["errorMessage"]) end @@ -21,7 +21,7 @@ end Collection.updateEntries = function(self:typeof(Collection), filters:Types.EntryData, data:Types.EntryData):number if not self._collectionName then error("[MarcSync: Collection] Invalid Object created or trying to access an destroied object.") end - local result = Utils.makeHTTPRequest("entry", "PUT", "https://api.marcsync.dev/v0/entries/"..self._collectionName, {["filters"]=filters,["data"]=data}, self._accessToken); + local result = Utils.makeHTTPRequest("entry", "PUT", "https://api.marcsync.dev/v0/entries/"..self._collectionName, {["filters"]=filters,["data"]=data}, self._accessToken, self._options); if not result["success"] then error(result["errorMessage"]) end return result["modifiedEntries"] @@ -30,11 +30,11 @@ end Collection.getEntries = function(self:typeof(Collection), filters:Types.EntryData):{[number]:typeof(Entry.new())} if not self._collectionName then error("[MarcSync: Collection] Invalid Object created or trying to access an destroied object.") end if not filters then filters = {} end - local result = Utils.makeHTTPRequest("entry", "DELETE", "https://api.marcsync.dev/v0/entries/"..self._collectionName.."?isQuery=true", {["filters"]=filters}, self._accessToken); + local result = Utils.makeHTTPRequest("entry", "DELETE", "https://api.marcsync.dev/v0/entries/"..self._collectionName.."?isQuery=true", {["filters"]=filters}, self._accessToken, self._options); if result["success"] and result["entries"] then local _result = {} for index,entry in pairs(result["entries"]) do - _result[index] = require(script.Parent.Entry).new(self._collectionName, entry, self._accessToken) + _result[index] = require(script.Parent.Entry).new(self._collectionName, entry, self._accessToken, self._options) end result = _result else @@ -46,7 +46,7 @@ end Collection.deleteEntries = function(self:typeof(Collection), filters:Types.EntryData):number if not self._collectionName then error("[MarcSync: Collection] Invalid Object created or trying to access an destroied object.") end - local result = Utils.makeHTTPRequest("DELETE", "https://api.marcsync.dev/v0/entries/"..self._collectionName, {["filters"]=filters}, self._accessToken); + local result = Utils.makeHTTPRequest("DELETE", "https://api.marcsync.dev/v0/entries/"..self._collectionName, {["filters"]=filters}, self._accessToken, self._options); if not result["success"] then error(result["errorMessage"]) end return result["deletedEntries"] @@ -54,16 +54,17 @@ end Collection.drop = function(self:typeof(Collection)) if not self._collectionName then error("[MarcSync: Collection] Invalid Object created or trying to access an destroied object.") end - local result = Utils.makeHTTPRequest("collection", "DELETE", "https://api.marcsync.dev/v0/collection/"..self._collectionName, {}, self._accessToken); + local result = Utils.makeHTTPRequest("collection", "DELETE", "https://api.marcsync.dev/v0/collection/"..self._collectionName, {}, self._accessToken, self._options); if not result["success"] then error(result["errorMessage"]) end self = nil end return { - new = function(collectionName: string, accessToken: string):typeof(Collection) + new = function(collectionName: string, accessToken: string, options: Types.ClientOptions):typeof(Collection) local self = {} self._collectionName = collectionName self._accessToken = accessToken + self._options = options self = setmetatable(self, { __index = Collection diff --git a/src/MarcSync/Objects/Entry.lua b/src/MarcSync/Objects/Entry.lua index 1bc4e5d..f53631a 100644 --- a/src/MarcSync/Objects/Entry.lua +++ b/src/MarcSync/Objects/Entry.lua @@ -14,7 +14,7 @@ Entry.getValues = function(self:typeof(Entry)):Types.EntryData end Entry.updateValues = function(self:typeof(Entry), data:Types.EntryData):number - local result = Utils.makeHTTPRequest("entry", "PUT", "https://api.marcsync.dev/v0/entries/"..self._tableId, {["filters"]={["_id"]=self._objectId},["data"]=data}, self._accessToken); + local result = Utils.makeHTTPRequest("entry", "PUT", "https://api.marcsync.dev/v0/entries/"..self._tableId, {["filters"]={["_id"]=self._objectId},["data"]=data}, self._accessToken, self._options); if result["success"] and result["modifiedEntries"] and result["modifiedEntries"] > 0 then for i,v in pairs(data) do @@ -29,7 +29,7 @@ end Entry.delete = function(self:typeof(Entry)) if typeof(self) ~= "table" then error("Please use : instead of .") end - local result = Utils.makeHTTPRequest("entry", "DELETE", "https://api.marcsync.dev/v0/entries/"..self._tableId, {["filters"]={["_id"]=self._objectId}}, self._accessToken); + local result = Utils.makeHTTPRequest("entry", "DELETE", "https://api.marcsync.dev/v0/entries/"..self._tableId, {["filters"]={["_id"]=self._objectId}}, self._accessToken, self._options); if not result["success"] then error(result["errorMessage"]) end self = nil @@ -37,13 +37,14 @@ Entry.delete = function(self:typeof(Entry)) end return { - new = function(tableId:string, entryData:Types.EntryData, accessToken:string):typeof(Entry) + new = function(tableId:string, entryData:Types.EntryData, accessToken:string, options: Types.ClientOptions):typeof(Entry) if not tableId or not entryData or not entryData["_id"] or not accessToken then error("[MarcSync: Entry] Tried creating invalid Entry Object.") end local self = {} self._tableId = tableId self._entryData = entryData self._objectId = entryData["_id"] self._accessToken = accessToken + self._options = options self = setmetatable(self, { __index = Entry diff --git a/src/MarcSync/Types.lua b/src/MarcSync/Types.lua index 835be36..b8f26b2 100644 --- a/src/MarcSync/Types.lua +++ b/src/MarcSync/Types.lua @@ -4,4 +4,8 @@ export type EntryData = { [string]: any } +export type ClientOptions = { + retryCount: number +} + return types \ No newline at end of file diff --git a/src/MarcSync/Utils.lua b/src/MarcSync/Utils.lua index 194e2b2..bd242ec 100644 --- a/src/MarcSync/Utils.lua +++ b/src/MarcSync/Utils.lua @@ -3,8 +3,9 @@ local CollectionError = require(script.Parent.Errors.Collection) local EntryError = require(script.Parent.Errors.Entry) local HttpService = game:GetService("HttpService") +local Types = require(script.Parent.Types) -function errorHandler(type: string, resultBody: any, resultObject: {}) +function errorHandler(callInformation: {}, resultBody: any, resultObject: {}, retryCount: number) local Error; if typeof(resultBody) == typeof({}) and resultBody["message"] then Error = resultBody["message"] @@ -14,30 +15,39 @@ function errorHandler(type: string, resultBody: any, resultObject: {}) Error = "An Unexpected Error occoured." end - if type == "collection" then - if resultObject["StatusCode"] == 401 then + local statusCode = resultObject["StatusCode"] + if callInformation.type == "collection" then + if statusCode == 401 then Error = AuthorizationError.InvalidAccessToken("InvalidAccessToken") - elseif resultObject["StatusCode"] == 404 then + elseif statusCode == 404 then Error = CollectionError.CollectionNotFound("CollectionNotFound") - elseif resultObject["StatusCode"] == 400 then + elseif statusCode == 400 then Error = CollectionError.CollectionAlreadyExists("CollectionAlreadyExists") end - elseif type == "entry" then - if resultObject["StatusCode"] == 401 then + elseif callInformation.type == "entry" then + if statusCode == 401 then Error = AuthorizationError.InvalidAccessToken("InvalidAccessToken") - elseif resultObject["StatusCode"] == 404 then + elseif statusCode == 404 then Error = CollectionError.CollectionNotFound("CollectionNotFound") - elseif resultObject["StatusCode"] == 400 then + elseif statusCode == 400 then Error = EntryError.InvalidEntryData("InvalidEntryData") end end + if(statusCode ~= 400 and statusCode ~= 401) then + if retryCount > 0 then + warn("[MarcSync HTTPRequest Handler] MarcSync HTTP Request failed with error: "..Error.." and status code: "..statusCode..". Retrying Request. ("..retryCount..") retries left") + task.wait(3) + return require(script.Parent.Utils).makeHTTPRequest(callInformation.type, callInformation.method, callInformation.url, callInformation.body, callInformation.authorization, {retryCount = retryCount - 1}) + end + end + return {["success"] = false, ["errorMessage"] = Error} end local utils = {} -function utils.makeHTTPRequest(type: string, method: string, url: string, body: {}, authorization: string):{["success"]: boolean, ["message"]: string} +function utils.makeHTTPRequest(type: string, method: string, url: string, body: {}, authorization: string, options: Types.ClientOptions):{["success"]: boolean, ["message"]: string} local resultObj; local resultBody; local success = pcall(function() @@ -54,7 +64,13 @@ function utils.makeHTTPRequest(type: string, method: string, url: string, body: if resultBody["warning"] then warn('[MarcSync HTTPRequest Handler] MarcSync HTTP Request returned warning for URL "'..url..'" with body: "'..HttpService:JSONEncode(body)..'": '..resultBody["warning"]) end return resultBody end - return errorHandler(type, resultBody, resultObj) + return errorHandler({ + type = type, + method = method, + url = url, + body = body, + authorization = authorization + }, resultBody, resultObj, options.retryCount) end return utils \ No newline at end of file diff --git a/website/docs-marcsync-dev/docs/classes/MarcSyncClient.mdx b/website/docs-marcsync-dev/docs/classes/MarcSyncClient.mdx index 1a856e1..2db7cad 100644 --- a/website/docs-marcsync-dev/docs/classes/MarcSyncClient.mdx +++ b/website/docs-marcsync-dev/docs/classes/MarcSyncClient.mdx @@ -18,6 +18,24 @@ METHODS +## CONSTRUCTOR + +### .new(`accessToken:` [string](https://www.lua.org/pil/2.4.html), `options:` [ClientOptions?](../types/ClientOptions)) +Creates a new MarcSync client. + +:::info Info +When creating a new client, you must provide an `accessToken`. This argument can either be the key of the "tokens" table in the client's Class or the actual token itself. If you provide the key, the client will automatically try to fetch the token from the "tokens" table. If you provide the token itself, the client will use that token instead. If no token is found by the key provided, it will use the key as the token itself. +::: + +:::info Info +The `options` argument is optional and can be used to specify the options of the client. If you do not provide any options, the client will use the default options. The default options are as follows: +```lua +{ + retryCount = 3 +} +``` +::: + ## METHODS ### :getVersion(`clientId:` [number?](https://www.lua.org/pil/2.3.html)) diff --git a/website/docs-marcsync-dev/docs/types/ClientOptions.md b/website/docs-marcsync-dev/docs/types/ClientOptions.md new file mode 100644 index 0000000..6a78b00 --- /dev/null +++ b/website/docs-marcsync-dev/docs/types/ClientOptions.md @@ -0,0 +1,11 @@ +# ClientOptions + +ClientOptions is a type which is used to specify the options of a client. It is used in the [MarcSyncClient](../classes/MarcSyncClient) class when creating a new client. + +## Type Definition + +```typescript +type ClientOptions = { + retryCount: number +} +``` \ No newline at end of file