eris  1.4.0
A WorldForge client library.
TypeService.cpp
1 #include <utility>
2 
3 #ifdef HAVE_CONFIG_H
4  #include "config.h"
5 #endif
6 
7 #include "TypeService.h"
8 
9 #include "TypeInfo.h"
10 #include "Log.h"
11 #include "Connection.h"
12 #include "Exceptions.h"
13 #include "Response.h"
14 
15 #include <Atlas/Objects/Operation.h>
16 #include <Atlas/Objects/RootEntity.h>
17 #include <Atlas/Objects/RootOperation.h>
18 #include <Atlas/Objects/Anonymous.h>
19 
20 using namespace Atlas::Objects::Operation;
21 using Atlas::Objects::Root;
22 using Atlas::Objects::Entity::RootEntity;
23 using Atlas::Objects::Entity::Anonymous;
24 using Atlas::Objects::smart_dynamic_cast;
25 
26 namespace Eris
27 {
28 
29 TypeService::TypeService(Connection &con) :
30  m_con(con),
31  m_inited(false)
32 {
33  defineBuiltin("root", nullptr);
34 }
35 
36 TypeService::~TypeService() = default;
37 
38 void TypeService::init()
39 {
40  assert(!m_inited);
41  m_inited = true;
42 
43  // every type already in the map delayed it's sendInfoRequest because we weren't inited;
44  // go through and fix them now. This allows static construction (or early construction) of
45  // things like ClassDispatchers in a moderately controlled fashion.
46  for (auto& type : m_types) {
47  if (!type.second->isBound()) sendRequest(type.second->getName());
48  }
49 }
50 
51 TypeInfo* TypeService::findTypeByName(const std::string &id)
52 {
53  auto T = m_types.find(id);
54  if (T != m_types.end()) {
55  return T->second.get();
56  }
57 
58  return nullptr;
59 }
60 
61 TypeInfo* TypeService::getTypeByName(const std::string &id)
62 {
63  auto T = m_types.find(id);
64  if (T != m_types.end()) {
65  return T->second.get();
66  }
67 
68 // not found, do some work
70  auto node = new TypeInfo(id, *this);
71  m_types[id] = std::unique_ptr<TypeInfo>(node);
72 
73  sendRequest(id);
74  return node;
75 }
76 
78 {
79  /* special case code to handle the root object which has no parents. */
80  if (obj->getParent().empty()) {
81  // check that obj->isA(ROOT_NO);
82  return getTypeByName("root");
83  }
84 
85  return getTypeByName(obj->getParent());
86 }
87 
88 void TypeService::handleOperation(const RootOperation& op)
89 {
90  if (op->instanceOf(ERROR_NO)) {
91  auto message = getErrorMessage(op);
92  notice() << "Error from server when requesting type: " << message;
93  auto& args = op->getArgs();
94  for (const auto& arg : args) {
95  Get request = smart_dynamic_cast<Get>(arg);
96  if (request) {
97  recvError(request);
98  }
99  }
100  } else if (op->instanceOf(CHANGE_NO)) {
101  const std::vector<Root>& args(op->getArgs());
102  for (const auto& arg : args) {
103  if (!arg->isDefaultObjtype()) {
104  auto& objType = arg->getObjtype();
105  if ((objType == "meta") ||
106  (objType == "class") ||
107  (objType == "op_definition") ||
108  (objType == "archetype")) {
109  recvTypeUpdate(arg);
110  }
111  }
112  }
113  } else if (op->instanceOf(INFO_NO)) {
114  const std::vector<Root>& args(op->getArgs());
115  for (const auto& arg : args) {
116  if (!arg->isDefaultObjtype()) {
117  auto& objType = arg->getObjtype();
118 
119  if ((objType == "meta") ||
120  (objType == "class") ||
121  (objType == "op_definition") ||
122  (objType == "archetype")) {
123  recvTypeInfo(arg);
124  }
125  }
126  }
127  } else {
128  error() << "type service got op that wasn't info or error";
129  }
130 }
131 
132 void TypeService::recvTypeInfo(const Root &atype)
133 {
134  auto T = m_types.find(atype->getId());
135  if (T == m_types.end()) {
136  error() << "received type object with unknown ID " << atype->getId();
137  return;
138  }
139 
140  T->second->processTypeData(atype);
141 }
142 
143 void TypeService::recvTypeUpdate(const Root &atype)
144 {
145  //A type has been updated on the server. Check if we have it. If so we need to refresh.
146  //If we don't have it we should do nothing.
147  auto T = m_types.find(atype->getId());
148  if (T == m_types.end()) {
149  return;
150  }
151 
152  sendRequest(atype->getId());
153 }
154 
155 void TypeService::sendRequest(const std::string &id)
156 {
157  // stop premature requests (before the connection is available); when TypeInfo::init
158  // is called, the requests will be re-issued manually
159  if (!m_inited) return;
160 
161  Anonymous what;
162  what->setId(id);
163 
164  Get get;
165  get->setArgs1(what);
166  get->setSerialno(getNewSerialno());
167  if (!m_type_provider_id.empty()) {
168  get->setFrom(m_type_provider_id);
169  }
170 
171  m_con.getResponder().await(get->getSerialno(), this, &TypeService::handleOperation);
172  m_con.send(get);
173 }
174 
175 void TypeService::recvError(const Get& get)
176 {
177  const std::vector<Root>& args = get->getArgs();
178 
179  for (const auto& request: args) {
180  if (!request->isDefaultId()) {
181  auto T = m_types.find(request->getId());
182  if (T == m_types.end()) {
183  // This type isn't known, which is strange
184  error() << "got ERROR(GET()) with request for unknown type: " + request->getId();
185  continue;
186  }
187 
188  warning() << "type " << request->getId() << " undefined on server";
189  BadType.emit(T->second.get());
190 
191  m_types.erase(T);
192 
193  }
194  }
195 }
196 
197 TypeInfo* TypeService::defineBuiltin(const std::string& name, TypeInfo* parent)
198 {
199  assert(m_types.count(name) == 0);
200 
201  auto type = new TypeInfo(name, *this);
202  m_types[name] = std::unique_ptr<TypeInfo>(type);
203 
204  if (parent) {
205  type->setParent(parent);
206  }
207  type->validateBind();
208 
209  assert(type->isBound());
210  return type;
211 }
212 
213 void TypeService::setTypeProviderId(std::string id) {
214  m_type_provider_id = std::move(id);
215 }
216 
217 } // of namespace Eris
std::unordered_map< std::string, std::unique_ptr< TypeInfo > > m_types
Definition: TypeService.h:77
The representation of an Atlas type (i.e a class or operation definition). This class supports effice...
Definition: TypeInfo.h:32
sigc::signal< void, TypeInfo * > BadType
Definition: TypeService.h:47
Definition: Account.cpp:33
TypeInfo * findTypeByName(const std::string &tynm)
Definition: TypeService.cpp:51
void setTypeProviderId(std::string id)
Set another provider of type data than the connection.
virtual void send(const Atlas::Objects::Root &obj)
Transmit an Atlas::Objects instance to the server.
Definition: Connection.cpp:160
TypeInfo * getTypeForAtlas(const Atlas::Objects::Root &obj)
Definition: TypeService.cpp:77
std::int64_t getNewSerialno()
operation serial number sequencing
Definition: Connection.cpp:390
std::string m_type_provider_id
Definition: TypeService.h:85
void sendRequest(const std::string &id)
TypeInfo * getTypeByName(const std::string &tynm)
Definition: TypeService.cpp:61