I want to have an ability to send notification to private channels of all users in my group
This is my code
public static void main(String[] args) throws LoginException {
final JDA bot =
new JDABuilder(AccountType.BOT)
.setToken("secret")
.addEventListener(new DemoApplication())
.build();
}
#Override
public void onPrivateMessageReceived(final PrivateMessageReceivedEvent event) {
if (event.getAuthor().isBot()) {
return;
}
event.getJDA().getGuilds().get(0).getMembers().forEach(user->user.getUser().openPrivateChannel().queue());
event.getJDA().getPrivateChannels().forEach(privateChannel -> privateChannel.sendMessage("ZDAROVA").queue());
}
But only sender of this private message receive a message . What did i miss ?
I use JDA with version 3.8.3_462
Your code makes use of async operations. An async task is one that is started on another thread and possibly happens at a later time.
Discord has rate-limits which have to be respected by the operating client. For this reason and the reason that HTTP requests take some time, the requests happen in the background. The method you're using which is called queue() simply puts the request on a queue that is drained by a worker thread.
openPrivateChannel() returns RestAction<PrivateChannel> which means it will receive a private channel instance as a response. This response can be interacted with by using the callback parameter of queue(Consumer<PrivateChannel> callback).
static void sendMessage(User user, String content) {
user.openPrivateChannel().queue(channel -> { // this is a lambda expression
// the channel is the successful response
channel.sendMessage(content).queue();
});
}
guild.getMembers().stream()
.map(Member::getUser)
.forEach(user -> sendMessage(user, "ZDAROVA"));
More information on RestAction is available in the JDA Wiki and Documentation.
Related
This the class that runs verticles :
public class RequestResponseExample {
public static void main(String[] args) throws InterruptedException {
Logger LOG = LoggerFactory.getLogger(RequestResponseExample.class);
final Vertx vertx = Vertx.vertx();
final Handler<AsyncResult<String>> RequestHandler = dar-> vertx.deployVerticle(new ResponseVerticle());
vertx.deployVerticle(new ResponseVerticle(), RequestHandler);
}
}
This is The Request verticle Class :
public class RequestVerticle extends AbstractVerticle{
public static final Logger LOG = LoggerFactory.getLogger(RequestVerticle.class);
static final String ADDRESS = "my.request.address";
#Override
public void start() throws Exception {
Router router = Router.router(vertx);
router.get("/Test").handler(rc -> rc.response().sendFile("index.html"));
vertx.createHttpServer()
.requestHandler(router)
.listen(8080);
}
}
This is The Response verticle Class: Here Im having a difficulty getting The Inserted value in the HTML file
public class ResponseVerticle extends AbstractVerticle{
public static final Logger LOG = LoggerFactory.getLogger(RequestVerticle.class);
#Override
public void start() throws Exception {
Router router = Router.router(vertx);
// How to handle the POST value ?
router.post("/Test/Result").handler(rc -> rc.end("The Post Value"));
vertx.createHttpServer()
.requestHandler(router)
.listen(8080);
}
When the user invokes POST /Test/Result and sends some POST value, you receive it in your Response verticle class (third snippet). If you want to share that method with other verticles, you should store it somewhere inside the handler method so other verticles access it or immediately forward it to other verticle via the event bus.
One possible solution would be to create a third verticle (e.g. StorageVerticle) which has get and set methods. That way, ResponseVerticle invokes the set method to store the value it got, and the RequestVerticle invokes the get method to fetch the value the user sent on calling POST method.
The other solution of direct communication between verticles involves the Event Bus message exchange - one verticle publishes/sends a message and all other verticles can register as a consumer to get that message. More on this you can find here: https://vertx.io/docs/vertx-core/java/#_the_event_bus_api.
It is hard to say which approach is better because it is case-to-case basis and I have limited information here about the scope of the project.
I want to read a message at a specific position in an class other than InboundHandler. I can't find a way to read it expect in the channelRead0 method, which is called from the netty framework.
For example:
context.writeMessage("message");
String msg = context.readMessage;
If this is not possible, how can I map a result, which I get in the channelRead0 method to a specific call I made in another class?
The Netty framework is designed to be asynchronously driven. Using this analogy, it can handle large amount of connections with minimal threading usage. I you are creating an api that uses the netty framework to dispatch calls to a remote location, you should use the same analogy for your calls.
Instead of making your api return the value direct, make it return a Future<?> or a Promise<?>. There are different ways of implementing this system in your application, the simplest way is creating a custom handler that maps the incoming requests to the Promises in a FIFO queue.
An example of this could be the following:
This is heavily based on this answer that I submitted in the past.
We start with out handler that maps the requests to requests in our pipeline:
public class MyLastHandler extends SimpleInboundHandler<String> {
private final SynchronousQueue<Promise<String>> queue;
public MyLastHandler (SynchronousQueue<Promise<String>> queue) {
super();
this.queue = queue;
}
// The following is called messageReceived(ChannelHandlerContext, String) in 5.0.
#Override
public void channelRead0(ChannelHandlerContext ctx, String msg) {
this.queue.remove().setSuccss(msg);
// Or setFailure(Throwable)
}
}
We then need to have a method of sending the commands to a remote server:
Channel channel = ....;
SynchronousQueue<Promise<String>> queue = ....;
public Future<String> sendCommandAsync(String command) {
return sendCommandAsync(command, new DefaultPromise<>());
}
public Future<String> sendCommandAsync(String command, Promise<String> promise) {
synchronized(channel) {
queue.offer(promise);
channel.write(command);
}
channel.flush();
}
After we have done our methods, we need a way to call it:
sendCommandAsync("USER anonymous",
new DefaultPromise<>().addListener(
(Future<String> f) -> {
String response = f.get();
if (response.startWidth("331")) {
// do something
}
// etc
}
)
);
If the called would like to use our a api as a blocking call, he can also do that:
String response = sendCommandAsync("USER anonymous").get();
if (response.startWidth("331")) {
// do something
}
// etc
Notice that Future.get() can throw an InterruptedException if the Thread state is interrupted, unlike a socket read operation, who can only be cancelled by some interaction on the socket. This exception should not be a problem in the FutureListener.
I want to send more than one response to client based on back end process. But in Netty examples I saw echo server is sending back the response at the same time.
My requirement is, I need to validate the client and send him OK response, then send him the DB updates when available.
How can I send more responses to client? Pls direct me to an example or any guide?
at every point in your pipeline you can get the pipeline Channel object from the MessageEvent object (or ChannelEvent) which is passed from handler to handler. you can use this information to send multiple responses at different points in the pipeline.
if we take the echo server example as a base, we can add a handler which send the echo again (that can be done also in the same handler, but the example is to show that multiple handlers can respond).
public class EchoServerHandler extends ChannelHandlerAdapter {
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = e.getChannel();
// first message
ch.write(e.getMessage());
}
// ...
}
public class EchoServerHandler2 extends ChannelHandlerAdapter {
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = e.getChannel();
// send second message
ch.write(e.getMessage());
}
// ...
}
You can do that as long as you have the reference to the relevant Channel (or ChannelHandlerContext). For example, you can do this:
public class MyHandler extends ChannelHandlerAdapter {
...
public void channelRead(ctx, msg) {
MyRequest req = (MyRequest) msg;
ctx.write(new MyFirstResponse(..));
executor.execute(new Runnable() {
public void run() {
// Perform database operation
..
ctx.write(new MySecondResponse(...));
}
}
}
...
}
You can do this as long as Netty doesn't close the Channel. Its better you call close() yourself when you're done.
Here's a sample: https://stackoverflow.com/a/48128514/2557517
I am trying to post messages to some existing actors like show below but there may be a chance to to refer non existing actor and i would like to know before posting the message.
Thanks in advance
actor = getContext().actorFor("actorSystem/user/" + nameOfActor);
actor.tell("message",getSelf());
You can send them Identify message prior to sending your actual message. All actors understand it and should reply with Self(). Alternatively use resolveOne method:
You can acquire an ActorRef for an ActorSelection with the
resolveOne method of the ActorSelection. It returns a Future of the
matching ActorRef if such an actor exists. It is completed with
failure [[akka.actor.ActorNotFound]] if no such actor exists or the
identification didn't complete within the supplied timeout.
The only possible way of knowing that an actor is alive (without DeathWatch) is by receiving a message from it. And that only proves that the actor was alive at some point in time (when it has sent the message).
The following is snippet of my code how i implemented used DeadLettersHandler actor to handle DeadLetters
public class MyActor extends UntypedActor
{
#Override
public void onReceive(Object message) throws Exception
{
System.out.println("MyActor received : "+message.toString());
}
}
public class DeadLettersHandler extends UntypedActor
{
public void onReceive(Object deadLetter) throws Exception
{
System.out.println("DeadLettersHandler received : "+deadLetter.toString());
}
}
public class DeadLetterTest
{
public static void main(String[] args)
{
ActorSystem MyActorSystem = ActorSystem.create("MyActorSystem");
ActorRef existingActor = MyActorSystem.actorOf(Props.create(MyActor.class),"ExistingActor");
ActorRef DLH = MyActorSystem.actorOf(Props.create(DeadLettersHandler.class), "DeadLetterHandler");
MyActorSystem.eventStream().subscribe(DLH, DeadLetter.class);
ActorSelection nonExist = MyActorSystem.actorSelection("akka://user/MyActorSystem/NonExistingActor");
existingActor.tell("Hello Akka", existingActor);
nonExist.tell("Hello Akka", DLH);
MyActorSystem.shutdown();
}
}
output:
MyActor received : Hello Akka
DeadLettersHandler received : DeadLetter(Hello Akka,Actor[akka://MyActorSystem/user/DeadLetterHandler#-3707992],Actor[akka://MyActorSystem/deadLetters])
[INFO] [10/10/2013 15:43:43.343] [MyActorSystem-akka.actor.default-dispatcher-6] [akka://MyActorSystem/deadLetters] Message [java.lang.String] from Actor[akka://MyActorSystem/user/DeadLetterHandler#-3707992] to Actor[akka://MyActorSystem/deadLetters] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
Actually I need to handle the every message received, if a actor not exists then that message has to be handled separately which i achied using Deadletter implementation
final ActorRef actor = actorSystem.actorOf(new Props(DeadLetterHandlerActor.class));
actorSystem.eventStream().subscribe(actor, DeadLetter.class);
I'm mostly there with Netty but one concept is still alluding me, and I can't find anything in the tutorials and so on. Firstly I do understand that Netty is asynchronous, but there must be a way for a client to call the server and be able to get a response beyond the handler. Let me explain more.
I have a client as illustrated below. And please note that I understand it's bootstrapped and a new connection is established on each call, that's just there to make the example smaller and more succinct. Please ignore that fact.
Client.java
// ServerResponse is a result from the server, in this case
// a list of users of the system (ignore that each time it's all bootstrapped).
public User[] callServerForInformationFromGUIWidget()
{
ClientBootstrap bootstrap = new ClientBootstrap(...);
bootstrap.setPipelineFactory(...);
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
Channel channel = future.awaitUninterruptibly().getChannel();
// Where request is a POJO sent to the server,
// with a request such as get me a list of users
RequestPojo request = new RequestPojo(requestUserListCommand);
ChannelFuture lastWriteFuture = channel.write(request);
if(lastWriteFuture != null)
lastWriteFuture.awaitUninterruptibly();
}
Now I understand how to get the data on the server, and fire back the result. The only thing is how do I handle it on the client side? Yes the clientHandler class can do something like the following:
ClientHandler.java
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
{
User[] users = (User[])e.getMessage();
}
The problem is how does the client code actually get that result? All the examples are similar to a chat service, where the event fires off something else on the client that's not waiting on a response. Even the http client example I found lacking this. The documentation overall is really good, but it's lacking on how to do callbacks. Anyways, in this case I need the client to get the response from the server, and based on the results it will do what it needs.
In other words, how do I write the client to do something like this:
IdealClient.java
// ServerResponse is a result from the server, in this case
// a list of users of the system.
public User[] callServerForInformationFromGUIWidget()
{
...
RequestPojo request = new RequestPojo(requestUserListCommand);
ChannelFuture lastWriteFuture = channel.write(request);
if(lastWriteFuture != null)
lastWriteFuture.awaitUninterruptibly();
User[] users = resultFromCallToServer();
performSomeAction(users);
}
Because the handler doesn't know who is looking for the answer, or who asked the question. And if it's done in the handler, than how?
Back to my comments about the examples, the http client (and handler) examples just dump the result to System.out. If you had a GUI how would you pass the result from your request up to the GUI? I never saw any examples for this.
Jestan is correct. In my case I have a client that need to process price tick data. I use Antlr for the parsing. I fire my events in my parser, but in my case my protocol is String based. Below is an example without Antlr, I pass the String message in your case it could be the users.
//----------------- Event --------------
public class DataChangeEvent {
private String message;
public DataChangeEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
//----------------- Listener --------------
public interface DataChangeListenter {
public void dataChangeEvent(DataChangeEvent event);
}
//----------------- Event Handler that fires the dataChange events --------------
// This class needs to be static since you need to register all your classes that want to be notified of data change events
public class DataChangedHandler {
private static List<DataChangeListenter> listeners = new ArrayList<DataChangeListenter>();
public static void registerDataChangeListener(DataChangeListenter listener) {
listeners.add(listener);
}
public static void fireDataChange(DataChangeEvent dataChangeEvent) {
for(DataChangeListenter listenter : listeners) {
listenter.dataChangeEvent(dataChangeEvent);
}
}
}
//----------------- Example class that implements the listener and registers itself for events --------------
public class ProcessMessage implements DataChangeListenter {
public ProcessMessage() {
DataChangedHandler.registerDataChangeListener(this);
}
public void dataChangeEvent(DataChangeEvent event) {
//Depending on your protocal, I use Antlr to parse my message
System.out.println(event.getMessage());
}
}
//---------------- Netty Handler -----------
public class TelnetClientHandler extends SimpleChannelHandler {
private static final Logger logger = Logger.getLogger(TelnetClientHandler.class.getName());
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
String message = (String) e.getMessage();
DataChangedHandler.fireDataChange(message);
}
}
You have to handle it in the Handler with messageReceived(). I'm not sure what your issue is exactly. My guess is you have a response to a request that changes depending on what request was made? Maybe a concrete description of something you are doing of a response that has to know what request it came from. One thing you might be able to do is to pass a long living object the handler that knows the outstanding request, and it can match up the response when it receives it. The pipeline factory method can pass a reference to a manager type object to the Handler.
This was pretty much what I was trying to say. Your Handler is created in the PipelineFactory which is easy to pass parameters to the Handler from there:
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.nulDelimiter()));
pipeline.addLast("decoder", new XMLDecoder() );
pipeline.addLast("encoder", new XMLEncoder() );
// notice here I'm passing two objects to the Handler so it can
// call the UI.
pipeline.addLast("handler", new MyHandler(param1, param2));
return pipeline;
}
});
When you create your pipeline you'll add your Handler upon a new connection. Simply pass one or more objects that allows it to communicate back to the UI or a controller.