diff --git a/src/MarcSync/MarcSyncv1.0.lua b/src/MarcSync/MarcSyncv1.1.lua similarity index 80% rename from src/MarcSync/MarcSyncv1.0.lua rename to src/MarcSync/MarcSyncv1.1.lua index bbecde5..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,19 +42,20 @@ 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 - if not HttpService.HttpEnabled then error("Please Enable HTTPService in order to use MarcSync.") end + if not game:GetService("HttpService").HttpEnabled then error("Please Enable HTTPService in order to use MarcSync.") end end self = setmetatable(self, { diff --git a/src/MarcSync/Objects/Collection.lua b/src/MarcSync/Objects/Collection.lua index 73c0d79..ccb5667 100644 --- a/src/MarcSync/Objects/Collection.lua +++ b/src/MarcSync/Objects/Collection.lua @@ -1,19 +1,17 @@ local Utils = require(script.Parent.Parent.Utils) local Entry = require(script.Parent.Entry) -local types = { - EntryData = require(script.Parent.Parent.Types.EntryData).getType() -} +local Types = require(script.Parent.Parent.Types) local Collection = {} -Collection.createEntry = function(self:typeof(Collection), data:typeof(types.EntryData)):typeof(Entry.new()) +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,22 +19,22 @@ Collection.createEntry = function(self:typeof(Collection), data:typeof(types.Ent return result end -Collection.updateEntries = function(self:typeof(Collection), filters:typeof(types.EntryData), data:typeof(types.EntryData)):number +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"] end -Collection.getEntries = function(self:typeof(Collection), filters:typeof(types.EntryData)):{[number]:typeof(Entry.new())} +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,9 +44,9 @@ Collection.getEntries = function(self:typeof(Collection), filters:typeof(types.E return result end -Collection.deleteEntries = function(self:typeof(Collection), filters:typeof(types.EntryData)):number +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"] @@ -56,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 d28907e..f53631a 100644 --- a/src/MarcSync/Objects/Entry.lua +++ b/src/MarcSync/Objects/Entry.lua @@ -1,8 +1,6 @@ local Utils = require(script.Parent.Parent.Utils) -local types = { - EntryData = require(script.Parent.Parent.Types.EntryData).getType() -} +local Types = require(script.Parent.Parent.Types) local Entry = {} @@ -11,12 +9,12 @@ Entry.getValue = function(self:typeof(Entry), key:string):any return self._entryData[key] end -Entry.getValues = function(self:typeof(Entry)):typeof(types.EntryData) +Entry.getValues = function(self:typeof(Entry)):Types.EntryData return self._entryData end -Entry.updateValues = function(self:typeof(Entry), data:typeof(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); +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, self._options); if result["success"] and result["modifiedEntries"] and result["modifiedEntries"] > 0 then for i,v in pairs(data) do @@ -31,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 @@ -39,13 +37,14 @@ Entry.delete = function(self:typeof(Entry)) end return { - new = function(tableId:string, entryData:typeof(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 new file mode 100644 index 0000000..b8f26b2 --- /dev/null +++ b/src/MarcSync/Types.lua @@ -0,0 +1,11 @@ +local types = {} + +export type EntryData = { + [string]: any +} + +export type ClientOptions = { + retryCount: number +} + +return types \ No newline at end of file diff --git a/src/MarcSync/Types/EntryData.lua b/src/MarcSync/Types/EntryData.lua deleted file mode 100644 index c9f8aa1..0000000 --- a/src/MarcSync/Types/EntryData.lua +++ /dev/null @@ -1,9 +0,0 @@ -type EntryData = { - [string]: any -} - -return { - getType = function(): EntryData - return {} - end, -} \ 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