How to create a ReplaySubject with RxCpp? - c++

In my c++ project, I need to create Subjects having an initial value, that may be updated. On each subscription/update, subscribers may trigger then data processing... In a previous Angular (RxJS) project, this kind of behavior was handled with ReplaySubject(1).
I'm not able to reproduce this using c++ rxcpp lib.
I've looked up for documentation, snippets, tutorials, but without success.
Expected pseudocode (typescript):
private dataSub: ReplaySubject<Data> = new ReplaySubject<Data>(1);
private init = false;
// public Observable, immediatly share last published value
get currentData$(): Observable<Data> {
if (!this.init) {
return this.initData().pipe(switchMap(
() => this.dataSub.asObservable()
));
}
return this.dataSub.asObservable();
}

I think you are looking for rxcpp::subjects::replay.
Please try this:
auto coordination = rxcpp::observe_on_new_thread();
rxcpp::subjects::replay<int, decltype(coordination)> test(1, coordination);
// to emit data
test.get_observer().on_next(1);
test.get_observer().on_next(2);
test.get_observer().on_next(3);
// to subscribe
test.get_observable().subscribe([](auto && v)
printf("%d\n", v); // this will print '3'
});

Related

How to consume messages from Kafka using cppkafka

Ok, so I'm a new with all the Kafka stuff and cppkafka library in particular. I'm trying to write my convenience wrapper on top of cppkafka. The producer side is quite straightforward and looks like it does what it supposed to do
cppkafka::Producer producer(cppkafka::Configuration{{"metadata.broker.list", "localhost:9092"}});
producer.produce(cppkafka::MessageBuilder(topic[0])
.partition((message_counter++) % partitions)
.payload(buffer.str()));
producer.flush();
Error handling and retries, here and below, were removed for brevity.
This code produces messages that I can see using whatever kafka UI.
The consumer side is somewhat more complicated
cppkafka::Consumer consumer(cppkafka::Configuration{
{"metadata.broker.list", "localhost:9092"},
{"group.id", "MyGroup"},
{"client.id", "MyClient"},
// {"auto.offset.reset", "smallest"},
// {"auto.offset.reset", "earliest"},
// {"enable.auto.offset.store", "false"},
{"enable.partition.eof", "false"},
{"enable.auto.commit", "false"}});
cppkafka::TopicPartitionList assignment;
consumer.set_assignment_callback([&, this](cppkafka::TopicPartitionList& partitions_) {
assignment = partitions_;
LOG_INFO(log, "Partitions assigned");
});
consumer.set_rebalance_error_callback([this](cppkafka::Error error) {
LOG_ERROR(log, "Rebalancing error. Reason: {}", error.to_string());
});
consumer.set_revocation_callback([&, this](const cppkafka::TopicPartitionList&) {
assignment.clear();
LOG_INFO(log, "Partitions revoked");
});
consumer.subscribe({topic});
auto start = std::chrono::high_resolution_clock::now();
while (some_condition)
{
auto subscriptions = consumer.get_subscription();
if (subscriptions.empty())
{
consumer.subscribe(topic);
}
cppkafka::Message msg = consumer.poll(100ms);
if (!msg)
{
if (!assignment.empty())
{
auto committed_offset = consumer.get_offsets_committed(consumer.get_assignment());
consumer.assign(committed_offset);
}
continue;
}
try
{
std::string_view payload_view(reinterpret_cast<const char *>(msg.get_payload().get_data()), msg.get_payload().get_size());
consumer.commit(msg);
}
....
}
Looks like this code not picking old uncommitted messages, the poll always returns null message. I have no idea whats going on here and why it leaves old messages in the queue. As one can see in the beginning of the last code snippet I've tried various consumer settings to no avail. What I'm missing here? Maybe I have to configure something on the Kafka side? Like, some topic settings? Or the problem with the consumer configuration?
One important (I think) detail. Messages may be added before any consumer connects to the Kafka. Maybe it is important?

Smarthome AOG. The best way (in 2021) to integrate state of devices with firestore fields

I have this project: https://github.com/neuberfran/firebasefunction/blob/main/firebase/functions/smart-home/fulfillment.js
It works well. But, for example, I want to implement a condition that if I have the garage closed and I said "close garage", the Home assistantt will alert me about it.
As shown in the photo below, I am using an rpi3/iot-device/back-end that controls the garagestate field.
I need to know the best way to implement this condition, that is, read the value of the garagestate field and from that, know if I can open the garage or not:
You'd probably need to add an intermediary condition in your onExecute to return an error based on the Firestore state:
// ...
for (const target of command.devices) {
const configRef = firestore.doc(`device-configs/${target.id}`)
const targetDoc = await configRef.get()
const {garagestate} = targetDoc.data()
if (garagestate === false) {
// garagestate exists and is false
// return an error
return {
requestId,
payload: {
status: 'ERROR',
errorCode: 'alreadyClosed'
}
}
}
// ...
}
// ...

How to wait for a promise to be fulfilled before continuing

How can I wait until a Promise is resolved before executing the next line of code?
e.g.
var option = null;
if(mustHaveOption){
option = store.find("option", 1).then(function(option){ return option })
}
//wait until promise is resolved before returning this value
return option;
rallrall provided the correct answer in his comment: you can't
The solution for me was to redesign my code to return promises and then the receiving function must evaluate the result something along the lines of:
function a(){
var option = null;
return mustHaveOption ? store.find("option", 1) : false;
}
}
function b(){
res = a();
if (!res){
res.then(function(option){
// see option here
});
}
}
Another key solution for me was to use a hash of promises. One creates an array of all the promises that must be resolve before executing the next code:
Em.RSVP.Promise.all(arrayOfPromises).then(function(results){
//code that must be executed only after all of the promises in arrayOfPromises is resolved
});
It tooks me a while to wrap my head around this async way of programming - but once I did things work quite nicely.
With ES6, you can now use the async/await syntax. It makes the code much more readable:
async getSomeOption() {
var option = null;
if (mustHaveOption) {
option = await store.find("option", 1)
}
}
return option;
PS: this code could be simplified, but I'd rather keep it close from the example given above.
You can start to show a loading gif, then you can subscribe to the didLoad event for the record, inside which you can continue your actual processing..
record = App.User.find(1);
//show gif..
record.on("didLoad", function() {
console.log("ren loaded!");
});
//end gif; continue processing..

symfony2.1 translatable saved, but not retrieved

Basically, I had the same problem as here:
Symfony2 & Translatable : entity's locale is empty
Translations where saved in the ext_translations table, but where not being displayed.
After adding the proposed fix, it DID work.
Today I upgraded from 2.0 to 2.1 I managed to get pretty much everything working so far.
But now my translatables are again not being displayed properly (they ARE still being saved properly).
I think it has something to do with the changes to where and how the users locale is stored in 2.1 compared to 2.0 .. but i cannot figure this one out.
Fixed this by registering a custom listener
namespace XXX;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class LocaleListener implements EventSubscriberInterface
{
private $defaultLocale;
public function __construct($defaultLocale = 'en')
{
$this->defaultLocale = $defaultLocale;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$request->hasPreviousSession()) {
return;
}
if ($locale = $request->attributes->get('_locale')) {
$request->getSession()->set('_locale', $request->getLocale());
} else {
$request->setDefaultLocale($request->getSession()->get('_locale', $this->defaultLocale));
}
}
static public function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
then changed
$request->setDefaultLocale($request->getSession()->get('_locale', $this->defaultLocale));
to
$request->setLocale($request->getSession()->get('_locale'));
and used
$this->getRequest()->getSession()->set('_locale', 'nl');
to set the locale, translations and translatables now work
hope this also helps someone else ..

How do I insert test data in Play Framework 2.0 (Scala)?

I'm having some problems with making my tests insert fake data in my database. I've tried a few approaches, without luck. It seems that Global.onStart is not run when running tests within a FakeApplication, although I think I read that it should work.
object TestGlobal extends GlobalSettings {
val config = Map("global" -> "controllers.TestGlobal")
override def onStart(app: play.api.Application) = {
// load the data ...
}
}
And in my test code:
private def fakeApp = FakeApplication(additionalConfiguration = (
inMemoryDatabase().toSeq +
TestGlobal.config.toSeq
).toMap, additionalPlugins = Seq("plugin.InsertTestDataPlugin"))
Then I use running(fakeApp) within each test.
The plugin.InsertTestDataPlugin was another attempt, but it didn't work without defining the plugin in conf/play.plugins -- and that is not wanted, as I only want this code in the test scope.
Should any of these work? Have anyone succeeded with similar options?
Global.onStart should be executed ONCE (and only once) when the application is launched, whatever mode (dev, prod, test) it is in. Try to follow the wiki on how to use Global.
In that method then you can check the DB status and populate. For example in Test if you use an in-memory db it should be empty so do something akin to:
if(User.findAll.isEmpty) { //code taken from Play 2.0 samples
Seq(
User("guillaume#sample.com", "Guillaume Bort", "secret"),
User("maxime#sample.com", "Maxime Dantec", "secret"),
User("sadek#sample.com", "Sadek Drobi", "secret"),
User("erwan#sample.com", "Erwan Loisant", "secret")
).foreach(User.create)
}
I chose to solve this in another way:
I made a fixture like this:
def runWithTestDatabase[T](block: => T) {
val fakeApp = FakeApplication(additionalConfiguration = inMemoryDatabase())
running(fakeApp) {
ProjectRepositoryFake.insertTestDataIfEmpty()
block
}
}
And then, instead of running(FakeApplication()){ /* ... */}, I do this:
class StuffTest extends FunSpec with ShouldMatchers with CommonFixtures {
describe("Stuff") {
it("should be found in the database") {
runWithTestDatabase { // <--- *The interesting part of this example*
findStuff("bar").size must be(1);
}
}
}
}