libkazv
sdk.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of libkazv.
3  * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
4  * SPDX-License-Identifier: AGPL-3.0-or-later
5  */
6 
7 #pragma once
8 #include <libkazv-config.hpp>
9 #include <lager/store.hpp>
10 
11 #include <random>
12 
13 #include <store.hpp>
14 
15 #include "sdk-model.hpp"
16 #include "sdk-model-cursor-tag.hpp"
17 #include "client.hpp"
18 #include "thread-safety-helper.hpp"
19 
20 #include "random-generator.hpp"
21 
22 
23 namespace Kazv
24 {
28  template<class EventLoop, class Xform, class ...Enhancers>
29  class Sdk
30  {
31  using ModelT = ::Kazv::SdkModel;
33  using ActionT = typename ModelT::Action;
34  using CursorT = lager::reader<ModelT>;
35  using CursorTSP = std::shared_ptr<CursorT>;
36 
37  using StoreT = decltype(
38  makeStore<ActionT>(
39  std::declval<ModelT>(),
41  std::declval<EventLoop>(),
42  lager::with_deps(
43  std::ref(detail::declref<JobInterface>()),
44  std::ref(detail::declref<EventInterface>()),
45  lager::dep::as<SdkModelCursorKey>(std::declval<std::function<CursorTSP()>>()),
46  std::ref(detail::declref<RandomInterface>())
47 #ifdef KAZV_USE_THREAD_SAFETY_HELPER
48  , std::ref(detail::declref<EventLoopThreadIdKeeper>())
49 #endif
50  ),
51  std::declval<Enhancers>()...)
52  );
53 
54  using DepsT = lager::deps<JobInterface &, EventInterface &, SdkModelCursorKey, RandomInterface &
55 #ifdef KAZV_USE_THREAD_SAFETY_HELPER
56  , EventLoopThreadIdKeeper &
57 #endif
58  >;
59 
61  public:
62  Sdk(ModelT model,
63  JobInterface &jobHandler,
64  EventInterface &eventEmitter,
65  EventLoop &&eventLoop,
66  Xform &&xform,
67  Enhancers &&...enhancers)
68  : m_d(std::make_unique<Private>(
69  std::move(model), jobHandler, eventEmitter,
70  std::forward<EventLoop>(eventLoop), std::forward<Xform>(xform),
71  std::forward<Enhancers>(enhancers)...)) {}
72 
79  ContextT context() const {
80  return m_d->store;
81  }
82 
88  Client client() const {
89  return {Client::InEventLoopTag{}, ContextT(m_d->store)};
90  }
91 
102  template<class EL>
103  auto createSecondaryRoot(EL &&eventLoop, ModelT initialModel = ModelT{}) const {
104  auto secondaryStore = lager::make_store<ModelT>(
105  std::move(initialModel),
106  std::forward<EL>(eventLoop),
107  lager::with_reducer([](auto &&, auto next) { return next; }));
108 
109  lager::context<ModelT> secondaryCtx = secondaryStore;
110 
112  .then([secondaryCtx, d=m_d.get()](auto &&) {
113  lager::watch(*(d->sdk),
114  [secondaryCtx](auto next) { secondaryCtx.dispatch(std::move(next)); });
115  });
116 
117  return secondaryStore;
118  }
119 
132  Client clientFromSecondaryRoot(lager::reader<ModelT> sr) const {
133  return Client(sr, ContextT(m_d->store));
134  }
135 
136  private:
137  struct Private
138  {
139  Private(ModelT model,
140  JobInterface &jobHandler,
141  EventInterface &eventEmitter,
142  EventLoop &&eventLoop,
143  Xform &&xform,
144  Enhancers &&...enhancers)
146  , store(makeStore<ActionT>(
147  std::move(model),
148  &ModelT::update,
149  std::forward<EventLoop>(eventLoop),
150  lager::with_deps(
151  std::ref(jobHandler),
152  std::ref(eventEmitter),
153  lager::dep::as<SdkModelCursorKey>(
154  std::function<CursorTSP()>([this] { return sdk; })),
155  std::ref(rg.value())
156 #ifdef KAZV_USE_THREAD_SAFETY_HELPER
157  , std::ref(keeper)
158 #endif
159  ),
160  std::forward<Enhancers>(enhancers)...))
161  , sdk(std::make_shared<lager::reader<ModelT>>(store.reader().xform(std::forward<Xform>(xform))))
162  {
163 #ifdef KAZV_USE_THREAD_SAFETY_HELPER
164  store.context().createResolvedPromise(EffectStatus{})
165  .then([this](auto &&) {
166  keeper.set(std::this_thread::get_id());
167  });
168 #endif
169  }
170 #ifdef KAZV_USE_THREAD_SAFETY_HELPER
171  EventLoopThreadIdKeeper keeper;
172 #endif
173  std::optional<RandomInterface> rg;
174  StoreT store;
175  CursorTSP sdk;
176  };
177 
178  std::unique_ptr<Private> m_d;
179  };
180 
199  template<class EventLoop, class Xform, class ...Enhancers>
200  inline auto makeSdk(SdkModel sdk,
201  JobInterface &jobHandler,
202  EventInterface &eventEmitter,
203  EventLoop &&eventLoop,
204  Xform &&xform,
205  Enhancers &&...enhancers)
206  -> Sdk<EventLoop, Xform, Enhancers...>
207  {
208  return { std::move(sdk),
209  jobHandler,
210  eventEmitter,
211  std::forward<EventLoop>(eventLoop),
212  std::forward<Xform>(xform),
213  std::forward<Enhancers>(enhancers)... };
214  }
215 
220  {
221  return Crypto::constructRandomSize();
222  }
223 
224  template<class EventLoop, class Xform, class ...Enhancers>
225  [[deprecated("Use deterministic makeDefaultSdkWithCryptoRandom instead. In the future, this will be removed.")]]
227  JobInterface &jobHandler,
228  EventInterface &eventEmitter,
229  EventLoop &&eventLoop,
230  Xform &&xform,
231  Enhancers &&...enhancers)
232  -> Sdk<EventLoop, Xform, Enhancers...>
233  {
234  auto m = SdkModel{};
236 
237  return makeSdk(std::move(m),
238  jobHandler,
239  eventEmitter,
240  std::forward<EventLoop>(eventLoop),
241  std::forward<Xform>(xform),
242  std::forward<Enhancers>(enhancers)...);
243  }
244 
265  template<class PH, class Xform, class ...Enhancers>
267  RandomData random,
268  JobInterface &jobHandler,
269  EventInterface &eventEmitter,
270  PH &&ph,
271  Xform &&xform,
272  Enhancers &&...enhancers)
273  -> Sdk<PH, Xform, Enhancers...>
274  {
275  auto m = SdkModel{};
276  m.client.crypto = Crypto(RandomTag{}, std::move(random));
277 
278  return makeSdk(std::move(m),
279  jobHandler,
280  eventEmitter,
281  std::forward<PH>(ph),
282  std::forward<Xform>(xform),
283  std::forward<Enhancers>(enhancers)...);
284  }
285 
286 
295  {
296  return lager::with_deps(std::ref(random));
297  }
298 }
Represent a Matrix client.
Definition: client.hpp:59
Definition: context.hpp:130
PromiseT createResolvedPromise(RetType v) const
Definition: context.hpp:185
Definition: crypto.hpp:36
Definition: eventinterface.hpp:15
A movable wrapper around std::random_device.
Definition: random-generator.hpp:103
Definition: random-generator.hpp:16
Contain the single source of truth of a matrix sdk.
Definition: sdk.hpp:30
Sdk(ModelT model, JobInterface &jobHandler, EventInterface &eventEmitter, EventLoop &&eventLoop, Xform &&xform, Enhancers &&...enhancers)
Definition: sdk.hpp:62
ContextT context() const
Get the context associated with this.
Definition: sdk.hpp:79
Client client() const
Get a Client representing this.
Definition: sdk.hpp:88
auto createSecondaryRoot(EL &&eventLoop, ModelT initialModel=ModelT{}) const
Create a secondary root for this Sdk.
Definition: sdk.hpp:103
Client clientFromSecondaryRoot(lager::reader< ModelT > sr) const
Get a Client representing this.
Definition: sdk.hpp:132
Definition: location.hpp:10
@ Private
Definition: client-model.hpp:41
auto makeSdk(SdkModel sdk, JobInterface &jobHandler, EventInterface &eventEmitter, EventLoop &&eventLoop, Xform &&xform, Enhancers &&...enhancers) -> Sdk< EventLoop, Xform, Enhancers... >
Create an sdk with the provided model.
Definition: sdk.hpp:200
lager::dep::key< SdkModelCursorTag, lager::dep::fn< std::shared_ptr< lager::reader< SdkModel > >> > SdkModelCursorKey
Definition: sdk-model-cursor-tag.hpp:23
std::string RandomData
Definition: crypto-util.hpp:34
RandomData genRandomData(int len)
Definition: crypto-util.hpp:76
std::size_t makeDefaultSdkWithCryptoRandomSize()
Definition: sdk.hpp:219
auto withRandomGenerator(RandomInterface &random)
An enhancer to use a custom random generator.
Definition: sdk.hpp:294
auto makeDefaultSdkWithCryptoRandom(RandomData random, JobInterface &jobHandler, EventInterface &eventEmitter, PH &&ph, Xform &&xform, Enhancers &&...enhancers) -> Sdk< PH, Xform, Enhancers... >
Create an sdk with a default-constructed model, and a Crypto constructed with user-provided random da...
Definition: sdk.hpp:266
auto makeDefaultEncryptedSdk(JobInterface &jobHandler, EventInterface &eventEmitter, EventLoop &&eventLoop, Xform &&xform, Enhancers &&...enhancers) -> Sdk< EventLoop, Xform, Enhancers... >
Definition: sdk.hpp:226
auto makeStore(Model &&initialModel, Reducer &&reducer, PH &&ph, Enhancers &&...enhancers)
Definition: store.hpp:141
Definition: clientutil.hpp:217
Definition: client-model.hpp:59
std::optional< immer::box< Crypto > > crypto
Definition: client-model.hpp:85
Definition: client.hpp:74
Definition: jobinterface.hpp:21
The tag to indicate that a constructor should use user-provided random data.
Definition: crypto-util.hpp:32
Definition: sdk-model.hpp:26
SdkAction Action
Definition: sdk-model.hpp:32
static SdkResult update(SdkModel s, SdkAction a)
Definition: sdk-model.cpp:23
ClientModel client
Definition: sdk-model.hpp:27