Gestão de contatos
Esta seção apresentará como localizar e adicionar um contato do DHT ao cliente. O uso de um servidor de nomes não será explicado aqui. Se quiser obter mais detalhes sobre isso, leia Nome Protocolo do servidor.
Presença na rede
Anunciar a presença no DHT
A presença é muito simples de ser anunciada no DHT. Na verdade, é apenas um valor que contém o hash do dispositivo (consulte a seção anterior, Gestão de contas) no hash correspondente à impressão digital da chave. Portanto, se tivermos a conta bf5f1e21d3eb2c1246946aa49d5dcf3e5b9cb1b9
com o dispositivo 62fbdff0ce86f368c7d3c2682539e5ba9e06404f
, o seguinte valor definido será enviado pelo DHT:
/**
* Device announcement stored on DHT.
*/
struct DeviceAnnouncement : public dht::SignedValue<DeviceAnnouncement>
{
private:
using BaseClass = dht::SignedValue<DeviceAnnouncement>;
public:
static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA;
dht::InfoHash dev;
std::shared_ptr<dht::crypto::PublicKey> pk;
MSGPACK_DEFINE_MAP(dev, pk)
};
(Esse valor pode ser colocado com dht_.put(h, VALUE, dht::DoneCallback{}, {}, true);
, como uma colocação permanente). Se o dispositivo for anunciado, o dispositivo está presente. Por enquanto, não há como excluir ou editar um valor no DHT (isso ocorrerá quando o OpenDHT for compatível com ECC). Portanto, a presença sempre tem um atraso por enquanto (atraso médio: expire-time/2, portanto, 2min30 por enquanto).
Saber se um contato está presente
Agora que estamos presentes na rede, é altura de saber se alguém está presente na DHT. Com a secção anterior, é fácil fazer o processo inverso. Para sabermos se alguém está presente na DHT (ex: bf5f1e21d3eb2c1246946aa49d5dcf3e5b9cb1b9
), temos que obter o valor em bf5f1e21d3eb2c1246946aa49d5dcf3e5b9cb1b9
e recuperar o DeviceAnnouncement
neste hash. O código relacionado no daemon está em jamiaccount.cpp
:
auto shared = std::static_pointer_cast<RingAccount>(shared_from_this());
auto treatedDevices = std::make_shared<std::set<dht::InfoHash>>();
dht_.get<dht::crypto::RevocationList>(to, [to](dht::crypto::RevocationList&& crl){
tls::CertificateStore::instance().pinRevocationList(to.toString(), std::move(crl));
return true;
});
dht_.get<DeviceAnnouncement>(to, [shared,to,treatedDevices,op](DeviceAnnouncement&& dev) {
if (dev.from != to)
return true;
if (treatedDevices->emplace(dev.dev).second)
op(shared, dev.dev);
return true;
}, [=](bool /*ok*/){
{
std::lock_guard<std::recursive_mutex> lock(shared->buddyInfoMtx);
auto buddy_info_it = shared->trackedBuddies_.find(to);
if (buddy_info_it != shared->trackedBuddies_.end()) {
if (not treatedDevices->empty()) {
for (auto& device_id : *treatedDevices)
shared->onTrackedBuddyOnline(buddy_info_it, device_id);
} else
shared->onTrackedBuddyOffline(buddy_info_it);
}
}
RING_DBG("[Account %s] found %lu devices for %s",
getAccountID().c_str(), treatedDevices->size(), to.to_c_str());
if (end) end(shared, not treatedDevices->empty());
});
E é tudo.
Perspetiva do cliente
<method name="subscribeBuddy" tp:name-for-bindings="subscribeBuddy">
<tp:docstring>
Ask be be notified when 'uri' presence change
</tp:docstring>
<tp:added version="1.3.0"/>
<arg type="s" name="accountID" direction="in">
<tp:docstring>
An account from which get request presence informations
</tp:docstring>
</arg>
<arg type="s" name="uri" direction="in">
<tp:docstring>
A SIP uri to watch
</tp:docstring>
</arg>
<arg type="b" name="flag" direction="in">
<tp:docstring>
</tp:docstring>
</arg>
</method>
<signal name="newBuddyNotification" tp:name-for-bindings="newBuddyNotification">
<tp:added version="1.3.0"/>
<tp:docstring>
Notify when a registered presence uri presence informations changes
</tp:docstring>
<arg type="s" name="accountID">
<tp:docstring>
The associated account
</tp:docstring>
</arg>
<arg type="s" name="buddyUri">
<tp:docstring>
The registered URI
</tp:docstring>
</arg>
<arg type="i" name="status">
<tp:docstring>
Is the URI present or not
</tp:docstring>
</arg>
<arg type="s" name="lineStatus">
<tp:docstring>
A string containing informations from the user (human readable)
</tp:docstring>
</arg>
</signal>
<method name="publish" tp:name-for-bindings="publish">
<tp:added version="1.3.0"/>
<arg type="s" name="accountID" direction="in">
<tp:docstring>
The account from which the presence will be emitted
</tp:docstring>
</arg>
<arg type="b" name="status" direction="in">
<tp:docstring>
Is this account present or not
</tp:docstring>
</arg>
<arg type="s" name="note" direction="in">
<tp:docstring>
A message transmitted by the server to other users
</tp:docstring>
</arg>
</method>
São as principais APIs para clientes. O subscribeBuddy
irá escutar no DHT para detetar mudanças de presença e o newBuddyNotification
será enviado sempre que um novo estado for detetado:
O estado enviado ao cliente é agora 0=offline (nenhum dispositivo encontrado na DHT), 1=dht_presence (pelo menos um dispositivo é encontrado na DHT), 2=connected (com um canal TCP + SIP, portanto pronto para trocar dados).
lineStatus
conterá qualquer estado personalizado enviado pelo par (por exemplo, Hora do almoço!)
publish
é utilizado para publicar uma nota personalizada (status
é ignorado para as contas Jami, a nota conterá o estado personalizado).
O RFC3863 é utilizado para enviar o estado através da ligação SIP.
Pedido pendente
Enviar um pedido
PARA FAZER elaborar pedido
Finalmente, uma vez que o pedido de confiança é elaborado, podemos empurrar o pedido para o seguinte hash: InfoHash("inbox:" + dispositivoId)
O seguinte código é usado no daemon:
dht_.putEncrypted(dht::InfoHash::get("inbox:"+dev.toString()), dev, dht::TrustRequest(DHT_TYPE_NS, payload));
Recebimento de um pedido
PARA FAZER
(Aceptar/bloquear/descarar)
API daemon
Todos os métodos para acompanhar a presença de um amigo estão localizados no PresenceManager
tais como:
<signal name="newBuddyNotification" tp:name-for-bindings="newBuddyNotification">
<tp:added version="1.3.0"/>
<tp:docstring>
Notify when a registered presence uri presence informations changes
</tp:docstring>
<arg type="s" name="accountID">
<tp:docstring>
The associated account
</tp:docstring>
</arg>
<arg type="s" name="buddyUri">
<tp:docstring>
The registered URI
</tp:docstring>
</arg>
<arg type="b" name="status">
<tp:docstring>
Is the URI present or not
</tp:docstring>
</arg>
<arg type="s" name="lineStatus">
<tp:docstring>
A string containing informations from the user (human readable)
</tp:docstring>
</arg>
</signal>
Todos os métodos e sinais utilizados para gerir pedidos de confiança e contatos estão no ConfigurationManager
, tais como:
<method name="getTrustRequests" tp:name-for-bindings="getTrustRequests">
<tp:added version="2.2.0"/>
<arg type="s" name="accountID" direction="in">
</arg>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
<arg type="aa{ss}" name="requests" direction="out" >
<tp:docstring>
A list of contact request details. Details:
- from: account ID of sender
- received: UNIX timestamp of reception date
- payload: attached payload
</tp:docstring>
</arg>
</method>
<method name="acceptTrustRequest" tp:name-for-bindings="acceptTrustRequest">
<tp:added version="2.2.0"/>
<arg type="s" name="accountID" direction="in">
</arg>
<arg type="s" name="from" direction="in">
</arg>
<arg type="b" name="success" direction="out" tp:type="Boolean">
<tp:docstring>
True if the operation succeeded.
</tp:docstring>
</arg>
</method>
<method name="discardTrustRequest" tp:name-for-bindings="discardTrustRequest">
<tp:added version="2.2.0"/>
<arg type="s" name="accountID" direction="in">
</arg>
<arg type="s" name="from" direction="in">
</arg>
<arg type="b" name="success" direction="out" tp:type="Boolean">
<tp:docstring>
True if the operation succeeded.
</tp:docstring>
</arg>
</method>
<signal name="incomingTrustRequest" tp:name-for-bindings="incomingTrustRequest">
<tp:added version="2.2.0"/>
<tp:docstring>
Notify clients that a new contact request has been received.
</tp:docstring>
<arg type="s" name="accountID">
</arg>
<arg type="s" name="from">
</arg>
<arg type="ay" name="payload">
</arg>
<arg type="t" name="receiveTime">
</arg>
</signal>
<method name="sendTrustRequest" tp:name-for-bindings="sendTrustRequest">
<tp:added version="2.2.0"/>
<arg type="s" name="accountID" direction="in">
</arg>
<arg type="s" name="to" direction="in">
</arg>
<arg type="ay" name="payload" direction="in">
</arg>
</method>
<method name="addContact" tp:name-for-bindings="addContact">
<tp:added version="3.0.0"/>
<arg type="s" name="accountID" direction="in">
</arg>
<arg type="s" name="uri" direction="in">
</arg>
</method>
<method name="removeContact" tp:name-for-bindings="removeContact">
<tp:added version="3.0.0"/>
<arg type="s" name="accountID" direction="in">
</arg>
<arg type="s" name="uri" direction="in">
</arg>
<arg type="b" name="ban" direction="in" tp:type="Boolean">
<tp:docstring>
True if the the contact should be banned.
If false, the contact is removed from the contact list (banned or not).
</tp:docstring>
</arg>
</method>
Se você quiser alguns exemplos, esses métodos são usados em contactmodel.cpp
no LRC.