From b26c5dba080b3780263f8110560028c62fe48b56 Mon Sep 17 00:00:00 2001 From: Manuel Simon Hirsig Date: Thu, 25 Feb 2016 08:09:14 +0100 Subject: [PATCH] working on big scan/control refactoring --- control.lua | 30 ++++++- scan.lua | 217 ++++++++++++++++++++++++----------------------- search_frame.lua | 2 +- 3 files changed, 143 insertions(+), 106 deletions(-) diff --git a/control.lua b/control.lua index edeb593..f59fe3f 100644 --- a/control.lua +++ b/control.lua @@ -1,7 +1,9 @@ -Aux.control = {} +local private, public = {}, {} +Aux.control = public local event_listeners = {} local update_listeners = {} +private.threads = {} function Aux.control.on_event() for listener, _ in pairs(event_listeners) do @@ -20,6 +22,13 @@ function Aux.control.on_update() listener.action() end end + + for thread_id, k in pairs(private.threads) do + private.threads[thread_id] = nil + public.thread_id = thread_id + k() + public.thread_id = nil + end end @@ -143,3 +152,22 @@ function Aux.control.controller() return self end + +do + local next_thread_id = 1 + function public.new(k) + local thread_id = next_thread_id + next_thread_id = next_thread_id + 1 + private.threads[thread_id] = k + return thread_id + end +end + +function public.kill(thread_id) + private.threads[thread_id] = nil +end + +function public.wait(...) + local k = tremove(arg, 1) + private.threads[public.thread_id] = function() return k(unpack(arg)) end +end diff --git a/scan.lua b/scan.lua index e2406cd..19cb15c 100644 --- a/scan.lua +++ b/scan.lua @@ -3,17 +3,10 @@ Aux.scan = public local PAGE_SIZE = 50 -local controller = (function() - local controller - return function() - controller = controller or Aux.control.controller() - return controller - end -end)() - local state +local threads = {} -local scan_auctions, scan_auctions_helper, submit_query, wait_for_callback, wait_for_results, wait_for_owner_data, abort, current_query +local scan_auctions, scan_auctions_helper, submit_query, wait_for_callback, wait_for_owner_data, abort, current_query, current_thread function private.default_next_page(page, total_pages) local last_page = max(total_pages - 1, 0) @@ -23,79 +16,102 @@ function private.default_next_page(page, total_pages) end function current_query() - return state.params.queries[state.query_index] + return current_thread().params.queries[current_thread().query_index] +end + +function current_thread() + return threads[Aux.control.thread_id] end function public.start(params) - return controller().wait(function() return true end, function() - abort() + private.abort(params.type) - state = { - params = params, - } - - private.scan() - end) + local thread_id = Aux.control.new(private.scan) + threads[thread_id] = { + params = params, + } end function public.abort(k) - return controller().wait(function() return true end, function() - abort() + private.abort() - if k then - return k() + if k then + return k() + end +end + +function private.abort(type) + for thread_id, thread in pairs(threads) do + if not type or type == thread.type then + if thread.on_abort then + thread.on_abort() + end + threads[thread_id] = nil + Aux.control.kill(thread_id) end + end +end + +function private.as_soon_as(p, k) + if p() then + return k() + else + return Aux.control.wait(private.as_soon_as, p, k) + end +end + +function private.wait_for_results(k) + if current_thread().type == 'bidder' then + return private.wait_for_bidder_results(k) + elseif current_thread().type == 'owner' then + return private.wait_for_owner_results(k) + elseif current_thread().type == 'list' then + return private.wait_for_list_results(k) + end +end + +function private.wait_for_bidder_results(k) + if Aux.bids_loaded then + return k() + else -- recurse on the next update + return Aux.control.wait(private.wait_for_bidder_results, k) + end +end + +function private.wait_for_owner_results(k) + local updated + Aux.control.on_next_event('AUCTION_OWNED_LIST_UPDATE', function() + updated = true + end) + + private.as_soon_as(function() return updated end, k) +end + +function private.wait_for_list_results(k) + local updated, last_update + local listener = Aux.control.event_listener('AUCTION_ITEM_LIST_UPDATE', function() + last_update = GetTime() + updated = true + end) + listener:start() + private.as_soon_as(function() + -- order important, owner_data_complete must be called after an update to request missing data + local ok = updated and private.owner_data_complete() or last_update and GetTime() - last_update > 5 + updated = false + return ok + end, function() + listener:stop() + return k() end) end -function abort() - local on_abort = Aux.util.safe_index{state, 'params', 'on_abort' } - state = nil - if on_abort then - return on_abort() - end -end - -function wait_for_results(k) - - local ok - if current_query().type == 'bidder' then - Aux.control.as_soon_as(function() return Aux.bids_loaded end, function() - ok = true - end) - elseif current_query().type == 'owner' then - if state.page == Aux.current_owner_page then - ok = true - else - Aux.control.on_next_event('AUCTION_OWNED_LIST_UPDATE', function() - ok = true - end) - end - else - local last_update - local owner_data_complete - local listener = Aux.control.event_listener('AUCTION_ITEM_LIST_UPDATE') - listener:set_action(function() - owner_data_complete = state and private.owner_data_complete() - last_update = GetTime() - end) - listener:start() - Aux.control.as_soon_as(function() return owner_data_complete or last_update and GetTime() - last_update > 5 end, function() - listener:stop() - ok = true - end) - end - - return controller().wait(function() return ok end, k) -end - function private.owner_data_complete() - if state.params.no_wait_owner then + if current_thread().params.no_wait_owner then return true end - local count, _ = GetNumAuctionItems(current_query().type) + local count, _ = GetNumAuctionItems(current_thread().type) for i=1,count do - local auction_info = Aux.info.auction(i, current_query().type) + local auction_info = Aux.info.auction(i, current_thread().type) if auction_info and not auction_info.owner then return false end @@ -103,13 +119,6 @@ function private.owner_data_complete() return true end -function private.request_owner_data() - local count, _ = GetNumAuctionItems(current_query().type) - for i=1,count do - Aux.info.auction(i, current_query().type) - end -end - function wait_for_callback(args) -- the arguments must not be nil! local ok = true @@ -126,25 +135,25 @@ function wait_for_callback(args) -- the arguments must not be nil! if ok then return k() - else - return controller().wait(function() return ok end, k) + else + return private.as_soon_as(function() return ok end, k) end end function private.scan() - local start_query_index = state.params.start_query_index or 1 - local next_query_index = state.params.next_query_index or function(query_index) return query_index + 1 end + local start_query_index = current_thread().params.start_query_index or 1 + local next_query_index = current_thread().params.next_query_index or function(query_index) return query_index + 1 end - state.query_index = state.query_index and next_query_index(state.query_index) or start_query_index + current_thread().query_index = current_thread().query_index and next_query_index(current_thread().query_index) or start_query_index if current_query() then - wait_for_callback{state.params.on_start_query or Aux.util.pass, state.query_index, function() - state.page = current_query().start_page + wait_for_callback{current_thread().params.on_start_query or Aux.util.pass, current_thread().query_index, function() + current_thread().page = current_query().start_page return private.process_query() end } else - local on_complete = state.params.on_complete - state = nil + local on_complete = current_thread().params.on_complete + threads[Aux.control.thread_id] = nil if on_complete then return on_complete() end @@ -155,18 +164,18 @@ function private.process_query() submit_query(function() - local count, _ = GetNumAuctionItems(current_query().type) + local count, _ = GetNumAuctionItems(current_thread().type) scan_auctions(count, function() - wait_for_callback{state.params.on_page_scanned or Aux.util.pass, function() + wait_for_callback{current_thread().params.on_page_scanned or Aux.util.pass, function() if current_query().next_page then - state.page = current_query().next_page(state.page, state.total_pages) + current_thread().page = current_query().next_page(current_thread().page, current_thread().total_pages) else - state.page = private.default_next_page(state.page, state.total_pages) + current_thread().page = private.default_next_page(current_thread().page, current_thread().total_pages) end - if state.page then + if current_thread().page then return private.process_query() else return private.scan() @@ -189,16 +198,16 @@ function scan_auctions_helper(i, n, k) end end - local auction_info = Aux.info.auction(i, current_query().type) + local auction_info = Aux.info.auction(i, current_thread().type) if auction_info then auction_info.index = i - auction_info.page = state.page + auction_info.page = current_thread().page auction_info.query = current_query() Aux.history.process_auction(auction_info) if not current_query().validator or current_query().validator(auction_info) then - return wait_for_callback{state.params.on_read_auction or Aux.util.pass, auction_info, recurse } + return wait_for_callback{current_thread().params.on_read_auction or Aux.util.pass, auction_info, recurse } end end @@ -206,16 +215,16 @@ function scan_auctions_helper(i, n, k) end function submit_query(k) - if state.page then - controller().wait(function() return current_query().type ~= 'list' or CanSendAuctionQuery() end, function() + if current_thread().page then + private.as_soon_as(function() return current_thread().type ~= 'list' or CanSendAuctionQuery() end, function() - if state.params.on_submit_query then - state.params.on_submit_query() + if current_thread().params.on_submit_query then + current_thread().params.on_submit_query() end - if current_query().type == 'bidder' then - GetBidderAuctionItems(state.page) - elseif current_query().type == 'owner' then - GetOwnerAuctionItems(state.page) + if current_thread().type == 'bidder' then + GetBidderAuctionItems(current_thread().page) + elseif current_thread().type == 'owner' then + GetOwnerAuctionItems(current_thread().page) else QueryAuctionItems( Aux.util.safe_index{current_query(), 'blizzard_query', 'name'}, @@ -224,16 +233,16 @@ function submit_query(k) Aux.util.safe_index{current_query(), 'blizzard_query', 'slot'}, Aux.util.safe_index{current_query(), 'blizzard_query', 'class'}, Aux.util.safe_index{current_query(), 'blizzard_query', 'subclass'}, - state.page, + current_thread().page, Aux.util.safe_index{current_query(), 'blizzard_query', 'usable'}, Aux.util.safe_index{current_query(), 'blizzard_query', 'quality'} ) end - wait_for_results(function() - local _, total_count = GetNumAuctionItems(current_query().type) - state.total_pages = math.ceil(total_count / PAGE_SIZE) - if state.total_pages >= state.page + 1 then - wait_for_callback{state.params.on_page_loaded or Aux.util.pass, state.page, state.total_pages, function() + private.wait_for_results(function() + local _, total_count = GetNumAuctionItems(current_thread().type) + current_thread().total_pages = math.ceil(total_count / PAGE_SIZE) + if current_thread().total_pages >= current_thread().page + 1 then + wait_for_callback{current_thread().params.on_page_loaded or Aux.util.pass, current_thread().page, current_thread().total_pages, function() return k() end} else diff --git a/search_frame.lua b/search_frame.lua index aa7cf4e..622fa43 100644 --- a/search_frame.lua +++ b/search_frame.lua @@ -783,7 +783,6 @@ function public.start_search(filter_string) if filters then queries = Aux.util.map(filters, function(filter) return { - type = 'list', start_page = 0, blizzard_query = Aux.scan_util.blizzard_query(filter), validator = Aux.scan_util.validator(filter), @@ -813,6 +812,7 @@ function public.start_search(filter_string) local current_page, current_total_pages, current_query Aux.scan.start{ + type = 'list', queries = queries, on_page_loaded = function(page, total_pages) current_page = page + 1