Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --@name Task Library
- --@author Szymekk
- --------------------------------------
- -- Task class
- --------------------------------------
- local task = { }
- task.__index = task
- function task:init(func)
- self._func = func
- self._running = false -- The task has been run once and haven't finished
- self._finished = false -- The has returned - self.result should not be nil
- self.result = nil -- Values retured from the task as a table
- self._parent = nil -- Waiting parent of the task, should be awoken after the current task finishes
- self._async = nil -- Async object of the task, when true - parent should be awoken
- self._coroutine = coroutine.create(function(...)
- local result = { func(...) }
- if self._async then
- result = { coroutine.yield() } -- Wait for async:release()
- self._async = nil
- self.result = result
- self._running = false
- self._finished = true
- -- Resume the parent
- if self._parent then
- local parent = self._parent
- self._async = nil
- self._parent = nil
- local prevTask = tasks.current
- tasks.current = parent
- coroutine.resume(parent._coroutine)
- tasks.current = prevTask
- end
- end
- return unpack(returned)
- end)
- end
- --- Runs or resumes the task
- function task:run(...)
- -- Waiting for an asynchronic task - it's resumed somewhere else
- if self._waiting then
- return
- end
- if self._async then
- return
- end
- if self._finished then
- error("Cannot run finished task")
- end
- -- The task is running for the first time
- if not self._running then
- self._running = true
- end
- local prevTask = tasks.current
- tasks.current = self
- local result
- local args = { ... }
- xpcall(function() -- Temporary workaround
- result = { coroutine.resume(self._coroutine, unpack(args)) }
- end, function(err)
- -- TODO: Check if the error is the weird one
- error(err)
- end)
- tasks.current = prevTask
- -- The task could become async
- if self._async and self._async ~= true then
- return
- end
- -- When task finished the work
- if coroutine.status(self._coroutine) == "dead" then
- self.result = result
- self._running = false
- self._finished = true
- end
- end
- task.resume = task.run
- --- Makes the current task pause until this task finishes
- function task:wait(...)
- local parent = tasks.current
- self._parent = parent
- self:run(...)
- -- The task haven't finished yet - it's probably asynchronic
- if not self._finished then
- parent._waiting = true
- coroutine.yield()
- parent._waiting = false
- end
- self._parent = nil
- return unpack(self.result)
- end
- --------------------------------------
- -- Creation
- --------------------------------------
- tasks = { }
- tasks.current = nil -- Currently running task
- function tasks.new(func)
- local tbl = { }
- setmetatable(tbl, task)
- tbl:init(func)
- return tbl
- end
- --------------------------------------
- -- Async
- --------------------------------------
- local async = { }
- async.__index = async
- function async:init(task)
- self._task = task
- end
- --- Finishes an asynchronic task.
- --- Any parameters passed to this function
- --- will be the task's result.
- function async:release(...)
- local args = { ... }
- local prevTask = tasks.current
- tasks.current = self._task
- pcall(function()
- coroutine.resume(self._task._coroutine, unpack(args)) -- This function errors and won't go further, pcall is a temporary fix
- end)
- tasks.current = prevTask
- end
- function async.new(...)
- local tbl = { }
- setmetatable(tbl, async)
- tbl:init(...)
- return tbl
- end
- --- Makes the current task asynchronic.
- --- It won't finish as soon as its function returns,
- --- but an async object will be returned - calling
- --- async:release(toReturn) will finish the task.
- function tasks.makeAsync()
- local asyncObj = async.new(tasks.current)
- tasks.current._async = asyncObj
- return asyncObj
- end
- --------------------------------------
- -- Testing
- --------------------------------------
- if CLIENT then
- function tasks.download(url)
- return tasks.new(function()
- local async = tasks.makeAsync()
- http.get(url, function(body)
- async:release(body)
- end, function()
- async:release()
- end)
- end)
- end
- function tasks.wait(duration)
- return tasks.new(function()
- local async = tasks.makeAsync()
- timer.simple(duration, function()
- async:release()
- end)
- end)
- end
- -- Create a new task
- local tsk = tasks.new(function()
- local data = tasks.download("https://blockchain.info/ticker"):wait() -- Downloads data and waits for it
- print(data)
- tasks.wait(2):wait() -- Uses a timer to sleep 2 seconds
- data = tasks.download("https://blockchain.info/tobtc?currency=USD&value=500"):wait()
- print("And another! - ", data)
- end)
- tsk:run() -- Run it
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement