swift
identifier.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "misc/identifier.h"
5 
6 #include <QCoreApplication>
7 #include <QHostInfo>
8 #include <QStringBuilder>
9 #include <QSysInfo>
10 
11 #include "misc/comparefunctions.h"
12 #include "misc/propertyindexref.h"
13 #include "misc/stringutils.h"
14 
16 
17 QString toDBusPath(const QString &s) { return swift::misc::utfToPercentEncoding(s, "/", '_'); }
19 
21 QString toDBusPathElement(const QString &s) { return swift::misc::utfToPercentEncoding(s, {}, '_'); }
22 
24 QString fromDBusPath(const QString &s) { return swift::misc::utfFromPercentEncoding(s.toLatin1(), '_'); }
25 
27 QString fromDBusPathElement(const QString &s) { return swift::misc::utfFromPercentEncoding(s.toLatin1(), '_'); }
28 
30 const QString &cachedEscapedApplicationName()
31 {
32  static const QString appName = toDBusPathElement(QCoreApplication::applicationName());
33  return appName;
34 }
35 
37 const QString &cachedLocalHostName()
38 {
39  static const QString hostName = QHostInfo::localHostName();
40  return hostName;
41 }
42 
43 enum
44 {
45  UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000")
46 };
47 
48 QByteArray cachedMachineUniqueId()
49 {
50  static const QByteArray machineUniqueId = QSysInfo::machineUniqueId();
51  return machineUniqueId;
52 }
53 
54 namespace swift::misc
55 {
56  CIdentifier::CIdentifier(const QString &name)
57  : m_name(name.trimmed()), m_machineIdBase64(cachedMachineUniqueId().toBase64(QByteArray::OmitTrailingEquals)),
58  m_machineName(cachedLocalHostName()), m_processName(cachedEscapedApplicationName()),
59  m_processId(QCoreApplication::applicationPid())
60  {}
61 
62  CIdentifier::CIdentifier(const QString &name, QObject *object) : CIdentifier(name)
63  {
64  if (object)
65  {
66  // append object name
67  this->linkWithQObjectName(object);
68  this->appendName(object->objectName());
69  }
70  }
71 
72  CIdentifier::CIdentifier(const QString &name, const QString &machineId, const QString &machineName,
73  const QString &processName, qint64 processId)
74  : m_name(name), m_machineIdBase64(machineId), m_machineName(machineName), m_processName(processName),
75  m_processId(processId)
76  {}
77 
79  {
80  static const CIdentifier id("");
81  return id;
82  }
83 
85  {
86  static const CIdentifier id("", "", "", "", 0);
87  return id;
88  }
89 
91  {
92  static const CIdentifier id(
93  "fake", QByteArrayLiteral("00000000-0000-0000-0000-000000000000").toBase64(QByteArray::OmitTrailingEquals),
94  "fake machine", "fake process", 0);
95  return id;
96  }
97 
98  QUuid CIdentifier::toUuid() const
99  {
100  static const QUuid ns = QUuid::createUuid();
101  QByteArray baseData;
102  baseData.append(getMachineId());
103  baseData.append(reinterpret_cast<const char *>(&m_processId), sizeof(m_processId));
104  baseData.append(getName().toUtf8());
105  return QUuid::createUuidV5(ns, baseData);
106  }
107 
108  QString CIdentifier::toUuidString() const { return toUuid().toString(); }
109 
110  void CIdentifier::appendName(const QString &name)
111  {
112  if (m_name.endsWith(name)) { return; }
113  if (name.isEmpty()) { return; }
114  const int index = m_name.lastIndexOf(':');
115  if (index >= 0) { m_name = m_name.left(index); }
116  m_name += QStringLiteral(":") + name;
117  }
118 
119  void CIdentifier::linkWithQObjectName(QObject *object)
120  {
121  if (!object) { return; }
122  QObject::connect(object, &QObject::objectNameChanged, object,
123  [=](const QString &name) { this->appendName(name); });
124  }
125 
126  QByteArray CIdentifier::getMachineId() const
127  {
128  return *QByteArray::fromBase64Encoding(m_machineIdBase64.toLocal8Bit());
129  }
130 
131  QString CIdentifier::toDBusObjectPath(const QString &root) const
132  {
133  QString path = root;
134  path += '/' % toDBusPathElement(m_machineName) % "__" % toDBusPathElement(m_machineIdBase64);
135  path += '/' % toDBusPathElement(m_processName) % "__" % QString::number(m_processId);
136 
137  const QString name = toDBusPath(m_name);
138  Q_ASSERT_X(!name.contains("//") && !name.startsWith('/') && !name.endsWith('/'), Q_FUNC_INFO, "Invalid name");
139  if (!name.isEmpty()) { path += '/' % name; }
140  return path;
141  }
142 
143  CIdentifier CIdentifier::fromDBusObjectPath(const QString &path, const QString &root)
144  {
145  const QString relative = path.startsWith(root) ? path.mid(root.length()) : path;
146  const QString machine = relative.section('/', 1, 1);
147  const QString process = relative.section('/', 2, 2);
148  const QString name = relative.section('/', 3, -1);
149 
150  CIdentifier result(fromDBusPath(name));
151  result.m_machineIdBase64 = fromDBusPathElement(machine.section("__", 1, 1));
152  result.m_machineName = fromDBusPathElement(machine.section("__", 0, 0));
153  result.m_processId = process.section("__", 1, 1).toInt();
154  result.m_processName = fromDBusPathElement(process.section("__", 0, 0));
155  return result;
156  }
157 
159  {
160  return !other.getMachineName().isEmpty() && other.getMachineName() == this->getMachineName();
161  }
162 
164  {
165  return !m_machineIdBase64.isEmpty() && m_machineIdBase64 == other.m_machineIdBase64;
166  }
167 
169  {
170  return this->hasSameMachineId(other) || this->hasSameMachineName(other);
171  }
172 
174  {
176  return cachedMachineUniqueId() == getMachineId();
177  }
178 
180  {
181  return QCoreApplication::applicationPid() == getProcessId() && isFromLocalMachine();
182  }
183 
185  {
186  return cachedEscapedApplicationName() == toDBusPathElement(getProcessName());
187  }
188 
189  bool CIdentifier::isAnonymous() const { return &anonymous() == this || anonymous() == *this; }
190 
191  bool CIdentifier::isNull() const { return &null() == this || null() == *this; }
192 
194  {
195  m_machineIdBase64 = cachedMachineUniqueId().toBase64(QByteArray::OmitTrailingEquals);
196  m_machineName = cachedLocalHostName();
197  }
198 
200  {
201  m_processName = QCoreApplication::applicationName();
202  m_processId = QCoreApplication::applicationPid();
203  }
204 
205  QString CIdentifier::convertToQString(bool i18n) const
206  {
207  Q_UNUSED(i18n);
208  const QString s = m_name % u' ' % m_machineIdBase64 % u' ' % m_machineName % u' ' %
209  QString::number(m_processId) % u' ' % m_processName;
210  return s;
211  }
212 
214  {
215  if (index.isMyself()) { return QVariant::fromValue(*this); }
216 
217  const ColumnIndex i = index.frontCasted<ColumnIndex>();
218 
219  switch (i)
220  {
221  case IndexName: return QVariant::fromValue(m_name);
222  case IndexMachineIdBase64: return QVariant::fromValue(m_machineIdBase64);
223  case IndexMachineName: return QVariant::fromValue(getMachineName());
224  case IndexMachineId: return QVariant::fromValue(getMachineId());
225  case IndexProcessId: return QVariant::fromValue(m_processId);
226  case IndexProcessName: return QVariant::fromValue(m_processName);
227  case IndexIsFromLocalMachine: return QVariant::fromValue(isFromLocalMachine());
228  case IndexIsFromSameProcess: return QVariant::fromValue(hasApplicationProcessId());
229  case IndexIsFromSameProcessName: return QVariant::fromValue(hasApplicationProcessName());
230  default: return CValueObject::propertyByIndex(index);
231  }
232  }
233 
235  {
236  if (index.isMyself()) { return Compare::compare(m_processId, compareValue.m_processId); }
237 
238  const ColumnIndex i = index.frontCasted<ColumnIndex>();
239 
240  switch (i)
241  {
242  case IndexName: return m_name.compare(compareValue.m_name, Qt::CaseInsensitive);
243  case IndexMachineIdBase64: return m_machineIdBase64.compare(compareValue.m_machineIdBase64);
244  case IndexMachineName: return m_machineName.compare(compareValue.m_machineName, Qt::CaseInsensitive);
245  case IndexMachineId: return m_machineName.compare(compareValue.m_machineName, Qt::CaseInsensitive);
246  case IndexProcessId: return Compare::compare(m_processId, compareValue.m_processId);
247  case IndexProcessName: return m_processName.compare(compareValue.m_processName, Qt::CaseInsensitive);
248  case IndexIsFromLocalMachine:
249  return Compare::compare(this->isFromLocalMachine(), compareValue.isFromLocalMachine());
250  case IndexIsFromSameProcess:
251  return Compare::compare(this->hasApplicationProcessId(), compareValue.hasApplicationProcessId());
252  case IndexIsFromSameProcessName:
253  return Compare::compare(this->hasApplicationProcessName(), compareValue.hasApplicationProcessName());
254  default: return CValueObject::comparePropertyByIndex(index, compareValue);
255  }
256  }
257 
258  void CIdentifier::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
259  {
260  CValueObject::setPropertyByIndex(index, variant);
261  }
262 
263 } // namespace swift::misc
Value object encapsulating information identifying a component of a modular distributed swift process...
Definition: identifier.h:29
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: identifier.cpp:258
bool hasApplicationProcessName() const
Check if originating from the same process name.
Definition: identifier.cpp:184
static const CIdentifier & anonymous()
Returns an anonymous identifier, which is a valid identifier without name.
Definition: identifier.cpp:78
bool hasSameMachineId(const CIdentifier &other) const
Check if other identifier is from the same machine id.
Definition: identifier.cpp:163
void appendName(const QString &name)
Set name or append name.
Definition: identifier.cpp:110
bool isNull() const
Null identifier (no name, ids etc)
Definition: identifier.cpp:191
ColumnIndex
Properties by index.
Definition: identifier.h:33
bool isAnonymous() const
Check if it is anonymous identifier.
Definition: identifier.cpp:189
qint64 getProcessId() const
Get process id.
Definition: identifier.h:115
QUuid toUuid() const
Produces a UUID generated from the identifier.
Definition: identifier.cpp:98
QByteArray getMachineId() const
Get machine id.
Definition: identifier.cpp:126
bool hasApplicationProcessId() const
Check if originating from the same process id.
Definition: identifier.cpp:179
const QString & getProcessName() const
Get process name.
Definition: identifier.h:118
const QString & getName() const
Name.
Definition: identifier.h:80
static CIdentifier fromDBusObjectPath(const QString &path, const QString &root={})
Reconstruct an identifier from a DBus object path.
Definition: identifier.cpp:143
static const CIdentifier & fake()
Returns a fake identifier.
Definition: identifier.cpp:90
const QString & getMachineName() const
Machine name.
Definition: identifier.h:103
bool hasSameMachineName(const CIdentifier &other) const
Check if the other identifier has the same machine name.
Definition: identifier.cpp:158
void updateToCurrentProcess()
Update to current process.
Definition: identifier.cpp:199
bool isFromLocalMachine() const
Check if originating from the same local machine.
Definition: identifier.cpp:173
void updateToCurrentMachine()
Update to current machine.
Definition: identifier.cpp:193
void linkWithQObjectName(QObject *object)
Reflect changes of QObject::
Definition: identifier.cpp:119
bool hasSameMachineNameOrId(const CIdentifier &other) const
Same machine or id?
Definition: identifier.cpp:168
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
Definition: identifier.cpp:213
static const CIdentifier & null()
Null (empty) identifier.
Definition: identifier.cpp:84
QString toUuidString() const
UUID string.
Definition: identifier.cpp:108
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: identifier.cpp:205
QString toDBusObjectPath(const QString &root={}) const
Produces a DBus object path from the identifier.
Definition: identifier.cpp:131
int comparePropertyByIndex(CPropertyIndexRef index, const CIdentifier &compareValue) const
Compare for index.
Definition: identifier.cpp:234
Non-owning reference to a CPropertyIndex with a subset of its features.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
Definition: mixinindex.h:187
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:160
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:167
Free functions in swift::misc.
SWIFT_MISC_EXPORT QByteArray utfToPercentEncoding(const QString &s, const QByteArray &allow={}, char percent='%')
Extended percent encoding supporting UTF-16.
SWIFT_MISC_EXPORT QString utfFromPercentEncoding(const QByteArray &ba, char percent='%')
Reverse utfFromPercentEncoding.
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67