├── .clang-format ├── .gitignore ├── LICENSE ├── Makefile ├── README.org ├── examples ├── test-consumer.php └── test-producer.php └── src ├── Client.cpp ├── Client.h ├── Consumer.cpp ├── Consumer.h ├── ConsumerConfiguration.cpp ├── ConsumerConfiguration.h ├── Message.cpp ├── Message.h ├── MessageBuilder.cpp ├── MessageBuilder.h ├── MessageId.cpp ├── MessageId.h ├── Producer.cpp ├── Producer.h └── Pulsar.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 4 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.o -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Oraoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CPP = g++ 2 | RM = rm -f 3 | CPP_FLAGS = -Wall -c -I. -g -std=c++11 4 | 5 | LD = g++ 6 | LD_FLAGS = -Wall -shared -O2 7 | RESULT = pulsar-phpcpp.so 8 | 9 | SOURCES = $(wildcard src/*.cpp) 10 | OBJECTS = $(SOURCES:%.cpp=%.o) 11 | 12 | all: ${OBJECTS} ${RESULT} 13 | 14 | ${RESULT}: ${OBJECTS} 15 | ${LD} ${LD_FLAGS} -o $@ ${OBJECTS} -lphpcpp -lpulsar 16 | 17 | clean: 18 | ${RM} *.obj *~* ${OBJECTS} ${RESULT} 19 | 20 | src/%.o: src/%.cpp 21 | ${CPP} ${CPP_FLAGS} -fpic -c $< -o $@ 22 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * Apache Pulsar client library for PHP 2 | 3 | ** Build 4 | 5 | Requirements: 6 | 7 | - [[https://github.com/apache/pulsar/tree/master/pulsar-client-cpp/][Pulsar C++ client library]] 8 | - [[https://github.com/CopernicaMarketingSoftware/PHP-CPP][PHP-CPP]] 9 | - PHP 7.4 10 | 11 | Compilation: 12 | 13 | #+begin_src 14 | git clone git@github.com:oraoto/pulsar-client-phpcpp.git 15 | make -j4 16 | #+end_src 17 | 18 | ** Usage 19 | 20 | See [[./examples][examples]] for more examples. 21 | -------------------------------------------------------------------------------- /examples/test-consumer.php: -------------------------------------------------------------------------------- 1 | setConsumerType(Consumer::ConsumerShared); 12 | 13 | $consumer = $client->subscribe("persistent://prop/r1/ns1/test-topic", "consumer-1", $config); 14 | 15 | while (true) { 16 | $message = $consumer->receive(); 17 | var_dump($message->getDataAsString()); 18 | $consumer->acknowledge($message); 19 | } 20 | -------------------------------------------------------------------------------- /examples/test-producer.php: -------------------------------------------------------------------------------- 1 | createProducer("persistent://prop/r1/ns1/test-topic"); 9 | 10 | $prop = [ 11 | "a" => 1, 12 | ]; 13 | 14 | $builder = new MessageBuilder(); 15 | $builder->setContent("Amazing " . time()) 16 | ->setProperties($prop); 17 | 18 | unset($prop); 19 | 20 | $message = $builder->setDeliverAfter(5000)->build(); 21 | $producer->send($message); 22 | -------------------------------------------------------------------------------- /src/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "Consumer.h" 3 | #include "ConsumerConfiguration.h" 4 | #include "Producer.h" 5 | 6 | void Client::__construct(Php::Parameters ¶ms) { 7 | std::string serviceUrl = params[0]; 8 | this->client = new ::pulsar::Client(serviceUrl); 9 | } 10 | 11 | Php::Value Client::createProducer(Php::Parameters ¶ms) { 12 | Producer *producer = new Producer(); 13 | this->client->createProducer(params[0], producer->producer); 14 | return Php::Object("Pulsar\\Producer", producer); 15 | } 16 | 17 | Php::Value Client::subscribe(Php::Parameters ¶ms) { 18 | Consumer *consumer = new Consumer(); 19 | 20 | if (params.size() == 2 && params[0].isString() && params[1].isString()) { 21 | std::string topic = params[0]; 22 | std::string consumerName = params[1]; 23 | this->client->subscribe(topic, consumerName, consumer->consumer); 24 | return Php::Object("Pulsar\\Consumer", consumer); 25 | } 26 | 27 | if (params.size() == 3 && params[0].isString() && params[1].isString() && 28 | params[2].isObject()) { 29 | std::string topic = params[0]; 30 | std::string consumerName = params[1]; 31 | auto conf = (ConsumerConfiguration *)(params[2].implementation()); 32 | this->client->subscribe(topic, consumerName, conf->config, 33 | consumer->consumer); 34 | return Php::Object("Pulsar\\Consumer", consumer); 35 | } 36 | 37 | return Php::Object("Pulsar\\Consumer", consumer); 38 | } 39 | 40 | void registerClient(Php::Namespace &pulsarNamespace) { 41 | Php::Class client("Client"); 42 | client.method<&Client::__construct>("__construct"); 43 | client.method<&Client::createProducer>("createProducer"); 44 | client.method<&Client::subscribe>("subscribe"); 45 | pulsarNamespace.add(client); 46 | } 47 | -------------------------------------------------------------------------------- /src/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Client : public Php::Base { 7 | 8 | public: 9 | pulsar::Client *client; 10 | 11 | ~Client() {} 12 | 13 | void __construct(Php::Parameters ¶ms); 14 | 15 | Php::Value createProducer(Php::Parameters ¶ms); 16 | 17 | Php::Value subscribe(Php::Parameters ¶ms); 18 | 19 | // Php::Value createReader(Php::Parameters ¶ms); 20 | 21 | // Php::Value getPartitionsForTopic(Php::Parameters ¶ms); 22 | 23 | // void close(); 24 | 25 | // void shutdown(); 26 | }; 27 | 28 | void registerClient(Php::Namespace &pulsarNamespace); 29 | -------------------------------------------------------------------------------- /src/Consumer.cpp: -------------------------------------------------------------------------------- 1 | #include "Consumer.h" 2 | #include "Message.h" 3 | 4 | Php::Value Consumer::receive(Php::Parameters ¶ms) { 5 | Message *message = new Message(); 6 | this->consumer.receive(message->message); 7 | return Php::Object("Pulsar\\Message", message); 8 | } 9 | 10 | void Consumer::acknowledge(Php::Parameters ¶ms) { 11 | auto message = (Message *)(params[0].implementation()); 12 | this->consumer.acknowledge(message->message); 13 | } 14 | 15 | void registerConsumer(Php::Namespace &pulsarNamespace) { 16 | Php::Class consumer("Consumer"); 17 | consumer.method<&Consumer::receive>("receive"); 18 | consumer.method<&Consumer::acknowledge>("acknowledge"); 19 | 20 | consumer.property("ConsumerExclusive", ::pulsar::ConsumerExclusive, 21 | Php::Const); 22 | consumer.property("ConsumerShared", ::pulsar::ConsumerShared, Php::Const); 23 | consumer.property("ConsumerFailover", ::pulsar::ConsumerFailover, 24 | Php::Const); 25 | consumer.property("ConsumerKeyShared", ::pulsar::ConsumerKeyShared, 26 | Php::Const); 27 | 28 | pulsarNamespace.add(consumer); 29 | } 30 | -------------------------------------------------------------------------------- /src/Consumer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class Consumer : public Php::Base { 8 | 9 | public: 10 | pulsar::Consumer consumer; 11 | 12 | Consumer() {} 13 | 14 | Php::Value receive(Php::Parameters ¶ms); 15 | 16 | void acknowledge(Php::Parameters ¶ms); 17 | }; 18 | 19 | void registerConsumer(Php::Namespace &pulsarNamespace); 20 | -------------------------------------------------------------------------------- /src/ConsumerConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include "ConsumerConfiguration.h" 2 | #include "Message.h" 3 | #include 4 | 5 | #define CONSUMER_CONFIGURATION_CLASS_NAME "Pulsar\\ConsumerConfiguration" 6 | 7 | Php::Value ConsumerConfiguration::setConsumerType(Php::Parameters ¶ms) { 8 | auto consumerType = pulsar::ConsumerType((params[0].numericValue())); 9 | this->config.setConsumerType(consumerType); 10 | return Php::Object(CONSUMER_CONFIGURATION_CLASS_NAME, this); 11 | } 12 | 13 | void registerConsumerConfiguration(Php::Namespace &pulsarNamespace) { 14 | Php::Class consumerConfiguration( 15 | "ConsumerConfiguration"); 16 | consumerConfiguration.method<&ConsumerConfiguration::setConsumerType>( 17 | "setConsumerType"); 18 | pulsarNamespace.add(consumerConfiguration); 19 | } 20 | -------------------------------------------------------------------------------- /src/ConsumerConfiguration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class ConsumerConfiguration : public Php::Base { 7 | 8 | public: 9 | pulsar::ConsumerConfiguration config; 10 | 11 | ConsumerConfiguration(){}; 12 | 13 | Php::Value setConsumerType(Php::Parameters ¶ms); 14 | }; 15 | 16 | void registerConsumerConfiguration(Php::Namespace &pulsarNamespace); 17 | -------------------------------------------------------------------------------- /src/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.h" 2 | 3 | Message::Message(pulsar::Message msg) { this->message = msg; } 4 | 5 | Php::Value Message::getDataAsString() { 6 | return this->message.getDataAsString(); 7 | } 8 | 9 | void registerMessage(Php::Namespace &pulsarNamespace) { 10 | Php::Class message("Message"); 11 | message.method<&Message::getDataAsString>("getDataAsString"); 12 | pulsarNamespace.add(message); 13 | } 14 | -------------------------------------------------------------------------------- /src/Message.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message : public Php::Base { 7 | public: 8 | pulsar::Message message; 9 | 10 | Message() {} 11 | Message(pulsar::Message msg); 12 | 13 | Php::Value getDataAsString(); 14 | 15 | // Php::Value getProperties(); 16 | // Php::Value hasProperty(Php::Parameters ¶ms); 17 | // Php::Value getProperty(Php::Parameters ¶ms); 18 | // Php::Value getMessageId(); 19 | // Php::Value getPartitionKey(Php::Parameters ¶ms); 20 | // Php::Value hasPartitionKey(); 21 | }; 22 | 23 | void registerMessage(Php::Namespace &pulsarNamespace); 24 | -------------------------------------------------------------------------------- /src/MessageBuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "MessageBuilder.h" 2 | #include "Message.h" 3 | #include 4 | 5 | #define MESSAGE_BUILDER_CLASS_NAME "Pulsar\\MessageBuilder" 6 | 7 | Php::Value MessageBuilder::setContent(Php::Parameters ¶ms) { 8 | std::string content = params[0]; 9 | this->builder.setContent(content); 10 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 11 | } 12 | 13 | Php::Value MessageBuilder::setProperty(Php::Parameters ¶ms) { 14 | std::string name = params[0]; 15 | std::string value = params[1]; 16 | this->builder.setProperty(name, value); 17 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 18 | } 19 | 20 | Php::Value MessageBuilder::setPartitionKey(Php::Parameters ¶ms) { 21 | std::string partitionKey = params[0]; 22 | this->builder.setPartitionKey(partitionKey); 23 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 24 | } 25 | 26 | Php::Value MessageBuilder::setOrderingKey(Php::Parameters ¶ms) { 27 | std::string orderingKey = params[0]; 28 | this->builder.setOrderingKey(orderingKey); 29 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 30 | } 31 | 32 | Php::Value MessageBuilder::setDeliverAfter(Php::Parameters ¶ms) { 33 | int delay = params[0]; 34 | this->builder.setDeliverAfter(std::chrono::milliseconds(delay)); 35 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 36 | } 37 | 38 | Php::Value MessageBuilder::setDeliverAt(Php::Parameters ¶ms) { 39 | int64_t deliveryTimestamp = params[0]; 40 | this->builder.setDeliverAt(deliveryTimestamp); 41 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 42 | } 43 | 44 | Php::Value MessageBuilder::setEventTimestamp(Php::Parameters ¶ms) { 45 | int64_t eventTimestamp = params[0]; 46 | this->builder.setDeliverAt(eventTimestamp); 47 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 48 | } 49 | 50 | Php::Value MessageBuilder::setSequenceId(Php::Parameters ¶ms) { 51 | int64_t sequenceId = params[0]; 52 | this->builder.setSequenceId(sequenceId); 53 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 54 | } 55 | 56 | Php::Value MessageBuilder::disableReplication(Php::Parameters ¶ms) { 57 | bool flag = params[0]; 58 | this->builder.disableReplication(flag); 59 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 60 | } 61 | 62 | Php::Value MessageBuilder::setProperties(Php::Parameters ¶ms) { 63 | std::map properties; 64 | for (auto v : params[0].mapValue()) { 65 | properties[v.first] = v.second.stringValue(); 66 | } 67 | this->builder.setProperties(properties); 68 | return Php::Object(MESSAGE_BUILDER_CLASS_NAME, this); 69 | } 70 | 71 | Php::Value MessageBuilder::build() { 72 | auto message = this->builder.build(); 73 | return Php::Object("Pulsar\\Message", new Message(message)); 74 | } 75 | 76 | void registerMessageBuilder(Php::Namespace &pulsarNamespace) { 77 | Php::Class builder("MessageBuilder"); 78 | builder.method<&MessageBuilder::setContent>("setContent"); 79 | builder.method<&MessageBuilder::setProperty>("setProperty"); 80 | builder.method<&MessageBuilder::setProperties>("setProperties"); 81 | builder.method<&MessageBuilder::setPartitionKey>("setPartiionKey"); 82 | builder.method<&MessageBuilder::setOrderingKey>("setOrderingKey"); 83 | builder.method<&MessageBuilder::setDeliverAfter>("setDeliverAfter"); 84 | builder.method<&MessageBuilder::setDeliverAt>("setDeliverAt"); 85 | builder.method<&MessageBuilder::setEventTimestamp>("setEventTimestamp"); 86 | builder.method<&MessageBuilder::setSequenceId>("sequenceId"); 87 | builder.method<&MessageBuilder::disableReplication>("disableReplication"); 88 | builder.method<&MessageBuilder::build>("build"); 89 | pulsarNamespace.add(builder); 90 | } 91 | -------------------------------------------------------------------------------- /src/MessageBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class MessageBuilder : public Php::Base { 7 | public: 8 | pulsar::MessageBuilder builder; 9 | 10 | MessageBuilder() {} 11 | 12 | Php::Value setContent(Php::Parameters ¶ms); 13 | 14 | Php::Value build(); 15 | 16 | Php::Value setProperty(Php::Parameters ¶ms); 17 | 18 | Php::Value setPartitionKey(Php::Parameters ¶ms); 19 | 20 | Php::Value setOrderingKey(Php::Parameters ¶ms); 21 | Php::Value setDeliverAfter(Php::Parameters ¶ms); 22 | Php::Value setDeliverAt(Php::Parameters ¶ms); 23 | Php::Value setEventTimestamp(Php::Parameters ¶ms); 24 | Php::Value setSequenceId(Php::Parameters ¶ms); 25 | 26 | Php::Value disableReplication(Php::Parameters ¶ms); 27 | 28 | Php::Value setProperties(Php::Parameters ¶ms); 29 | // TODO 30 | // Php::Value setReplicationClusters(Php::Parameters ¶ms); 31 | // Php::Value create(); 32 | }; 33 | 34 | void registerMessageBuilder(Php::Namespace &pulsarNamespace); 35 | -------------------------------------------------------------------------------- /src/MessageId.cpp: -------------------------------------------------------------------------------- 1 | #include "MessageId.h" 2 | #include 3 | 4 | #define MESSAGE_ID_CLASS_NAME "Pulsar\\MessageId" 5 | 6 | MessageId::MessageId(pulsar::MessageId messageId) { this->messageId = messageId; } 7 | 8 | static Php::Value earliest() 9 | { 10 | auto messageId = new MessageId(pulsar::MessageId::earliest()); 11 | return Php::Object(MESSAGE_ID_CLASS_NAME, messageId); 12 | } 13 | 14 | static Php::Value latest() 15 | { 16 | auto messageId = new MessageId(pulsar::MessageId::latest()); 17 | return Php::Object(MESSAGE_ID_CLASS_NAME, messageId); 18 | } 19 | 20 | Php::Value MessageId::getTopicName() 21 | { 22 | return this->messageId.getTopicName(); 23 | } 24 | 25 | void MessageId::setTopicName(Php::Parameters ¶ms) 26 | { 27 | return this->messageId.setTopicName(params[0]); 28 | } 29 | 30 | Php::Value MessageId::deserialize(Php::Parameters ¶ms) 31 | { 32 | auto messageId = new MessageId(pulsar::MessageId::deserialize(params[0])); 33 | return Php::Object(MESSAGE_ID_CLASS_NAME, messageId); 34 | } 35 | 36 | Php::Value MessageId::serialize(Php::Parameters ¶ms) 37 | { 38 | std::string *result = new std::string(); 39 | this->messageId.serialize(*result); 40 | return result; 41 | } 42 | 43 | void registerMessageId(Php::Namespace &pulsarNamespace) 44 | { 45 | Php::Class messageId("MessageId"); 46 | messageId.method<&MessageId::earliest>("earliest"); 47 | messageId.method<&MessageId::latest>("latest"); 48 | messageId.method<&MessageId::getTopicName>("getTopicName"); 49 | messageId.method<&MessageId::serialize>("serialize"); 50 | messageId.method<&MessageId::deserialize>("deserialize"); 51 | } 52 | -------------------------------------------------------------------------------- /src/MessageId.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class MessageId : public Php::Base { 7 | public: 8 | pulsar::MessageId messageId; 9 | 10 | MessageId(pulsar::MessageId msgId); 11 | 12 | static Php::Value earliest(Php::Parameters ¶ms); 13 | static Php::Value latest(Php::Parameters ¶ms); 14 | 15 | Php::Value getTopicName(); 16 | void setTopicName(Php::Parameters ¶ms); 17 | 18 | Php::Value serialize(Php::Parameters ¶ms); 19 | static Php::Value deserialize(Php::Parameters ¶ms); 20 | }; 21 | 22 | void registerMessageId(Php::Namespace &pulsarNamespace); 23 | -------------------------------------------------------------------------------- /src/Producer.cpp: -------------------------------------------------------------------------------- 1 | #include "Producer.h" 2 | #include "Message.h" 3 | 4 | void Producer::send(Php::Parameters ¶ms) { 5 | auto message = (Message *)(params[0].implementation()); 6 | this->producer.send(message->message); 7 | } 8 | 9 | void registerProducer(Php::Namespace &pulsarNamespace) { 10 | Php::Class producer("Producer"); 11 | producer.method<&Producer::send>("send"); 12 | pulsarNamespace.add(producer); 13 | } 14 | -------------------------------------------------------------------------------- /src/Producer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Producer : public Php::Base { 7 | 8 | public: 9 | pulsar::Producer producer; 10 | 11 | Producer() {} 12 | 13 | void send(Php::Parameters ¶ms); 14 | }; 15 | 16 | void registerProducer(Php::Namespace &pulsarNamespace); 17 | -------------------------------------------------------------------------------- /src/Pulsar.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "Consumer.h" 3 | #include "ConsumerConfiguration.h" 4 | #include "Message.h" 5 | #include "MessageBuilder.h" 6 | #include "Producer.h" 7 | #include 8 | 9 | extern "C" { 10 | PHPCPP_EXPORT void *get_module() { 11 | static Php::Extension extension("pulsar-phpcpp", "0.1"); 12 | 13 | Php::Namespace pulsarNamespace("Pulsar"); 14 | 15 | registerMessage(pulsarNamespace); 16 | registerMessageBuilder(pulsarNamespace); 17 | registerProducer(pulsarNamespace); 18 | registerConsumer(pulsarNamespace); 19 | registerClient(pulsarNamespace); 20 | registerConsumerConfiguration(pulsarNamespace); 21 | 22 | extension.add(pulsarNamespace); 23 | 24 | return extension; 25 | } 26 | } 27 | --------------------------------------------------------------------------------