I've been playing around with Dbus 2.7 and java for a while and I almost got what I wanted, but eventually got stuck anew.
What I need is a java program that listens to the SYSTEM bus, particularly the org.freedesktop.UDisks interface signals, in order to detect when some devices (most often block devices) are added or removed from the machine( for me that means "plugged the device in and out"). Note that I only need to detect these signals, not the information that travels along with them.
The dbus signals in which I'm concretely interested are DeviceAdded and DeviceRemoved:
[dbus-monitor output]
signal sender=:1.45 -> dest=(null destination) serial=186 path=/org/freedesktop/UDisks; interface=org.freedesktop.UDisks; member=DeviceAdded
object path "/org/freedesktop/UDisks/devices/sdb"
signal sender=:1.45 -> dest=(null destination) serial=230 path=/org/freedesktop/UDisks; interface=org.freedesktop.UDisks; member=DeviceRemoved
object path "/org/freedesktop/UDisks/devices/sdb"
To accomplish this task in Java I created the following classes [1] and [2]:
[1] org.freedesktop.UDisks.java
/** Created with 'createinterface' utility on org.freedesktop.UDisks system bus interface**/
package org.freedesktop;
import java.util.List;
import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusSignal;
import org.freedesktop.dbus.UInt32;
import org.freedesktop.dbus.UInt64;
import org.freedesktop.dbus.exceptions.DBusException;
public interface UDisks extends DBusInterface
{
/** ... **/
public static class DeviceRemoved extends DBusSignal
{
public final DBusInterface a;
public DeviceRemoved(String path, DBusInterface a) throws DBusException
{
super(path, a);
this.a = a;
}
}
public static class DeviceAdded extends DBusSignal
{
public final DBusInterface a;
public DeviceAdded(String path, DBusInterface a) throws DBusException
{
super(path, a);
this.a = a;
}
}
public void Uninhibit(String cookie);
public String Inhibit();
public DBusInterface LinuxMdCreate(List<DBusInterface> components, String level, UInt64 stripe_size, String name, List<String> options);
...
/** ... Remaining code removed for the sake of post length**/
}
[2] org.freedesktop.ListenHWDBusSignal.java
package org.freedesktop;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.DBusSigHandler;
import org.freedesktop.dbus.exceptions.DBusException;
public class ListenHWDBusSignal {
public static void main(String[] args) throws DBusException, ParseException {
System.out.println("Creating Connection");
DBusConnection conn=DBusConnection.getConnection(DBusConnection.SYSTEM);
conn.addSigHandler(UDisks.DeviceAdded.class,new DBusSigHandler<UDisks.DeviceAdded>() {
#Override
public void handle(
UDisks.DeviceAdded added) {
System.out.println("Device added!");
}
});
conn.addSigHandler(UDisks.DeviceRemoved.class,new DBusSigHandler<UDisks.DeviceRemoved>() {
#Override
public void handle(
UDisks.DeviceRemoved removed) {
System.out.println("Device removed!");
}
});
System.out.println("Waiting for signals...");
}
}
All right, I execute [2], all goes fine and the program waits for signals:
Creating Connection
Waiting for signals...
When I manually add a usb device, I get this line:
Device added!
but when I remove manually the usb, and I mean not safely-removing it, just plugging it out, I get nothing.
I also checked the bus signals with dbus-monitor and see the DeviceRemoved signal is actually sent by org.freedesktop.UDisks to the system bus, so I think there's a problem on the java side that I am not seeing. Why I do not get the line "Device removed!"? Is there something wrong in the code?
Any help would be really appreciated, thanks!
Related
I am currently creating a bot for Discord. So far, I have got the bot up, and have it "Online" in my server. I created a custom command named !yata that displays a motivational message after being input. Is there a reason as to why my bot will not pick up commands? When I type in !yata it does not run the command.
Buki.java
package Buki;
import javax.security.auth.login.LoginException;
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
public class Buki {
public static JDA jda;
public static String prefix = "!";
//Main method
public static void main(String[] args) throws LoginException {
JDA jda = JDABuilder.createDefault("bot token").build();
jda.addEventListener(new Commands());
}
}
Commands.java
package Buki;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
public class Commands extends ListenerAdapter {
public void onGuildMessageReceived(MessageReceivedEvent e) {
String[] message = e.getMessage().getContentRaw().split(" ");
if (message[0].equalsIgnoreCase("!yata")) {
e.getChannel().sendTyping().queue();
e.getChannel().sendMessage("The road of a ninja is long!").queue();
}
else {
}
}
}
First of all, your codes are so weird!
How could the event be called MessageReceivedEvent, meanwhile, the method called onGuildMessageReceivedEvent, JDA already renamed the methods! and second you didn't use the GatewayIntent.GUILD_MESSAGES, so basically, it going to be like this:
JDABuilder jda = JDABuilder.create(token, GatewayIntent.GUILD_MESSAGES);
and third, think is I see you using JDA, not JDABuilder which is wrong, I recommended you to check what version of JDA you use and use the last one!
public void onGuildMessageReceived(MessageReceivedEvent e)
needed to be changed to
public void onMessageReceivedEvent(MessageReceivedEvent e).
"Guild" was not required in this method's name.
I'm trying to make my bot welcome someone whenever someone joins but I can't seem to get it to work. For example(this will appear in an embed by the way):
#Jason joined. You must construct additional pylons.
Can someone help me edit my code so it works please?
Here's my Main code:
import Events.*;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Activity;
import javax.security.auth.login.LoginException;
public class Main {
public static void main(String[] args) throws LoginException {
JDABuilder jda = JDABuilder.createDefault("I imported key here");
jda.setActivity(Activity.watching("baldness"));
jda.addEventListeners(new Help());
jda.addEventListeners(new PingPong());
jda.addEventListeners(new Clear());
jda.addEventListeners(new Welcome());
jda.build();
}
}
and Here's my Welcome code:
package Events;
import java.util.Random;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
public class Welcome extends ListenerAdapter {
public class GuildMemberJoin extends ListenerAdapter {
String[] messages = {
"[member] joined. You must construct additional pylons.",
"Never gonna give [member] up. Never let [member] down!",
"Hey! Listen! [member] has joined!",
"Ha! [member] has joined! You activated my trap card!",
"We've been expecting you, [member].",
"It's dangerous to go alone, take [member]!",
"Swoooosh. [member] just landed.",
"Brace yourselves. [member] just joined the server.",
"A wild [member] appeared."
};
public void onGuildMemberJoin(GuildMemberJoinEvent event) {
Random rand = new Random();
int number = rand.nextInt(messages.length);
EmbedBuilder join = new EmbedBuilder();
join.setColor(0x66d8ff);
join.setDescription(messages[number].replace("[member]", event.getMember().getAsMention()));
event.getGuild().getDefaultChannel().sendMessage(join.build()).queue();
}
}
}
The documentation fo GuildMemberJoinEvent clearly states:
Requirements
This event requires the GUILD_MEMBERS intent to be enabled.
createDefault(String) and createLight(String) disable this by default!
So you must enable the intent. Read more in the wiki guide Gateway Intents and Member Cache Policy
Additionally, you have a nested class for no reason which means you register the enclosing class as a listener but not the nested class that actually implements it.
Better:
public class Welcome extends ListenerAdapter {
#Override
public void onGuildMemberJoin(GuildMemberJoinEvent event) {
...
}
}
I'm currently working on a plugin for Bukkit (Paper Spigot) that acts as a queue. This plugin in running in a queue server that then will take players over to the proper server when the proper server has less that a set number of players. I need to obtain the playercount from the proper server and use it in code from my queue plugin. I found examples on how to do this using Bukkit's messaging channel but that requires players (I think) and I don't completely understand it even though I've read many other articles and stackoverflow posts as most of these people have had slightly different problems. I've also heard other people talk about sockets but I'm not sure how they work. I am fine with running a second plugin in either the proper server or the Bungeecord server. I just need to know what code to write and where to write it! or at least a helpful example of a working system.
Here's my code so far:
package com.Package;
import org.bukkit.Bukkit;
//import org.bukkit.command.Command;
//import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.messaging.PluginMessageListener;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.util.ArrayList;
import java.util.logging.Logger;
public class AnarchyQueue extends JavaPlugin implements PluginMessageListener {
ArrayList<Player> players = new ArrayList<Player>();
Boolean isListening = false;
int playerNumber = 0;
#Override
public void onEnable() {
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", this);
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
getCount();
log(Integer.toString(playerNumber));
}
}, 200L, 200L);
}
#Override
public void onDisable() {
}
private void log(String str)
{
Logger.getLogger("Minecraft").info(str);
}
public void onPlayerJoin(PlayerJoinEvent event)
{
players.add(event.getPlayer());
}
/*public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (command.getName().equalsIgnoreCase("players")) {
if (!(sender instanceof Player)) {
sender.sendMessage("You must be in game!");
return true;
}
else {
getCount();
}
}
return true;
}*/
private void getCount() {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerCount");
out.writeUTF("anarchy");
Player player = Bukkit.getPlayerExact("Ed_Silver");
player.sendPluginMessage(this, "BungeeCord", out.toByteArray());
isListening=true;
}
#Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (channel.equals("BungeeCord")) {
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subchannel = in.readUTF();
if (subchannel.equals("PlayerCount") && isListening) {
int playerCount = in.readInt();
playerNumber = playerCount;
isListening=false;
}
}
}
}
I know this code is broken in many ways, I am not really looking to fix it - I just want a way to do what I'm doing and I'll work the rest out later. (giving code as people tend to get shirty if they think you haven't tried :) !)
Feel free to ask for more detail etc...
Thanks in advance,
Edward
--EDIT--
I have found Jedis and have been experimenting. If someone could explain Jedis to me that would be great.
This is what I've found so far:
public static void main(String[] args) {// priOnEnable() {
//Connecting to Redis server on localhost
Jedis jedis = new Jedis("localhost");
System.out.println("Connection to server sucessfully");
//check whether server is running or not
System.out.println("Server is running: "+jedis.ping());
}
This gets an error however. I believe that I need to be running something else to manage Redis or something.
Thanks Again,
Edward
What I've done:
Installed Redis (https://github.com/MicrosoftArchive/redis/releases)
Used guides such as https://www.tutorialspoint.com/redis/redis_java.htm to work out code.
Good luck to all those out there attempting this!
Have fun and I hope you work it out!
I've tried to modify minecraft by adding a new item called "uranium". Therefore I created the class "Trauma.java" in the main package and a few other classes listed below.
All packages and classes:
Package Explorer
Trauma.java
package main;
import items.ItemUranium;
import net.minecraft.item.Item;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import proxy.ServerProxy;
#Mod(modid = Trauma.MODID)
public class Trauma {
public static final String MODID = "Trauma";
#SidedProxy(clientSide = "proxy.ClientProxy", serverSide = "proxy.ServerProxy")
public static ServerProxy proxy;
public static ItemUranium uranium = new ItemUranium();
#EventHandler
public void preInit(FMLPreInitializationEvent event) {
GameRegistry.register(uranium);
}
#EventHandler
public void init(FMLInitializationEvent event) {
proxy.registerClientStuff();
}
#EventHandler
public void postInit(FMLPostInitializationEvent event) {
}
}
BasicItem.java
package items;
import net.minecraft.item.Item;
public class BasicItem extends Item {
public BasicItem(String name) {
setUnlocalizedName(name);
setRegistryName(name);
}
}
ItemUranium.java
package items;
public class ItemUranium extends BasicItem {
public ItemUranium() {
super("uranium");
}
}
ClientProxy.java
package proxy;
import items.BasicItem;
import main.Trauma;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
public class ClientProxy extends ServerProxy {
#Override
public void registerClientStuff () {
registerItemModel(Trauma.uranium);
}
public static void registerItemModel(BasicItem item) {
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation(Trauma.MODID + ":" + item.getRegistryName(), "inventory"));
}
}
ServerProxy.java
package proxy;
public class ServerProxy {
public void registerClientStuff() {}
}
uranium.json
{
"parent": "item/generated",
"textures": {
"layer0": "Trauma:items/uranium"
}
}
uranium.png
ingame
Also I don't know why the item in inventory isn't called uranium...
I spent two hours on fixing the problem and it didn't help so it would be really nice if somebody of you may help me.
Thanks :)
Don't use the Model Mesher:
The model mesher is Vanilla (Mojang) code and using it correctly has always been finicky and unreliable, failing if you called it too early and failing if you called it too late. So Forge added the ModelLoader class to resolve that problem.
Replace this line:
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(...)
With this line:
ModelLoader.setCustomModelResourceLocation(...)
The ... contents are identical.
Second, depending on what version of Minecraft you're using, you should...:
Stop using GameRegistry.Register
Instead use the RegistryEvent.Register<T> events (where <T> will be <Block> to register blocks, <Item> to register items, etc)
Register your models in the ModelRegistryEvent and no where else.
This event is #SideOnly(CLIENT) and can be subscribed to in your client proxy, avoiding the need to forward references through your proxy class. Eg. I do it like this, where lines 197-199 is the most common scenario needed, where the array is populated during the item registration event. The rest of that method handles the custom state mappers and custom mesh definitions that are used by only a handful of items/blocks and not relevant here.
Include your Mod ID in your unlocalized name. The best way to do this would be setUnlocalizedName(getRegistryName().toString());
See also the Forge documentation on events.
I am using JNA to call functions of a dll file.
One of the functions requires a pointer to a callback function
// Dll function
void MyFunction (*CallBackFnName);
Below is the JNA proxy interface in java
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
public interface Dll extends Library {
interface CallBackFnName extends Callback {
void callback(Pointer dataBuffer, int dataLen);
}
public void MyFunction(Dll.CallBackFnName fn);
public int StartReading(short arg1, short arg2);
}
According to the API of the dll, after passing the pointer to a callback function to the function MyFunction(*CallBackFnName), whenever you call StartReading() function it will send data to the callback function.
When I am trying to do that, It is not calling my callback function. It is not throwing any exception also.
Below is the code from which I am calling functions:
import com.sun.jna.Native;
import com.sun.jna.Pointer;
public class Start {
private static Dll dll = (Dll) Native.loadLibrary("MyDll", Dll.class);
private static Dll.CallBackFnName fn = new Dll.CallBackFnName() {
#Override
public void callback(Pointer dataBuffer, int dataLen) {
System.err.println("Callback function is called successfully");
}
};
public static void main(String[] args) throws InterruptedException {
dll.MyFunction(fn); //passed the pointer to the callback function
short arg1 = 0;
short arg2 = 0;
dll.StartReading(arg1, arg2));
Thread.sleep(10 * 1000);
}
}
After running the above code, I am getting the following on the console:
DeviceAttach: received and accepted attach for vendor id 0x3eb, product id 0x2ffd, interface 0, device handle 0x037825E8
Main Menu (active Dev/Prod/Interface/Alt. Setting: 0x3eb/0x2ffd/0/0)
Read FailReadWritePipesMenu: WDU_Transfer(control receive) failed: error 0x2000000e ("
Read Fail")
Read FailReadWritePipesMenu: WDU_Transfer(control receive) failed: error 0x2000000e ("
Read Fail")
Read FailReadWritePipesMenu: WDU_Transfer(control receive) failed: error 0x2000000e ("
Read Fail")
Transferred 0 bytes
0 0
Don't know if you still need the answer , but to anyone else who has this problem,
I had this problem before.I had to create an anonymous class as such (using the above example),
dll.myfunc(new Dll.CallBackFnName() {
#Override
public void callback(Pointer dataBuffer, int dataLen) {
System.err.println("Callback function is called successfully");
} } );
This worked for me . although i can't explain why.