-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement WebSub publisher + hub and subscriber #1
Comments
Answers to your questions: Publisher
Hub
Subscriber
|
Actually I'm not sure whether my answer for the separate publisher is right. In addition to delivering results to subscribed media orgs, we need to do the following:
I guess we can make all of these also be subscribers of the websub engine but that seems rather overkill? If we're not doing that, then we need to have a separate service for the results publisher to deliver to and then have that do the above items PLUS publish to the websub hub. Thoughts? |
Yeah, +1 for a separate service. I don't think doing this via the WebSub hub would add value, given that it would just result in an additional topic with one subscriber, or three subscribers for not-so-independent tasks. We can have this intermediary service start up the hub, and it could have direct access to the hub. Follow up questions/notes regarding the subscriptions:
While this could be done while setting up, the subscriber would have to respond to an intent verification request sent by the hub (the request is sent to the callback URL specified in the subscription request). The request would have a query param Can we expect the subscribers to echo the challenge? The
Authenticated content distribution - If the subscription request specified a secret, the hub sends a "X-Hub-Signature" header calculating a HMAC value for the content with the secret specified as the key, the subscriber has to validate the header for each content delivery. |
Yes we can ask them to respond to the intent verification. However, we have to dumb this down totally for them ... maybe provide them a server they can run. Basically we can write a (compiled) Ballerina client they run that just produces the files on the disk. They just run "java -jar mediaclient.jar" and then type in the secret and the files simply show up in that directory. That way they don't really need to understand anything - we say we will deliver the files to them directly. What do you think? Can we um get this working by Wednesday ;-). Straightforward really .. |
Yeah, we should be able to. So basically, we write the WebSub subscriber service for them, build it and give them the JAR? As input we would require from them
I was thinking a service like import ballerina/config;
import ballerina/websub;
@websub:SubscriberServiceConfig {
path: getAsStringOrPanic("subscriber.path"),
subscribeOnStartUp: true,
target: [getAsStringOrPanic("subscriber.hub"), getTopic()],
leaseSeconds: 172800,
secret: getAsStringOrPanic("subscriber.secret"),
callback: getAsStringOrPanic("subscriber.url")
}
service subscriberService on new websub:Listener(getAsIntOrPanic("subscriber.port")) {
resource function onNotification (websub:Notification notification) {
// Intro logic to write to files.
}
}
function getAsIntOrPanic(string key) returns int {
int value = config:getAsInt(key);
if (value == 0) {
panic error("Error", message = key + " not specified or 0");
}
return value;
}
function getAsStringOrPanic(string key) returns string {
string value = config:getAsString(key);
if (value.trim() == "") {
panic error("Error", message = key + " not specified or empty");
}
return value;
}
function getTopic() returns string {
string topic = getAsStringOrPanic("subscriber.topic");
match topic {
"https://github.com/ECLK/Results-Dist-json"|
"https://github.com/ECLK/Results-Dist-xml"|
"https://github.com/ECLK/Results-Dist-text" => {
return topic;
}
_ => {
panic error("Error", message = "invalid topic specified: " + topic);
}
}
} They would have to specify a ballerina.conf file similar to [subscriber]
hub="http://localhost:9090/websub/hub" # what we advertise as the hub
port=8181
path="/subscriber"
topic="https://github.com/ECLK/Results-Dist-json"
secret="qweKLS"
url="http://localhost:8181/subscriber" Also, regarding writing to the files,
So a new file in the current directory (or we could make this configurable) per update (result)? Probably with a name that is a combination of the timestamp and something random? |
Perhaps we can include 4 subscribers for predefined 4 topics(JSON, XML, Text, Image), build it and give them a JAR. So media companies only have to work with a single JAR and a ballerina.conf file rather than letting them to work with multiple jars for each subscriber. Depending on their requirement media teams can list down subscribers along with the topics in the conf file. When they lists down the topics that they need to subscribe in the conf file, our program can only start the required subscriber services. Apparently, they would have to specify a ballerina.conf file similar following it they need to subscribe for JSON and XML payloads.(We can provide a sample too) [subscriber.json]
hub="http://localhost:9090/websub/hub" # what we advertise as the hub
port=8181
path="/subscriberJson"
topic="https://github.com/ECLK/Results-Dist-json"
secret="qweKLS"
url="http://localhost:8181/subscriberJson"
[subscriber.xml]
hub="http://localhost:9090/websub/hub" # what we advertise as the hub
port=8181
path="/subscriberXml"
topic="https://github.com/ECLK/Results-Dist-xml"
secret="qweKLW"
url="http://localhost:8181/subscriberXml" |
No I'm going even MORE simple: we give them a program that gets them the results in ALL the formats as well as the signed document image. If they want to go fancy they can take this source code and do whatever they want. Lets keep it ultra simple. In that case the only info they need to give is their secret, the callback URL domain name/port (to get back to this service), and an optional path to store files into (otherwise we'll use CWD). |
We could also write the code late bind-ing the services depending on what the user wants. We could enable all by default, but give the option to the user to opt out of receiving content in certain formats. The information required would still be pretty much the same.
The only addition would be to disable receiving content of a particular type. [subscriber]
text=false Suggesting this because sending updates to all subscribers in all formats would mean 50 x 4 subscriptions minimum. This would also result in 4 files being created per result update to a single subscriber? I'm OK with either approach though. import ballerina/config;
import ballerina/websub;
websub:Listener websubListener = new(8181);
service jsonSubscriber =
@websub:SubscriberServiceConfig {
path: "/json",
subscribeOnStartUp: true,
target: ["http://localhost:9090/websub/hub", "https://github.com/ECLK/Results-Dist-json"],
leaseSeconds: 172800,
callback: "<JSON_CALLBACK>"
}
service {
resource function onNotification(websub:Notification notification) {
}
};
service xmlSubscriber =
@websub:SubscriberServiceConfig {
path: "/xml",
subscribeOnStartUp: true,
target: ["http://localhost:9090/websub/hub", "https://github.com/ECLK/Results-Dist-xml"],
leaseSeconds: 172800,
callback: "<XML_CALLBACK>"
}
service {
resource function onNotification(websub:Notification notification) {
}
};
service textSubscriber =
@websub:SubscriberServiceConfig {
path: "/text",
subscribeOnStartUp: true,
target: ["http://localhost:9090/websub/hub", "https://github.com/ECLK/Results-Dist-text"],
leaseSeconds: 172800,
callback: "<TEXT_CALLBACK>"
}
service {
resource function onNotification(websub:Notification notification) {
}
};
service imageSubscriber =
@websub:SubscriberServiceConfig {
path: "/image",
subscribeOnStartUp: true,
target: ["http://localhost:9090/websub/hub", "https://github.com/ECLK/Results-Dist-image"],
leaseSeconds: 172800,
callback: "<IMAGE_CALLBACK>"
}
service {
resource function onNotification(websub:Notification notification) {
}
};
public function main() {
if (config:getAsBoolean("subscriber.json", true)) {
checkpanic websubListener.__attach(jsonSubscriber);
}
if (config:getAsBoolean("subscriber.xml", true)) {
checkpanic websubListener.__attach(xmlSubscriber);
}
if (config:getAsBoolean("subscriber.text", true)) {
checkpanic websubListener.__attach(textSubscriber);
}
if (config:getAsBoolean("subscriber.image", true)) {
checkpanic websubListener.__attach(imageSubscriber);
}
checkpanic websubListener.__start();
} |
How about the following compromise:
I don't like the conf file because someone will mess it up. |
+1 Does this mean we wouldn't be using a conf file even for the other configs? If so, do we expect the user to pass the values as arguments (to the main function)? java -jar mediaclient.jar --all -secret=xxxx -port=8080 Or should we prompt the user to enter the values when they run the JAR? e.g., $ java -jar mediaclient.jar
Enter secret (random string with no spaces):
xxxx
Enter port:
8080
Enter required format (1-4):
1 - json
2 - text
3 - xml
4 - all
1 |
Prompting is hard to automate. So lets use options but use good defaults so they're minimal. How about:
Secret of course its safer to take from stdin (command line args are not safe) but lets ignore that for now and use a required argument:
is the command to run with all defaults. |
The updated subscriber source is now available at https://github.com/ECLK/Results-Dist/blob/master/src/subscriber/subscriber.bal. The main function has the following signature: public function main(string secret, string content = "json", string domain = "localhost", int port = 8080,
string? keystorePath = (), string keystorePassword = "") {
} Few more follow up questions :)
|
Shouldn't the signature be: public function main(string secret, boolean jsonData = false, boolean xmlData = false, boolean textData = false, int port = 8080) {
} That is, by default we assume you want json/xml/text all 3 and you indicate that by saying nothing. If you want one (or more specifically) you have to say So the test in main() is to see whether all 3 are false and if so take that as user wants all. If any of them is true, then subscribe only to those. Please correct if that logic is flawed! (Note that I removed the keystore parts per the comment I put in the gdoc.) Ref follow up questions:
|
Um I had forgotten that I suggested defaulting to json as the data format! So how about this: public function main(string secret, boolean jsonData = true, boolean xmlData = false, boolean textData = false, int port = 8080) {
} And we just subscribe to all the topics they have selected? So if I want just json I have to do nothing. If I want others xml only I need to turn off json and turn on xml. If that's complicated lets just have all of them be false and force them to pick the formats. Maybe that's even easier! |
FYI I'm changing the design as follows:
|
Closing this issue as we've got new issues for particular items. |
Creating this issue as an overview of the tasks to be completed and to track the points/properties to be decided upon, in relation to $subject.
Publisher + Hub
Publisher
Hub
Subscriber
record
parsed from thejson
payload.The text was updated successfully, but these errors were encountered: