File copas/eventer.lua
The eventer is an event dispatcher. It works on top of Copas Timer using the workers to create event threads. The eventer uses a publish/subscribe mechanism with servers and clients. The servers should register before firing any events, and the clients should subscribe to server events.
 
Dispatching creates a separate worker (thread/coroutine) for each client that has to receive the event. This means that separate threads will have been scheduled but not executed when an event is dispatched. Execution follows later when the Copas Timer loop continues to handle its worker queue in the background. The eventer will create a global table; copas.eventer
, but that should generally not be used except for the copas.eventer.decorate()
method which will provide an object/table with event capabilities.
 
This module is part of Copas Timer and is free software under the MIT/X11 license.
Copyright ©2011-2012 Thijs Schreijer
Release: Version 0.4.2, Timer module to extend Copas with a timer and worker capability
Functions
clientsubscribe (client, server, handler, event) | subscribes a client to events |
clientunsubscribe (client, server, event) | unsubscribes a client from events |
decorate (server, events) | Decorates an object as an event server. |
e.cancel (self) | Removes all event related workers from the copas background worker queue. |
e.event () | The event string. |
e.finish (self, timeout) | Waits for an event to be completed in a blocking mode. |
e.threads () | Table with threads (coroutines) created. |
e.waitfor (self, timeout) | Waits for an event to be completed. |
getclients (server) | Gets a list of clients of a particular server. |
getsubscriptions (client) | Gets a list of subscriptions of a particular client. |
s.dispatch (self, event, ...) | Dispatches an event for this server. |
s.events () | Table (as a set) with the event strings for this server. |
s.subscribe (self, client, handler, event) | Subscribes a client to the events of this server. |
s.unsubscribe (self, client, event) | Unsubscribes a client from the events of this server. |
serverdispatch (server, event, ...) | dispatches an event from a server |
serverregister (server, eventlist) | registers a server that will fire events |
serverunregister (server) | unregisters a server that will fire events |
Tables
copas.eventer.events | Event list for eventer (events generated by it). |
copas.events | Event list for Copas itself. |
Functions
- clientsubscribe (client, server, handler, event)
-
subscribes a client to events
Parameters
- client: unique client parameter (self)
- server: a unique key to identify the specific server
-
handler: event handler function to be called. It will be called with signature
handler(client, server, event, [additional event parameters...])
or in method notation;client:handler(server, event, [additional event parameters...])
. -
event: string,
nil
to subscribe to all events
- clientunsubscribe (client, server, event)
-
unsubscribes a client from events
Parameters
- client: unique client parameter (self)
-
server: a unique key to identify the specific server,
nil to unsubscribe all -
event: string,
nil
to unsubscribe from all events
- decorate (server, events)
-
Decorates an object as an event server. It will provide the object with the following methods/tables;
s:subscribe(client, handler, event)
s:unsubscribe(client, event)
s:dispatch(event, ...)
s.events
eventer
methodsclientsubscribe, clientunsubscribe, serverdispatch
.Parameters
- server: The event server object that will be decorated with the methods and tables listed above.
-
events: A list of event strings. This list will be copied to a new table (as a set) and stored in
server.events
See also:
- e.cancel (self)
-
Removes all event related workers from the copas background worker queue. Threads will remain in the event object itself, but will no longer be executed as background workers.
Parameters
- self:
- e.event ()
- The event string. (this is a field, not a function)
- e.finish (self, timeout)
-
Waits for an event to be completed in a blocking mode. That is; all event threads spawned have died (this does not include additional threads spawned from them). Current thread will NOT yield while waiting, it will only process the event related threads. It is blocking, so timers, sockets and workers will not run in the mean time, so executing this method may take a long time so use carefully!
 If it should not block, then usewaitfor()
.Parameters
- self:
-
timeout: timeout (in seconds), use
nil
for no timeout
Return value:
true
when completed, ornil, "timeout"
in case of a timeout.See also:
- e.threads ()
- Table with threads (coroutines) created. One for each event handler dispatched.
- e.waitfor (self, timeout)
-
Waits for an event to be completed. That is; all event threads spawned have died, this does not include additional threads spawned from them. Current thread will yield while waiting (so cannot be used from the mainthread!).
Parameters
- self:
-
timeout: timeout (in seconds), use
nil
for no timeout
Return value:
true
when completed, ornil, "timeout"
in case of a timeout.See also:
- getclients (server)
-
Gets a list of clients of a particular server.
Parameters
- server: the server for which to get the subscribed clients
Usage:
local list = copas.eventer.getclients(copas) -- get list of Copas clients
list = list[copas.events.loopstarted] -- get clients of the 'loopstarted' event
print ("the Copas 'loopstarted' event has " .. #list .. " clients subscribed.")Return value:
nil
if the server is unregistered, otherwise a table with subscriptions. The result table is keyed by 'event string' and each value is a list of clients that is subscribed to this event. - getsubscriptions (client)
-
Gets a list of subscriptions of a particular client.
Parameters
- client: the client for which to get the subscriptions
Return value:
nil
if the client has no subscriptions, otherwise a table with subscriptions. The result table is keyed by 'server' and each value is a list of eventstrings the client is subscribed to on this server. - s.dispatch (self, event, ...)
-
Dispatches an event for this server. It functions as a shortcut to
serverdispatch()
.Parameters
- self:
- event: event string of the event to dispatch
- ...: any additional event parameters
Usage:
-- create an object and decorate it with event capabilities
local obj1 = {}
copas.eventer.decorate(obj1, { "start", "error", "stop" } )
 
..... do some stuff, subscribe to events, start the copas loop, etc.
 
-- raise the start event and include th starttime as an extra
-- parameter to be passed to the eventhandlers
local e = obj1:dispatch(obj1.events.start, socket.gettime())
-- now wait for the event to be completely handled
e:waitfor()See also:
- s.events ()
-
Table (as a set) with the event strings for this server.
See also:
- s.subscribe (self, client, handler, event)
-
Subscribes a client to the events of this server. It functions as a shortcut to
clientsubscribe()
.Parameters
- self:
- client: the client identifier (usually the client object table)
- handler: the handler function for the event
-
event: the event to subscribe to or
nil
to subscribe to all events
Usage:
-- create an object and decorate it with event capabilities
local obj1 = {}
copas.eventer.decorate(obj1, { "start", "error", "stop" } )
 
-- create another object and subscribe to events of obj1
local obj2 = {
    eventhandler = function(self, sender, event, ...)
        print ("received event: " .. event)
    end
}
obj1:subscribe(obj2, obj1.events.stop)
 
..... do some stuff, start the copas loop, etc.
 
-- raise the stop event
local e = obj1:dispatch(obj1.events.stop)See also:
- s.unsubscribe (self, client, event)
-
Unsubscribes a client from the events of this server. It functions as a shortcut to
clientunsubscribe()
.Parameters
- self:
- client: the client identifier (usually the client object table), must be the same as used while subscribing.
-
event: the event to unsubscribe from or
nil
to unsubscribe from all events
See also:
- serverdispatch (server, event, ...)
-
dispatches an event from a server
Parameters
- server: a unique key to identify the specific server
- event: string
- ...: other arguments to be passed on as arguments to the eventhandler
Return value:
eventobject, see the 'see' section below.See also:
- serverregister (server, eventlist)
-
registers a server that will fire events
Parameters
- server: a unique key to identify the specific server, can be a string or table, or whatever, as long as it is unique
- eventlist: list of strings with event names (table keys are unused, only values, so may also be a set)
- serverunregister (server)
-
unregisters a server that will fire events
Parameters
- server: a unique key to identify the specific server, can be a string or table, or whatever, as long as it is unique
Tables
- copas.eventer.events
- Event list for eventer (events generated by it).
Fields
- register: Fired whenever a new server registers events (note: 'copas' and 'copas.eventer' will have been registered before any client had a chance to subscribe, so these subscriptions cannot be caught by using this event)
- unregister: Fired whenever a server unregisters its events
- subscribe: Fired whenever a client subscribes to events
- unsubscribe: Fired whenever a client unsubscribes from events
- copas.events
- Event list for Copas itself. The event structure for Copas will only be initialized when the eventer is used.
Fields
-
loopstarting: Fired before the copas loop starts. It will immediately be finished (see
e.finish()
). So while the event threads run there will be no timers, sockets, nor workers running. Only the threads created for the 'loopstarting' event will run. - loopstarted: Fired when the Copas loop has started, by now timers, sockets and workers are running.
- loopstopping: Fired the Copas loop starts exiting. For as long as not all event threads (for this specific event) have finished, the timers, sockets and workers will keep running.
-
loopstopped: Fired after the Copas loop has finished, this event will immediately be finished (see
e.finish()
), so the timers, sockets and workers no longer run.
-
loopstarting: Fired before the copas loop starts. It will immediately be finished (see