228 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- ------------------------------------------------------------------------------ --
 | |
| --                                TradeSkillMaster                                --
 | |
| --                          https://tradeskillmaster.com                          --
 | |
| --    All Rights Reserved - Detailed license information included with addon.     --
 | |
| -- ------------------------------------------------------------------------------ --
 | |
| 
 | |
| local _, TSM = ...
 | |
| local CraftingSync = TSM.Crafting:NewPackage("Sync")
 | |
| local L = TSM.Include("Locale").GetTable()
 | |
| local Delay = TSM.Include("Util.Delay")
 | |
| local TempTable = TSM.Include("Util.TempTable")
 | |
| local String = TSM.Include("Util.String")
 | |
| local Log = TSM.Include("Util.Log")
 | |
| local Theme = TSM.Include("Util.Theme")
 | |
| local Sync = TSM.Include("Service.Sync")
 | |
| local private = {
 | |
| 	hashesTemp = {},
 | |
| 	spellsTemp = {},
 | |
| 	spellsProfessionLookupTemp = {},
 | |
| 	spellInfoTemp = {
 | |
| 		spellIds = {},
 | |
| 		mats = {},
 | |
| 		itemStrings = {},
 | |
| 		names = {},
 | |
| 		numResults = {},
 | |
| 		hasCDs = {},
 | |
| 	},
 | |
| 	accountLookup = {},
 | |
| 	accountStatus = {},
 | |
| }
 | |
| local RETRY_DELAY = 5
 | |
| local PROFESSION_HASH_FIELDS = { "spellId", "itemString" }
 | |
| 
 | |
| 
 | |
| 
 | |
| -- ============================================================================
 | |
| -- Module Functions
 | |
| -- ============================================================================
 | |
| 
 | |
| function CraftingSync.OnInitialize()
 | |
| 	Sync.RegisterConnectionChangedCallback(private.ConnectionChangedHandler)
 | |
| 	Sync.RegisterRPC("CRAFTING_GET_HASHES", private.RPCGetHashes)
 | |
| 	Sync.RegisterRPC("CRAFTING_GET_SPELLS", private.RPCGetSpells)
 | |
| 	Sync.RegisterRPC("CRAFTING_GET_SPELL_INFO", private.RPCGetSpellInfo)
 | |
| end
 | |
| 
 | |
| function CraftingSync.GetStatus(account)
 | |
| 	local status = private.accountStatus[account]
 | |
| 	if not status then
 | |
| 		return Theme.GetFeedbackColor("RED"):ColorText(L["Not Connected"])
 | |
| 	elseif status == "UPDATING" or status == "RETRY" then
 | |
| 		return Theme.GetFeedbackColor("YELLOW"):ColorText(L["Updating"])
 | |
| 	elseif status == "SYNCED" then
 | |
| 		return Theme.GetFeedbackColor("GREEN"):ColorText(L["Up to date"])
 | |
| 	else
 | |
| 		error("Invalid status: "..tostring(status))
 | |
| 	end
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| -- ============================================================================
 | |
| -- RPC Functions and Result Handlers
 | |
| -- ============================================================================
 | |
| 
 | |
| function private.RPCGetHashes()
 | |
| 	wipe(private.hashesTemp)
 | |
| 	local player = UnitName("player")
 | |
| 	private.GetPlayerProfessionHashes(player, private.hashesTemp)
 | |
| 	return player, private.hashesTemp
 | |
| end
 | |
| 
 | |
| function private.RPCGetHashesResultHandler(player, data)
 | |
| 	if not player or not private.accountLookup[player] then
 | |
| 		-- request timed out, so try again
 | |
| 		Log.Warn("Getting hashes timed out")
 | |
| 		if private.accountLookup[player] then
 | |
| 			private.accountStatus[private.accountLookup[player]] = "RETRY"
 | |
| 			Delay.AfterTime(RETRY_DELAY, private.RetryGetHashesRPC)
 | |
| 		end
 | |
| 		return
 | |
| 	end
 | |
| 	local currentInfo = TempTable.Acquire()
 | |
| 	private.GetPlayerProfessionHashes(player, currentInfo)
 | |
| 	local requestProfessions = TempTable.Acquire()
 | |
| 	for profession, hash in pairs(data) do
 | |
| 		if hash == currentInfo[profession] then
 | |
| 			Log.Info("%s data for %s already up to date", profession, player)
 | |
| 		else
 | |
| 			Log.Info("Need updated %s data from %s (%s, %s)", profession, player, hash, tostring(currentInfo[hash]))
 | |
| 			requestProfessions[profession] = true
 | |
| 		end
 | |
| 	end
 | |
| 	TempTable.Release(currentInfo)
 | |
| 	if next(requestProfessions) then
 | |
| 		private.accountStatus[private.accountLookup[player]] = "UPDATING"
 | |
| 		Sync.CallRPC("CRAFTING_GET_SPELLS", player, private.RPCGetSpellsResultHandler, requestProfessions)
 | |
| 	else
 | |
| 		private.accountStatus[private.accountLookup[player]] = "SYNCED"
 | |
| 	end
 | |
| 	TempTable.Release(requestProfessions)
 | |
| end
 | |
| 
 | |
| function private.RPCGetSpells(professions)
 | |
| 	wipe(private.spellsProfessionLookupTemp)
 | |
| 	wipe(private.spellsTemp)
 | |
| 	local player = UnitName("player")
 | |
| 	local query = TSM.Crafting.CreateRawCraftsQuery()
 | |
| 		:Select("spellId", "profession")
 | |
| 		:Custom(private.QueryProfessionFilter, professions)
 | |
| 		:Custom(private.QueryPlayerFilter, player)
 | |
| 		:OrderBy("spellId", true)
 | |
| 	for _, spellId, profession in query:Iterator() do
 | |
| 		private.spellsProfessionLookupTemp[spellId] = profession
 | |
| 		tinsert(private.spellsTemp, spellId)
 | |
| 	end
 | |
| 	query:Release()
 | |
| 	return player, private.spellsProfessionLookupTemp, private.spellsTemp
 | |
| end
 | |
| 
 | |
| function private.RPCGetSpellsResultHandler(player, professionLookup, spells)
 | |
| 	if not player or not private.accountLookup[player] then
 | |
| 		-- request timed out, so try again from the start
 | |
| 		Log.Warn("Getting spells timed out")
 | |
| 		if private.accountLookup[player] then
 | |
| 			private.accountStatus[private.accountLookup[player]] = "RETRY"
 | |
| 			Delay.AfterTime(RETRY_DELAY, private.RetryGetHashesRPC)
 | |
| 		end
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	for i = #spells, 1, -1 do
 | |
| 		local spellId = spells[i]
 | |
| 		if TSM.Crafting.HasSpellId(spellId) then
 | |
| 			-- already have this spell so just make sure this player is added
 | |
| 			TSM.Crafting.AddPlayer(spellId, player)
 | |
| 			tremove(spells, i)
 | |
| 		end
 | |
| 	end
 | |
| 	if #spells == 0 then
 | |
| 		Log.Info("Spells up to date for %s", player)
 | |
| 		private.accountStatus[private.accountLookup[player]] = "SYNCED"
 | |
| 	else
 | |
| 		Log.Info("Requesting %d spells from %s", #spells, player)
 | |
| 		Sync.CallRPC("CRAFTING_GET_SPELL_INFO", player, private.RPCGetSpellInfoResultHandler, professionLookup, spells)
 | |
| 	end
 | |
| end
 | |
| 
 | |
| function private.RPCGetSpellInfo(professionLookup, spells)
 | |
| 	for _, tbl in pairs(private.spellInfoTemp) do
 | |
| 		wipe(tbl)
 | |
| 	end
 | |
| 	for i, spellId in ipairs(spells) do
 | |
| 		private.spellInfoTemp.spellIds[i] = spellId
 | |
| 		private.spellInfoTemp.mats[i] = TSM.db.factionrealm.internalData.crafts[spellId].mats
 | |
| 		private.spellInfoTemp.itemStrings[i] = TSM.db.factionrealm.internalData.crafts[spellId].itemString
 | |
| 		private.spellInfoTemp.names[i] = TSM.db.factionrealm.internalData.crafts[spellId].name
 | |
| 		private.spellInfoTemp.numResults[i] = TSM.db.factionrealm.internalData.crafts[spellId].numResult
 | |
| 		private.spellInfoTemp.hasCDs[i] = TSM.db.factionrealm.internalData.crafts[spellId].hasCD
 | |
| 	end
 | |
| 	Log.Info("Sent %d spells", #private.spellInfoTemp.spellIds)
 | |
| 	return UnitName("player"), professionLookup, private.spellInfoTemp
 | |
| end
 | |
| 
 | |
| function private.RPCGetSpellInfoResultHandler(player, professionLookup, spellInfo)
 | |
| 	if not player or not professionLookup or not spellInfo or not private.accountLookup[player] then
 | |
| 		-- request timed out, so try again from the start
 | |
| 		Log.Warn("Getting spell info timed out")
 | |
| 		if private.accountLookup[player] then
 | |
| 			private.accountStatus[private.accountLookup[player]] = "RETRY"
 | |
| 			Delay.AfterTime(RETRY_DELAY, private.RetryGetHashesRPC)
 | |
| 		end
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	for i, spellId in ipairs(spellInfo.spellIds) do
 | |
| 		TSM.Crafting.CreateOrUpdate(spellId, spellInfo.itemStrings[i], professionLookup[spellId], spellInfo.names[i], spellInfo.numResults[i], player, spellInfo.hasCDs[i] and true or false)
 | |
| 		for itemString in pairs(spellInfo.mats[i]) do
 | |
| 			TSM.db.factionrealm.internalData.mats[itemString] = TSM.db.factionrealm.internalData.mats[itemString] or {}
 | |
| 		end
 | |
| 		TSM.Crafting.SetMats(spellId, spellInfo.mats[i])
 | |
| 	end
 | |
| 	Log.Info("Added %d spells from %s", #spellInfo.spellIds, player)
 | |
| 	private.accountStatus[private.accountLookup[player]] = "SYNCED"
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| -- ============================================================================
 | |
| -- Private Helper Functions
 | |
| -- ============================================================================
 | |
| 
 | |
| function private.ConnectionChangedHandler(account, player, connected)
 | |
| 	if connected then
 | |
| 		private.accountLookup[player] = account
 | |
| 		private.accountStatus[account] = "UPDATING"
 | |
| 		-- issue a request for profession info
 | |
| 		Sync.CallRPC("CRAFTING_GET_HASHES", player, private.RPCGetHashesResultHandler)
 | |
| 	else
 | |
| 		private.accountLookup[player] = nil
 | |
| 		private.accountStatus[account] = nil
 | |
| 	end
 | |
| end
 | |
| 
 | |
| function private.RetryGetHashesRPC()
 | |
| 	for player, account in pairs(private.accountLookup) do
 | |
| 		if private.accountStatus[account] == "RETRY" then
 | |
| 			Sync.CallRPC("CRAFTING_GET_HASHES", player, private.RPCGetHashesResultHandler)
 | |
| 		end
 | |
| 	end
 | |
| end
 | |
| 
 | |
| function private.QueryProfessionFilter(row, professions)
 | |
| 	return professions[row:GetField("profession")]
 | |
| end
 | |
| 
 | |
| function private.QueryPlayerFilter(row, player)
 | |
| 	return String.SeparatedContains(row:GetField("players"), ",", player)
 | |
| end
 | |
| 
 | |
| function private.GetPlayerProfessionHashes(player, resultTbl)
 | |
| 	local query = TSM.Crafting.CreateRawCraftsQuery()
 | |
| 		:Custom(private.QueryPlayerFilter, player)
 | |
| 		:OrderBy("spellId", true)
 | |
| 	query:GroupedHash(PROFESSION_HASH_FIELDS, "profession", resultTbl)
 | |
| 	query:Release()
 | |
| end
 |