DSM: groups module

Development of this module was sponsored by TelTech Systems Inc.

The groups module implements a group event broadcast system. DSM calls can
join and leave groups, and post events to groups. Events are passed to all
members of the group that the event is posted to. Events can, just like the
`postEvent` function of DSM, contain either some variables, or all variables.
If a call ends, it is automatically removed from all groups it belongs to.

Actions:

  groups.join(groupname)            -  Join a group
  groups.leave(groupname)           -  Leave a group
  groups.leaveAll()                 -  Leave all groups
  groups.postEvent(groupname, var1;var2)  -  post event to groupname with var1 and var2
  groups.postEvent(groupname, var)  -  post event to groupname with all variables
sayer/1.4-spce2.6
Stefan Sayer 16 years ago
parent aee8585091
commit cad6589d67

@ -0,0 +1,7 @@
set (mod_groups_SRCS
ModGroups.cpp
)
SET(sems_dsm_module_name mod_groups)
INCLUDE(${CMAKE_SOURCE_DIR}/cmake/dsm.lib.rules.txt)

@ -0,0 +1,10 @@
plug_in_name = mod_groups
DSMPATH ?= ../..
module_ldflags =
module_cflags = -DMOD_NAME=\"$(plug_in_name)\" -I$(DSMPATH)
COREPATH ?=$(DSMPATH)/../../core
lib_full_name = $(DSMPATH)/mods/lib/$(lib_name)
include $(DSMPATH)/mods/Makefile.dsm_module

@ -0,0 +1,175 @@
/*
* Copyright (C) 2010 Stefan Sayer
*
* Development of this module was sponsored by TelTech Systems Inc
*
* This file is part of SEMS, a free SIP media server.
*
* SEMS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* SEMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ModGroups.h"
#include "log.h"
#include "AmUtils.h"
#include "DSMSession.h"
#include "AmSession.h"
#include "AmSessionContainer.h"
SC_EXPORT(MOD_CLS_NAME);
AmMutex GroupsModule::groups_mut;
GroupMap GroupsModule::groups;
GroupMap GroupsModule::groups_rev;
MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
DEF_CMD("groups.join", GroupsJoinAction);
DEF_CMD("groups.leave", GroupsLeaveAction);
DEF_CMD("groups.leaveAll", GroupsLeaveAllAction);
// DEF_CMD("groups.get", GroupsGetAction);
// DEF_CMD("groups.getMembers", GroupsGetMembersAction);
DEF_CMD("groups.postEvent", GroupsPostEventAction);
} MOD_ACTIONEXPORT_END;
MOD_CONDITIONEXPORT_NONE(MOD_CLS_NAME);
void GroupsModule::onBeforeDestroy(DSMSession* sc_sess, AmSession* sess) {
leave_all_groups(sess->getLocalTag());
}
void GroupsModule::leave_all_groups(const string& ltag) {
GroupsModule::groups_mut.lock();
GroupMap::iterator it = GroupsModule::groups_rev.find(ltag);
if (it != GroupsModule::groups_rev.end()) {
set<string>& active_groups = it->second;
for (set<string>::iterator ag_it =
active_groups.begin(); ag_it != active_groups.end(); ag_it++) {
GroupsModule::groups[*ag_it].erase(ltag);
if (GroupsModule::groups[*ag_it].empty()) {
DBG("clearing empty group '%s'\n", ag_it->c_str());
GroupsModule::groups.erase(*ag_it);
}
}
GroupsModule::groups_rev.erase(it);
}
GroupsModule::groups_mut.unlock();
}
EXEC_ACTION_START(GroupsJoinAction) {
string groupname = resolveVars(arg, sess, sc_sess, event_params);
DBG("call '%s' joining group '%s'\n",
sess->getLocalTag().c_str(), groupname.c_str());
GroupsModule::groups_mut.lock();
GroupsModule::groups[groupname].insert(sess->getLocalTag());
GroupsModule::groups_rev[sess->getLocalTag()].insert(groupname);
GroupsModule::groups_mut.unlock();
} EXEC_ACTION_END;
EXEC_ACTION_START(GroupsLeaveAction) {
string groupname = resolveVars(arg, sess, sc_sess, event_params);
string ltag = sess->getLocalTag();
DBG("call '%s' leaving group '%s'\n",
ltag.c_str(), groupname.c_str());
GroupsModule::groups_mut.lock();
GroupMap::iterator it = GroupsModule::groups.find(groupname);
if (it != GroupsModule::groups.end()) {
it->second.erase(ltag);
if (it->second.empty()) {
DBG("clearing empty group '%s'\n", groupname.c_str());
GroupsModule::groups.erase(it);
}
}
it = GroupsModule::groups_rev.find(ltag);
if (it != GroupsModule::groups_rev.end()) {
it->second.erase(groupname);
if (it->second.empty()) {
DBG("call '%s' in no group any more\n", ltag.c_str());
GroupsModule::groups_rev.erase(it);
}
}
GroupsModule::groups_mut.unlock();
} EXEC_ACTION_END;
EXEC_ACTION_START(GroupsLeaveAllAction) {
string ltag = sess->getLocalTag();
DBG("call '%s' leaving all groups\n", ltag.c_str());
GroupsModule::leave_all_groups(ltag);
} EXEC_ACTION_END;
CONST_ACTION_2P(GroupsPostEventAction, ',', true);
EXEC_ACTION_START(GroupsPostEventAction) {
string groupname = resolveVars(par1, sess, sc_sess, event_params);
string var = resolveVars(par2, sess, sc_sess, event_params);
map<string, string> ev_params;
if (!var.empty()) {
if (var == "var")
ev_params = sc_sess->var;
else {
vector<string> vars = explode(var, ";");
for (vector<string>::iterator it =
vars.begin(); it != vars.end(); it++)
ev_params[*it] = sc_sess->var[*it];
}
}
DBG("posting event to group '%s'\n", groupname.c_str());
GroupsModule::groups_mut.unlock();
GroupMap::iterator grp = GroupsModule::groups.find(groupname);
bool posted = false;
if (grp != GroupsModule::groups.end()) {
for (set<string>::iterator it =
grp->second.begin(); it != grp->second.end(); it++) {
if (*it == sess->getLocalTag())
continue; // don't post to myself
DSMEvent* ev = new DSMEvent();
ev->params = ev_params;
if (!AmSessionContainer::instance()->postEvent(*it, ev)) {
DBG("could not post to call '%s'\n", it->c_str());
} else {
DBG("posted event to call '%s'\n", it->c_str());
posted = true;
}
}
}
GroupsModule::groups_mut.unlock();
if (posted) {
sc_sess->CLR_ERRNO;
} else {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("event could not be posted\n");
}
} EXEC_ACTION_END;

@ -0,0 +1,67 @@
/*
* Copyright (C) 2010 Stefan Sayer
*
* Development of this module was sponsored by TelTech Systems Inc
*
* This file is part of SEMS, a free SIP media server.
*
* SEMS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* SEMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _MOD_MYSQL_H
#define _MOD_MYSQL_H
#include "DSMModule.h"
#include "DSMSession.h"
#include "AmThread.h"
#define MOD_CLS_NAME GroupsModule
#include <set>
using std::set;
#include <map>
using std::map;
#include <string>
using std::string;
typedef map<string, set<string> > GroupMap;
DECLARE_MODULE_BEGIN(MOD_CLS_NAME);
static AmMutex groups_mut;
// group name ltags
static GroupMap groups;
// ltags groups
static GroupMap groups_rev;
static void leave_all_groups(const string& ltag);
void onBeforeDestroy(DSMSession* sc_sess, AmSession* sess);
DECLARE_MODULE_END;
DEF_ACTION_1P(GroupsJoinAction);
DEF_ACTION_1P(GroupsLeaveAction);
DEF_ACTION_1P(GroupsLeaveAllAction);
/* DEF_ACTION_1P(GroupsGetAction); */
/* DEF_ACTION_1P(GroupsGetMembersAction); */
DEF_ACTION_2P(GroupsPostEventAction);
#endif

@ -0,0 +1,56 @@
mod_groups - Group event passing
Copyright (C) 2010 Stefan Sayer
Development of this module was sponsored by TelTech Systems Inc
Overview
--------
The groups module implements a group event broadcast system. DSM calls can
join and leave groups, and post events to groups. Events are passed to all
members of the group that the event is posted to. Events can, just like the
`postEvent` function of DSM, contain either some variables, or all variables.
If a call ends, it is automatically removed from all groups it belongs to.
Actions:
groups.join(groupname) - Join a group
groups.leave(groupname) - Leave a group
groups.leaveAll() - Leave all groups
groups.postEvent(groupname, var1;var2) - post event to groupname with var1 and var2
groups.postEvent(groupname, var) - post event to groupname with all variables
Example:
import(mod_groups);
initial state START
enter {
groups.join("yeah");
repost();
};
transition "in the call" START --> IN_CALL;
state IN_CALL;
transition "got key" IN_CALL - key / {
set($event="key_press");
set($key=#key);
set($duration=#duration);
set($type=groups);
logVars(1);
groups.postEvent("yeah", event;key;duration;type);
} -> IN_CALL;
transition "got group event" IN_CALL - event(#type==groups) / {
logParams();
} -> IN_CALL;
transition "hangup" IN_CALL - hangup / {
-- groups.leave("yeah");
groups.leaveAll();
stop(false);
} -> END;
state END;
Loading…
Cancel
Save