jami-docs

Forked version of Jami documentation, see wrycode.com/jami-docs-demo
git clone git://git.wrycode.com/wrycode/jami-docs.git
Log | Files | Refs

APIs.md (9362B)


      1 # APIs
      2 
      3 ## OpenDHT
      4 
      5 The documentation related to the API of OpenDHT is [here](https://github.com/savoirfairelinux/opendht/wiki/API-Overview) and will not be detailed in the following part.
      6 
      7 ## Daemon
      8 
      9 ### The managers
     10 
     11 The API of the daemon is decomposed between 5 Managers + 1 Instance file:
     12 + 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.
     13 + The **ConfigurationManager** used to handle the configuration stuff: accounts settings, user preferences, ...
     14 + The **PresenceManager** is used to track the presence of contacts
     15 + The **VideoManager** used to manage video devices and renderers
     16 + 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.
     17 
     18 ### DBUS
     19 
     20 All the documentation and code for the dbus API is located in `ring-daemon/bin/dbus`.
     21 
     22 If you use linux, you can use `d-feet` when the daemon is running to manipulate the API (or with any another tool).
     23 
     24 The LRC project uses this API (and use libwrap on windows and mac os).
     25 
     26 ### JNI
     27 
     28 All the documentation and code for the JNI API is located in `ring-daemon/bin/jni`.
     29 
     30 #### Generation process
     31 
     32 -   `cd ring-project/`
     33 -   Check `./daemon/src/dring`
     34 -   Create a new file .i in `./daemon/bin/jni/` from an existing file in the same folder
     35 -   Update with your new interfaces from documentation
     36 -   Check that callback block is at the beginning AND at the end of file
     37 -   `cd daemon/bin/jni`
     38 -   Edit ./daemon/bin/jni/jni\_interface.i and add yours with the other .i files that are in the same folder
     39 -   `export PACKAGEDIR=\*\*\*\*/ring-project/client-android/ring-android/libringclient/src/main/java/cx/ring/daemon.`
     40 	ie: `export PACKAGEDIR=/home/pduchemin/Documents/ring-project/client-android/ring-android/libringclient/src/main/java/cx/ring/daemon`
     41 -   Run
     42 	-   `./make-swig.sh`
     43 -   or, if you start from scratch
     44 	-   `./make-ring.py --init --distribution=Android`
     45 	-   `./make-ring.py --install --distribution=Android`
     46 
     47 ### node js
     48 
     49 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.
     50 
     51 ### REST
     52 
     53 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.
     54 
     55 ### Python wrapper
     56 
     57 A Python wrapper is available in `ring-daemon/tools/dringctrl`. This wrapper uses d-bus.
     58 
     59 This is, for example a quick and dirty IRC bot to interact with Ring made with this API:
     60 
     61 `config.json`:
     62 ```json
     63 {
     64 	"users": {
     65 	},
     66 	"debug": true,
     67 	"host": "irc.freenode.net",
     68 	"follow_all": {
     69 	},
     70 	"port": 6697,
     71 	"nick": "NICKNAME",
     72 	"ssl": true,
     73 	"channel": "#REPLACE"
     74 }
     75 ```
     76 
     77 `irc,py`:
     78 ```python
     79 #!/usr/bin/env python3
     80 # -*- coding: utf-8 -*-
     81 from controler import DRingCtrl
     82 from threading import Thread
     83 import irc3
     84 from irc3 import utils
     85 import json
     86 import sys
     87 
     88 
     89 @irc3.plugin
     90 class RingBridge:
     91 	'''This plug-in react to event from IRC and send messages to IRC'''
     92 
     93 	requires = [
     94 		'irc3.plugins.core',
     95 		'irc3.plugins.userlist',
     96 		'irc3.plugins.command',
     97 		'irc3.plugins.human',
     98 	]
     99 
    100 	def __init__(self, bot):
    101 		self.bot = bot
    102 		self.log = self.bot.log
    103 		self.channels = utils.as_list(self.bot.config.get('autojoins', []))
    104 		self.config = None
    105 
    106 	@irc3.event(irc3.rfc.PRIVMSG)
    107 	def on_privmsg(self, mask=None, target=None, data=None, **kwargs):
    108 		'''React to messages from IRC'''
    109 		message = data.split(' ')
    110 		follow_all = self.bot.config_bridge['follow_all']
    111 		if message[0] == '!tell':
    112 			msg_to_send = ('%s: ' % mask.nick) + ''.join(
    113 				'%s ' % m for m in message[2:])[:-1]
    114 			call_id = None
    115 			users = self.bot.config_bridge['users']
    116 			# Get ring_id from nick
    117 			for ring_id in users.keys():
    118 				if users[ring_id].lower() == message[1].lower():
    119 					call_id = ring_id
    120 			if call_id:
    121 				# if this nick want to receive all messages, we don't need
    122 				# to send the message here
    123 				if call_id not in follow_all.keys() \
    124 					or not follow_all[call_id] \
    125 						or target == self.bot.config_bridge['channel']:
    126 					print('Send: %s to %s' % (msg_to_send, call_id))
    127 					self.bot.controler.sendTextMessage(call_id,
    128 													   msg_to_send)
    129 			else:
    130 				self.bot.privmsg(self.bot.config_bridge['channel'],
    131 								 'I don\'t know how to contact this person')
    132 		# Send message to everyone who wants to receive message from #channel
    133 		if target.lower() != self.bot.config_bridge['channel'].lower():
    134 			return
    135 		msg_to_send = ('%s: %s' % (mask.nick, data))
    136 		for user in follow_all.keys():
    137 			if follow_all[user]:
    138 				self.bot.controler.sendTextMessage(user,
    139 												   msg_to_send)
    140 
    141 	@irc3.extend
    142 	def send_message_to_irc(self, ring_id, message):
    143 		'''send message to #channel'''
    144 		self.bot.privmsg(self.bot.config_bridge['channel'],
    145 						 '%s: %s' %
    146 						 (self.bot.config_bridge['users'][ring_id], message),
    147 						 True)
    148 
    149 
    150 def threadClient(controler, config_bridge):
    151 	config = dict(
    152 		nick=config_bridge['nick'],
    153 		autojoins=[config_bridge['channel']],
    154 		host=config_bridge['host'],
    155 		port=config_bridge['port'],
    156 		ssl=config_bridge['ssl'],
    157 		debug=config_bridge['debug'],
    158 		includes=[__name__]
    159 	)
    160 	bot = irc3.IrcBot.from_config(config)
    161 	# link irc and ring controlers
    162 	bot.controler = controler
    163 	bot.config_bridge = config_bridge
    164 	controler.irc_client = bot
    165 
    166 	bot.run(forever=True)
    167 
    168 
    169 class IRCRingController(DRingCtrl):
    170 	def __init__(self, config_bridge):
    171 		super().__init__('ircbridge', True)
    172 		self.irc_client = None
    173 		self.config_bridge = config_bridge
    174 		self.accountId = self.configurationmanager.getAccountList()[0]
    175 
    176 	def updateConfig(self):
    177 		'''Change actual config'''
    178 		with open('config.json', 'w') as config_file:
    179 			json.dump(self.config_bridge, config_file, indent=4)
    180 		if self.irc_client:
    181 			self.irc_client.config_bridge = self.config_bridge
    182 
    183 	def onIncomingAccountMessage(self, accountId, fromAccount, payloads):
    184 		'''React to message from Ring'''
    185 		# Avoid to react to message from self.
    186 		if fromAccount == self.accountId:
    187 			return
    188 		# If we have multiple accounts, avoid to react from another account
    189 		if accountId != self.accountId:
    190 			return
    191 		message = '%s: %s' % (fromAccount, payloads['text/plain'])
    192 		print('Receive new message from %s' % message)
    193 		# React to !commands
    194 		if payloads['text/plain'] == '!follow':
    195 			self.config_bridge['follow_all'][fromAccount] = True
    196 			self.updateConfig()
    197 		elif payloads['text/plain'] == '!unfollow':
    198 			self.config_bridge['follow_all'][fromAccount] = False
    199 			self.updateConfig()
    200 		elif payloads['text/plain'].split(' ')[0] == '!add':
    201 			irc_nick = payloads['text/plain'].split(' ')[1]
    202 			self.config_bridge['users'][fromAccount] = irc_nick
    203 			self.updateConfig()
    204 		elif payloads['text/plain'] == '!rm':
    205 			del self.config_bridge['users'][fromAccount]
    206 			del self.config_bridge['follow_all'][fromAccount]
    207 			self.updateConfig()
    208 		# Send message to IRC
    209 		else:
    210 			try:
    211 				if self.irc_client:
    212 					self.irc_client.send_message_to_irc(fromAccount,
    213 														payloads['text/plain'])
    214 			except:
    215 				print('Can\'t read message received: %s' % payloads)
    216 
    217 	def sendTextMessage(self, accountId, message):
    218 		'''Send a message to a ring id'''
    219 		if accountId == self.accountId:
    220 			return
    221 		self.configurationmanager.sendTextMessage(self.accountId,
    222 												  accountId,
    223 												  {
    224 													'text/plain':
    225 													str(message)
    226 												  })
    227 
    228 
    229 if __name__ == '__main__':
    230 	config_bridge = None
    231 	with open('config.json') as config_file:
    232 		config_bridge = json.loads(config_file.read())
    233 	if not config_bridge:
    234 		print('Can\'t find config.json')
    235 		sys.exit(-1)
    236 	irc_controler = IRCRingController(config_bridge)
    237 	thread = Thread(target=threadClient, args=(irc_controler, config_bridge,))
    238 	thread.start()
    239 	irc_controler.run()
    240 ```
    241 
    242 ## LRC
    243 
    244 ### Doxygen doc
    245 
    246 The Doxygen documentation is available [here](https://jenkins.ring.cx/view/libringclient/job/libringclient-doxygen/doxygen/annotated.html) and currently generated by Jenkins each week.
    247 
    248 ### Database schema
    249 
    250 ```sql
    251 CREATE TABLE profiles (id INTEGER PRIMARY KEY,  \
    252 					   uri TEXT NOT NULL,       \
    253 					   alias TEXT,              \
    254 					   photo TEXT,              \
    255 					   type TEXT,               \
    256 					   status TEXT);
    257 
    258 CREATE TABLE conversations (id INTEGER,\
    259 							participant_id INTEGER, \
    260 							FOREIGN KEY(participant_id) REFERENCES profiles(id));
    261 
    262 CREATE TABLE interactions (id INTEGER PRIMARY KEY,\
    263 						   account_id INTEGER, \
    264 						   author_id INTEGER, \
    265 						   conversation_id INTEGER, \
    266 						   timestamp INTEGER, \
    267 						   body TEXT,     \
    268 						   type TEXT,  \
    269 						   status TEXT, \
    270 						   daemon_id TEXT, \
    271 						   FOREIGN KEY(account_id) REFERENCES profiles(id), \
    272 						   FOREIGN KEY(author_id) REFERENCES profiles(id), \
    273 						   FOREIGN KEY(conversation_id) REFERENCES conversations(id));
    274 
    275 CREATE TABLE profiles_accounts (profile_id INTEGER NOT NULL,                    \
    276 								account_id TEXT NOT NULL,                       \
    277 								is_account TEXT,                                \
    278 								FOREIGN KEY(profile_id) REFERENCES profiles(id));
    279 ```