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 ```