Clearing chat using discord JDA - java

I am coding a discord bot in java, I use discord JDA, and the utilities dependency, I tried using the utilities one but I didn't get it to work, so I tried using just the normal JDA, this is what I did, but I need some way of telling the bot not to send the message in the new channel if the command wasn't ran.
public class NukeCommand extends ListenerAdapter {
#Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event){
if (event.getMessage().getContentRaw().equalsIgnoreCase(".nuke")){
event.getChannel().createCopy().queue();
event.getChannel().delete().queue();
}
}
#Override
public void onTextChannelCreate(TextChannelCreateEvent createEvent){
createEvent.getChannel().sendMessage(":warning:Nuked channel:warning:\nhttps://imgur.com/a/93vq9R8").queue();
}
I am open for answers in both dependencies.
this is the effect I want: https://gyazo.com/e549fd8dda0ded62db19fb84e31d3a61
I have the same effect but it sends the message every time I create a text channel.
I want it to only send the message if the .nuke command was ran.

You said you already got it but I though I'd explain more about how it actually works and refine your answer.
ListenerAdapter's methods are called for every event that happens in the whole scope of the bot, for example if you have
class Adapter extends ListenerAdapter {
#Override
public void onMessageReceived(MessageReceivedEvent event){
/*This will be called for every message, everywhere, including the bot's private channel*/
}
}
So you need to filter those events inside the method's body, what you did on your answer was check if whoever sent the message has permissions to manage messages, which is not the one you actually need to delete channels, it is Permission.MANAGE_CHANNELS, you can find at the roles tab in your server.
Then you call createCopy() which basically creates a shallow copy of the channel's information
I don't think you actually wanted to do that.
Then you queue that action, (This is what actually executes it) it is put in a queue for asynchronous processing by JDA's threads, which will subsequently be sent to discord over the websocket connection.
That queue method can take a Consumer<TextChannel> as a parameter, what does that mean?
Basically a consumer represent an operation that takes a single parameter as input (In this case a TextChannel) and returns nothing. More about it here: https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html
The consumer you give in your answer is doing what you actually want to, sending the message, on the channel that was operated on by the previous queue, meaning that, createCopy() is completely useless, both TextChannel objects are the same, the appropriate would be:
event.getChannel().sendMessage(":warning:Nuked channel:warning:\nhttps://imgur.com/a/93vq9R8").queue();
After that, you delete the channel right away, which does not make that much sense, since most likely no one would even be able to see the nuked message.
For that, JDA provides another method for queueing tasks, this time with a delay:
queueAfter()
It takes a long as the value, and a TimeUnit object to specify what is the time unit of said value, for example:
event.getChannel().delete().queueAfter(10, TimeUnit.SECONDS);
This would queue the task to be executed in 10 seconds, and it does NOT stop the execution of your code, unlike the complete() method.
Alternatively to that, you could just use Thread.sleep() which takes a long value as input: Thread.sleep(10000) for 10 seconds (10000 milliseconds).
You can find a lot more information regarding JDA and start tips and here: https://github.com/DV8FromTheWorld/JDA#creating-the-jda-object

I found a solution you can pass a consumable or whatever its called into the .queue method, this code gets run whenever the channel is created.
what i did:
#Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event){
if (event.getMember().hasPermission(Permission.MESSAGE_MANAGE)){
if (event.getMessage().getContentRaw().equalsIgnoreCase(".nuke")){
event.getChannel().createCopy().queue(channel->channel.sendMessage(":warning:Nuked channel:warning:\nhttps://imgur.com/a/93vq9R8").queue());
event.getChannel().delete().queue();
}
}
}

This seems to work (Without deleting the channel)
#Override
public void onMessageReceived(#NotNull MessageReceivedEvent event) {
String message = event.getMessage().getContentRaw();
if (message.toLowerCase().equals("$" + "clear")) {
for (int i = 0; i <= 1000; i++) {
TextChannel channel = (TextChannel) event.getChannel();
MessageHistory history = new MessageHistory(channel);
List<Message> msgs;
msgs = history.retrievePast(100).complete();
if (msgs.size() > 1) {
channel.deleteMessages(msgs).queue();
} else {
channel.sendMessage("Mensagens deletadas").queue();
return;
}
}
}`

Related

Wait statement that are sequential

I have an issue leading to the requirement of needing to wait sequentially from going from one thing into the next. I presently do this by setting 3 runnables with different delays to allow for a sequential flow of data to appear on my bluetooth connection. However, whilst this does work I feel there must be a better / cleaner implementation of this. My present code is below.
My code works like this:
Write command 1
Wait till command is written
Write command 2
Wait till command is written
Write command 3
Wait till command is written
Please could you give me some suggestions as to how I can perform my write functions one after another in a better manner.
Handler h =new Handler() ;
h.postDelayed(new Runnable() {
public void run() {
Log.d(TAG, "Write 1");
mBluetoothLeService.writeCharacteristic(10);
}
}, 1000);
Handler h1 =new Handler() ;
final int Command_to_run = value;
h1.postDelayed(new Runnable() {
public void run() {
Log.d(TAG, "Write 2");
mBluetoothLeService.writeCharacteristic(Command_to_run);
}
}, 2000);
Handler h2 =new Handler() ;
h2.postDelayed(new Runnable() {
public void run() {
Log.d(TAG, "Write 3");
mBluetoothLeService.writeCharacteristic(20);
}
}, 3000);
Write code
public void writeCharacteristic(int Data) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
byte[] value = intToByteArray(Data);
BluetoothGattService mCustomService =
mBluetoothGatt.getService(UUID.fromString("f3641400-00b0-4240-ba50-
05ca45bf8abc"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the read characteristic from the service*/
BluetoothGattCharacteristic characteristic =
mCustomService.getCharacteristic(UUID.fromString("f3641401-00b0-4240-
ba50-05ca45bf8abc"));
characteristic.setValue(value);
mBluetoothGatt.writeCharacteristic(characteristic);
}
I think mBluetoothLeService.writeCharacteristic(10); calls like these already blocks the thread so using them in order without the need of handlers can be your solution. I don't think that function is asynchronous, so if it returns true, you can write the next one. They are boolean functions so if it returns true you can switch to next one.
I've examined the source code and if it throws an exception inside it, it returns false. Otherwise, it returns if it was successful or not.
Side note: This behavior might differ on different API versions, the source code I've looked into was for API 29. Though, I believe the behavior would be the same, except you might need to wrap the mBluetoothLeService.writeCharacteristic(10); calls to a try-catch block.
I have to edit this since the answer is wrong, the boolean return value is not enough to determine whether the operation was successful. The operation is indeed asynchronous but there is a callback that you can use (this callback) to see if the write operation was successful, and then move on to the next one.
Check this answer for more information, and, if possible, remove the tick from this one please.
Android's BLE API is fully asynchronous and there are no blocking methods. The methods will return true if the operation was initiated successfully and false otherwise. In particular, false will be returned if there already is an operation ongoing.
When you call requestMtu, writeCharacteristic, readCharacteristic and so on, the corresponding callback onMtuChanged, onCharacteristicWrite, onCharacteristicRead will be called when the operation is complete. Note that this usually means a roundtrip to the remote device, which might take different amount of time to complete depending on how noisy the environment is and which connection parameters you have, so there is never a good idea to sleep or delay some fixed amount of time and assume the operation has then completed.
To make the code structure a bit better and avoiding the "callback hell", you could for example implement a (thread-safe) GATT queue which is later used by your application. This way you can just push what you want in the queue and let your GATT queue library handle the dirty stuff. Or you can use some Android BLE library that already does this.
See https://medium.com/#martijn.van.welie/making-android-ble-work-part-3-117d3a8aee23 for a more thorough discussion.
If the work you want to perform sequentially can be done asynchronously, you can consider the new WorkManager included in Android Jetpack. With WorkManager you can organize all your work very smartly, as per the documentation you can do it as follows:
WorkManager.getInstance(myContext)
// Candidates to run in parallel
.beginWith(listOf(filter1, filter2, filter3))
// Dependent work (only runs after all previous work in chain)
.then(compress)
.then(upload)
// Don't forget to enqueue()
.enqueue()
The library takes good care of the order of the execution for you. You can find more information on this matter here: https://developer.android.com/topic/libraries/architecture/workmanager/how-to/chain-work

Websockets onMessage Lock

I am using both python and java implementations of a websocket client. However, since onMessage is asynchronous, it will begin executing immediately, even if there is another function being executed. How can I ensure that each onMessage function will finish completely before the next message is handled. Thanks!
EDIT:
I am subscribing to multiple channels, and regardless of which channel sends a message, my onMessage handler will handle the message. I need my onMessage handler to fully process each message it receives before it begins to process the next message, but I cannot lose any messages. I hope this helps to clarify a bit.
It sounds just a concurrent issue. How about this?
private final Object onMessageLock = new Object();
#OnMessage
public void onMessage(String message, Session session)
{
synchronized (onMessageLock)
{
// Handle the message here.
}
}
I tested the solution proposed by Takahiko. It only works based on one client. The messages from different clients will still be processed parallely.
If you want all messages to be processed after the message before has been processed completely (regardless of the client that sent it) you have to make the Lock object static:
private static final Object onMessageLock = new Object();

Call a method of all parallel Class Threads

I have a question for you.
I have multiple Threads runnings of a class called ServerThread. When an specific event happens on ANY of those threads, I want to call a method of every other thread running in parallel.
public class ServerThread implements Runnable {
private TCPsocket clientSocket;
public ServerThread(Socket comSocket){
clientSocket = new TCPsocket(comSocket);
}
#Override
public void run(){
boolean waiting = true;
Message msg;
try{
while(waiting){
msg = clientSocket.getMessage();
shareMessage(msg);
}
}catch(Exception e){
ErrorLogger.toFile("EndConnection", e.toString());
}
}
public void shareMessage(Message msg){
clientSocket.sendMessage(msg);
}
}
I am talking about this specific line
shareMessage(msg);
which I would like to be called on every thread/instance
-- so that a message is sent to every client (in all tcp connections)
I've tried with synchronized but either I'm not using it well or that is not what I am looking for.
Another thing that might work is keeping a class with an static member which is a list of those tcpconnection objects and then do some loop in all every time.
Thanks for your help and time.
Edited with one possible solution
*Add an static array as a member of the class and add/remove objects of same class (or tcp sockets would also work)
private static ArrayList<ServerThread> handler;
...
handler.add(this);
...
handler.remove(this); //when client exists and thread stops
*Then create a method that iterates for each connection, and make it synchronized so that two threads won't interact at the same time. You may want to implement synchronized on your message sending methods as well.
public void shareMessage(Message msg){
//this.clientSocket.sendMessage(msg);
synchronized (handler){
for(ServerThread connection: handler){
try{
connection.clientSocket.sendMessage(msg);
} catch(Exception e){
connection.clientSocket.closeConnection();
}
}
}
}
First: synchronized is required to prevent race conditions when multiple threads want to call the same method and this method accesses/modifies shared data. So maybe (probably) you will need it somewhere but it does not provide you the functionality you require.
Second: You cannot command an other thread to call a method directly. It is not possible e.g. for ThreadA to call methodX in ThreadB.
I guess you have one thread per client. Probably each thread will block at clientSocket.getMessage() until the client sends a message. I don't know the implementation of TCPsocket but maybe it is possible to interrupt the thread. In this case you may need to catch a InterruptedException and ask some central data structure if the interrupt was caused because of a new shared message and to return the shared message.
Maybe it is also possible for TCPsocket.getMessage() to return, if no message was received for some time, in which case you would again have to ask a central data structure if there is a new shared message.
Maybe it is also possible to store all client connections in such a data structure and loop them every time, as you suggested. But keep in mind that the client might send a message at any time, maybe even at the exact same time when you try to send it the shared message received from another client. This might be no problem but this depends on your application. Also you have to consider that the message will also be shared with the client that sent it to your server in the first place…
Also take a look at java.util.concurrent and its subpackages, it is likely you find something useful there… ;-)
To summarize: There are many possibilities. Which one is the best depends on what you need. Please add some more detail to your question if you need more specific help.

Howto solve this typical Producer Consumer scenario

I encountered an interresting and I think very common synchronization problem in my test code.
This is the test (its a functional test that connects from the outside to the system), i run it via TestNG.
#Test
public void operationalClientConnected_sendGetUserSessionRequest_clientShallReceiveGetUserSessionResponse() {
// GIVEN
OperationalClientSimulator client = operationalClientHasEstablishedWebSocketConnection("ClientXY");
// WHEN
GetUserSessionRequest request = PojoRequestBuilder.newRequest(GetUserSessionRequest.class).build();
client.sendRequest(request);
// THEN
assertThatClientReceivesResponse(client, GetUserSessionResponse.class, request.getCorrelationId(), request.getRequestId());
}
Basically i send a single request and wait for the correct response, this is what i want to verify in this test.
Behind the assertThatClientReceivesResponse there is a hamcrest matcher that looks like this:
#Override
protected boolean matchesSafely(final OperationalClientSimulator client) {
Object awaitedMessage = client.awaitMessage(
new Verification<Object>() {
#Override
public VerificationResult verify(final Object actual) {
VerificationResult result = new VerificationResult();
if (!_expectedResponseClass.isInstance(actual)) {
result.addMismatch("not of expected type", actual, _expectedResponseClass.getSimpleName());
}
// check more details of message ..
return result;
}
}, _expectedTimeout);
boolean matches = awaitedMessage != null;
if (matches) {
_messageCaptor.setActualMessage((T) awaitedMessage);
}
return matches;
}
Now to the interresting part, the synchronization in the OperationalClientSimulator class.
Two methods are of interrest:
awaitMessage which blocks until either a message that matches the given Verification is received or the timeout expired
onMessage received method which is called for each message that is received (over a websocket connection)
Basically what I want to achive is having the test thread block on the awaitMessage method until either the correct message is received (via onMessage) or the specified timeout elapsed.
public Object awaitMessage(final Verification<Object> verification, final long timeoutMillis) {
// howto sync?
return awaitedMessage; // or null
}
#Override
public void onMessage(final String message) {
LOG.info("#Client {} <== received a message on websocket - {}", name, message);
// howto sync?
}
About the test:
The test thread will almost always be faster and therefor has to wait until the response is received via the awaitMessage method
There can be very rare cases when the expected message is received before the test thread is checking for it (this basically means i have to save every received message)
In this specific test case there are only a handfull of messages that are received (some heartbeat messages, the actual response and a notification), but in other cases there can be hundreds of messages which in need to inspect to find the expected message(s)
I was thinking about different solutions for synchronizing here:
The simplest of course would be the sync with the synchronized keyword but I think there are neater ways to do this
The onMessage received method could simply write into a blocking queue and the test thread can consume from it but here I dont know how to measure the timeout.. can I use a CountdownLatch?
Maybe I can do a non blocking solution where the producer (onMessage) writes into an Array and the consumer reads until it reaches an index that is published by the producer (like the LMAX Disruptor)
I know this is test code and performance is not really an issue here, I am just thinking how to solve this in a "nice" way.. you know.. because its christmas :-)
So the actual question here is, how do i "safely" wait for the message which i expect in my test with a timeout? Safely here means that i never miss a message or lose a message because of concurrency issues and that I also need to check if the expected message was already received.
How should I synchronize between the test runner thread and the thread that calls the onMessage method in the OperationalClientSimulator when a message is received on the websocket connection.

JavaFX Block the UI (and the code) until a server call is finished

This topic is around in countless articles of "not blocking the JavaFX UI during a long lasting call into something time consuming (server)". I know that and I googled and tried a lot.
Most of the "Internet" explains that long lasting calls caused by JavaFX events need to be made in an extra thread. After the thread is finished, you update the FX UI with the results via Platform.runLater(). Most of the FX Libraries encapsulate this with sophisticated code constructs (really cool stuff).
My current problem with it is: We are migrating a Swing rich client to JavaFX. It is a huge one, so we have to constantly include/replace JavaFX UI into it, until it is a full FX client.
There is some functionality in the client that does a server call and has to wait before the user can continue with his work.
The server uses JEE6 with stateless session beans and interfaces. The interfaces are known to the client and with a little library of our own, we implemented a little proxy hiding away the communication layer from the client.
The client just creates a "RemoteProxy" with the library then just calling the remote interface and the library propagates the call to the server. The method is called and the result or Exception transported back to the client. For the client this appears like a local call.
Here is the problem. A typical code fragment looks like this:
...
ServerRemoteInterface myServerRemoteProxy = Helper.getProxyForInterface(ServerRemoteInterface.class) ;
...
ComplexResult result = myServerRemoteProxy.doThingsOnServer(SerializableParameter p1 ...)
doSomethingUsefull() ;
The call to the server is triggered in the Swing UI thread (by a listener). It stops the execution of the program (Listener Code) although it is done in an extra thread. "doSomethingUsefull()" is called after the server got back. The developer does not have to take care about threading here.
How is it accomplished? By using the "Spin Library" (http://spin.sourceforge.net/).
It does some clever tricks with the Swing EDT.
An alternative would be to use a modal Dialog, but we decided not not have an extra window, but have a glasspane disabling some UI components instead.
So long explanation and short question...
Is there something similar for JavaFX helping us to seamlessly call a server, stop the program execution until it got back and NOT blocking the JavaFX UI? Best would be if it can work together with Java Swing parts of code.
EDIT... Adding an very compressed example for demonstration of the use with hidden JDialog.
We need the server remote interface. Any interface will do.
public interface ServerRemoteInterface
{
public String method1() ; // String result in our case for test purposes
public String method2() ; // Exceptions would also be possible.
}
Then we need the Proxy Invocation Handler
public class ServerProxy implements InvocationHandler
{
public Object result;
JDialog modalDialog = new JDialog((Frame)null, true);
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
ServerCallHelper serverThread = new ServerCallHelper(args, method) ;
modalDialog.setLocation(4000, 5000); // as if using Spin library. Here we use the dialog to block in a location off the screen.
serverThread.start();
modalDialog.setVisible(true) ;
return result;
}
class ServerCallHelper extends Thread
{
Object[] args;
Method method;
public ServerCallHelper(Object[] args, Method method)
{
this.args = args;
this.method = method;
}
public void run()
{
// do a server call via rmi or tunnel it via http, REST or whatever and provide the call parameters. On the server side there must be a receiver propagating the call to the wanted session bean.
// here we just do a simulation
try
{
Thread.sleep(3000);
} catch (InterruptedException e)
{
// interupt is ok here.
}
// now hand the result from the call back. we simulate a fix result
// We also could have caught the Exception and deal with it.
result = "Simulated Result" ;
// Since we are in the worker thread => inform EDT To close the dialog.
SwingUtilities.invokeLater(()->modalDialog.setVisible(false));
}
}
}
And finally some code to show the functionality
public class SampleUI extends JFrame
{
JButton serverCallButton = new JButton("Call server") ;
JLabel resultLabel = new JLabel("No result so far") ;
public SampleUI()
{
JPanel cont = new JPanel() ;
cont.add(serverCallButton) ;
cont.add(resultLabel) ;
this.setContentPane(cont);
serverCallButton.addActionListener((e)->processServerButtonCall());
}
private void processServerButtonCall()
{
ServerRemoteInterface serverAccess = (ServerRemoteInterface) Proxy.newProxyInstance(SampleUI.class.getClassLoader(), new Class[]{ServerRemoteInterface.class}, new ServerProxy());
String result = serverAccess.method1() ;
resultLabel.setText(result);
}
public static void main(String[] args)
{
SampleUI sampleUI = new SampleUI() ;
sampleUI.pack();
sampleUI.setVisible(true);
}
}
The example is very compressed but should show the principle. As a developer I do not have to take care that the call to the server is really a server call. To me it's like a local call. I do not even have to take care that I am in the EDT Thread, because i just am.
As I said it would work the same way in FX with a modal stage. I tried to set it to opaque 0.0 => It is not drawn anyway. This works.
The question remains: Are there ways to get around the extra JDialog or Stage ?
If I understood your intentions correctly, this is a use case for Future:
CompletableFuture.supplyAsync(() -> myServerRemoteProxy.doThingsOnServer(...))
.thenAccept(result -> doSomethingUseful(result));
Both the server call and doSomethingUseful will be executed in another thread, so you need to use Platform.runLater in doSomethingUseful if you want to access the scene graph.
Like Tomas said the solution is a nested Event Loop.
Currectly Java FX already has such an implementation:
com.sun.javafx.tk.Toolkit.getToolkit()
provides the methods enterNestedEventLoop and exitNestedEventLoop.
From the package name you can tell that it is sun(oracle) specific and should not be used. I read that people already asked Oracle to move it it "Platform" because it is a very useful feature.
Maybe we use it anyway :-)

Categories

Resources