11 KiB
OpenDHT
The documentation related to the API of OpenDHT is here and will not be detailed in the following part.
Daemon
The managers
The API of the daemon is decomposed between 5 Managers + 1 Instance file:
- The CallManager interface is used to manage call and conference related actions. Since Ring-daemon supports multiple incoming/outgoing calls, any actions involving a specific call must address the method by the means of a unique callID. Ring-daemon will generate a unique callID for outgoing and incoming calls.
- The ConfigurationManager used to handle the configuration stuff: accounts settings, user preferences, ...
- The PresenceManager is used to track the presence of contacts
- The VideoManager used to manage video devices and renderers
- The Instance is used to count the number of clients actually registered to the core. When initializing your client, you need to register it against the core by using this interface.
DBUS
All the documentation and code for the dbus API is located in ring-daemon/bin/dbus
.
If you use linux, you can use d-feet
when the daemon is running to manipulate the API (or with any another tool).
The LRC project uses this API (and use libwrap on windows and mac os).
JNI
All the documentation and code for the JNI API is located in ring-daemon/bin/jni
.
Generation process
cd ring-project/
- Check
./daemon/src/dring
- Create a new file .i in
./daemon/bin/jni/
from an existing file in the same folder - Update with your new interfaces from documentation
- Check that callback block is at the beginning AND at the end of file
cd daemon/bin/jni
- Edit ./daemon/bin/jni/jni_interface.i and add yours with the other .i files that are in the same folder
export PACKAGEDIR=\*\*\*\*/ring-project/client-android/ring-android/libringclient/src/main/java/cx/ring/daemon.
ie:export PACKAGEDIR=/home/pduchemin/Documents/ring-project/client-android/ring-android/libringclient/src/main/java/cx/ring/daemon
- Run
./make-swig.sh
- or, if you start from scratch
./make-ring.py --init --distribution=Android
./make-ring.py --install --distribution=Android
node js
All the documentation and code for the Node JS API is located in ring-daemon/bin/nodejs
. This API is not used in any known project and maybe is not up-to-date.
REST
All the documentation and code for the REST API is located in ring-daemon/bin/restcpp
. This API is not used in any known project and maybe is not up-to-date.
Python wrapper
A Python wrapper is available in ring-daemon/tools/dringctrl
. This wrapper uses d-bus.
This is, for example a quick and dirty IRC bot to interact with Ring made with this API:
config.json
:
{
"users": {
},
"debug": true,
"host": "irc.freenode.net",
"follow_all": {
},
"port": 6697,
"nick": "NICKNAME",
"ssl": true,
"channel": "#REPLACE"
}
irc,py
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from controler import DRingCtrl
from threading import Thread
import irc3
from irc3 import utils
import json
import sys
@irc3.plugin
class RingBridge:
'''This plug-in react to event from IRC and send messages to IRC'''
requires = [
'irc3.plugins.core',
'irc3.plugins.userlist',
'irc3.plugins.command',
'irc3.plugins.human',
]
def __init__(self, bot):
self.bot = bot
self.log = self.bot.log
self.channels = utils.as_list(self.bot.config.get('autojoins', []))
self.config = None
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg(self, mask=None, target=None, data=None, **kwargs):
'''React to messages from IRC'''
message = data.split(' ')
follow_all = self.bot.config_bridge['follow_all']
if message[0] == '!tell':
msg_to_send = ('%s: ' % mask.nick) + ''.join(
'%s ' % m for m in message[2:])[:-1]
call_id = None
users = self.bot.config_bridge['users']
# Get ring_id from nick
for ring_id in users.keys():
if users[ring_id].lower() == message[1].lower():
call_id = ring_id
if call_id:
# if this nick want to receive all messages, we don't need
# to send the message here
if call_id not in follow_all.keys() \
or not follow_all[call_id] \
or target == self.bot.config_bridge['channel']:
print('Send: %s to %s' % (msg_to_send, call_id))
self.bot.controler.sendTextMessage(call_id,
msg_to_send)
else:
self.bot.privmsg(self.bot.config_bridge['channel'],
'I don\'t know how to contact this person')
# Send message to everyone who wants to receive message from #channel
if target.lower() != self.bot.config_bridge['channel'].lower():
return
msg_to_send = ('%s: %s' % (mask.nick, data))
for user in follow_all.keys():
if follow_all[user]:
self.bot.controler.sendTextMessage(user,
msg_to_send)
@irc3.extend
def send_message_to_irc(self, ring_id, message):
'''send message to #channel'''
self.bot.privmsg(self.bot.config_bridge['channel'],
'%s: %s' %
(self.bot.config_bridge['users'][ring_id], message),
True)
def threadClient(controler, config_bridge):
config = dict(
nick=config_bridge['nick'],
autojoins=[config_bridge['channel']],
host=config_bridge['host'],
port=config_bridge['port'],
ssl=config_bridge['ssl'],
debug=config_bridge['debug'],
includes=[__name__]
)
bot = irc3.IrcBot.from_config(config)
# link irc and ring controlers
bot.controler = controler
bot.config_bridge = config_bridge
controler.irc_client = bot
bot.run(forever=True)
class IRCRingController(DRingCtrl):
def __init__(self, config_bridge):
super().__init__('ircbridge', True)
self.irc_client = None
self.config_bridge = config_bridge
self.accountId = self.configurationmanager.getAccountList()[0]
def updateConfig(self):
'''Change actual config'''
with open('config.json', 'w') as config_file:
json.dump(self.config_bridge, config_file, indent=4)
if self.irc_client:
self.irc_client.config_bridge = self.config_bridge
def onIncomingAccountMessage(self, accountId, fromAccount, payloads):
'''React to message from Ring'''
# Avoid to react to message from self.
if fromAccount == self.accountId:
return
# If we have multiple accounts, avoid to react from another account
if accountId != self.accountId:
return
message = '%s: %s' % (fromAccount, payloads['text/plain'])
print('Receive new message from %s' % message)
# React to !commands
if payloads['text/plain'] == '!follow':
self.config_bridge['follow_all'][fromAccount] = True
self.updateConfig()
elif payloads['text/plain'] == '!unfollow':
self.config_bridge['follow_all'][fromAccount] = False
self.updateConfig()
elif payloads['text/plain'].split(' ')[0] == '!add':
irc_nick = payloads['text/plain'].split(' ')[1]
self.config_bridge['users'][fromAccount] = irc_nick
self.updateConfig()
elif payloads['text/plain'] == '!rm':
del self.config_bridge['users'][fromAccount]
del self.config_bridge['follow_all'][fromAccount]
self.updateConfig()
# Send message to IRC
else:
try:
if self.irc_client:
self.irc_client.send_message_to_irc(fromAccount,
payloads['text/plain'])
except:
print('Can\'t read message received: %s' % payloads)
def sendTextMessage(self, accountId, message):
'''Send a message to a ring id'''
if accountId == self.accountId:
return
self.configurationmanager.sendTextMessage(self.accountId,
accountId,
{
'text/plain':
str(message)
})
if __name__ == '__main__':
config_bridge = None
with open('config.json') as config_file:
config_bridge = json.loads(config_file.read())
if not config_bridge:
print('Can\'t find config.json')
sys.exit(-1)
irc_controler = IRCRingController(config_bridge)
thread = Thread(target=threadClient, args=(irc_controler, config_bridge,))
thread.start()
irc_controler.run()
LRC
Doxygen doc
The Doxygen documentation is available here and currently generated by Jenkins each week.
Database schema
CREATE TABLE profiles (id INTEGER PRIMARY KEY, \
uri TEXT NOT NULL, \
alias TEXT, \
photo TEXT, \
type TEXT, \
status TEXT);
CREATE TABLE conversations (id INTEGER,\
participant_id INTEGER, \
FOREIGN KEY(participant_id) REFERENCES profiles(id));
CREATE TABLE interactions (id INTEGER PRIMARY KEY,\
account_id INTEGER, \
author_id INTEGER, \
conversation_id INTEGER, \
timestamp INTEGER, \
body TEXT, \
type TEXT, \
status TEXT, \
daemon_id TEXT, \
FOREIGN KEY(account_id) REFERENCES profiles(id), \
FOREIGN KEY(author_id) REFERENCES profiles(id), \
FOREIGN KEY(conversation_id) REFERENCES conversations(id));
CREATE TABLE profiles_accounts (profile_id INTEGER NOT NULL, \
account_id TEXT NOT NULL, \
is_account TEXT, \
FOREIGN KEY(profile_id) REFERENCES profiles(id));