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 支持修改当前时间,供调试用。