Skynet服务器框架(十一) 日程表服务


from 云风blog

 

这样一个日程表服务并不复杂,我花了一点时间随手实现了一个,供大家参考。它应该有很大的改进空间,明白了其设计之后,应该不难完善它:

local skynet = require "skynet"
local service = require "skynet.service"

local schedule = {}
local service_addr

-- { month=, day=, wday=, hour= , min= }
function schedule.submit(ti)
    return skynet.call(service_addr, "lua", ti)
end

function schedule.changetime(ti)
    local tmp = {}
    for k,v in pairs(ti) do
        tmp[k] = v
    end
    tmp.changetime = true
    return skynet.call(service_addr, "lua", tmp)
end

skynet.init(function()
    local schedule_service = function()
-- schedule service

local skynet = require "skynet"

local task = { session = 0, difftime = 0 }

local function next_time(now, ti)
    local nt = {
        year = now.year ,
        month = now.month ,
        day = now.day,
        hour = ti.hour or 0,
        min = ti.min or 0,
        sec = ti.sec,
    }
    if ti.wday then
        -- set week
        assert(ti.day == nil and ti.month == nil)
        nt.day = nt.day + ti.wday - now.wday
        local t = os.time(nt)
        if t < now.time then
            nt.day = nt.day + 7
        end
    else
        -- set day, no week day
        if ti.day then
            nt.day = ti.day
        end
        if ti.month then
            nt.month = ti.month
        end
        local t = os.time(nt)
        if t < now.time then
            if ti.month then
                nt.year = nt.year + 1   -- next year
            else
                nt.month = nt.month + 1 -- next month
            end
        end
    end

    return os.time(nt)
end

local function changetime(ti)
    local ct = math.floor(skynet.time())
    local current = os.date("*t", ct)
    current.time = ct
    if not ti.hour then
        ti.hour = current.hour
    end
    if not ti.min then
        ti.min = current.min
    end
    ti.sec = current.sec
    local nt = next_time(current, ti)
    skynet.error(string.format("Change time to %s", os.date(nil, nt)))
    task.difftime = os.difftime(nt,ct)
    for k,v in pairs(task) do
        if type(v) == "table" then
            skynet.wakeup(v.co)
        end
    end
    skynet.ret()
end

local function submit(_, addr, ti)
    if ti.changetime then
        return changetime(ti)
    end
    local session = task.session + 1
    task.session = session
    repeat
        local ct = math.floor(skynet.time()) + task.difftime
        local current = os.date("*t", ct)
        current.time = ct
        local nt = next_time(current, ti)
        task[session] = { time = nt, co = coroutine.running(), address = addr }
        local diff = os.difftime(nt , ct)
        print("sleep", diff)
    until skynet.sleep(diff * 100) ~= "BREAK"
    task[session] = nil
    skynet.ret()
end

skynet.start(function()
    skynet.dispatch("lua", submit)
    skynet.info_func(function()
        local info = {}
        for k, v in pairs(task) do
            if type(v) == "table" then
                table.insert( info, {
                    time = os.date(nil, v.time),
                    address = skynet.address(v.address),
                })
            end
            return info
        end
    end)
end)

-- end of schedule service
    end

    service_addr = service.new("schedule", schedule_service)
end)

return schedule

用 schedule.submit 可以申请一个时间点,到时后会返回。使用的时候只需要用 skynet.fork 开一个独立线程,循环调用 schedule.submit 即可。

schedule.changetime 支持修改当前时间,供调试用。

posted @ 2017-11-28 10:33  decode126  阅读(389)  评论(0编辑  收藏  举报