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
20using namespace Atlas::Objects::Operation;
21using Atlas::Objects::Root;
22using Atlas::Objects::Entity::RootEntity;
23using Atlas::Objects::Entity::Anonymous;
24using Atlas::Objects::smart_dynamic_cast;
25
26namespace Eris
27{
28
29TypeService::TypeService(Connection &con) :
30 m_con(con),
31 m_inited(false)
32{
33 defineBuiltin("root", nullptr);
34}
35
36TypeService::~TypeService() = default;
37
38void 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
51TypeInfo* 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
61TypeInfo* 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
77TypeInfo* TypeService::getTypeForAtlas(const Root &obj)
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
88void 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
132void 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
143void 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
155void 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
175void 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
197TypeInfo* 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
213void TypeService::setTypeProviderId(std::string id) {
214 m_type_provider_id = std::move(id);
215}
216
217} // of namespace Eris
The representation of an Atlas type (i.e a class or operation definition). This class supports effice...
Definition: TypeInfo.h:33
Definition: Account.cpp:33
std::int64_t getNewSerialno()
operation serial number sequencing
Definition: Connection.cpp:390