I'm trying to write an ircBot in Java for some practice. I am using this sample code as the base. I'm trying to figure out how to get it to read in text from my console so I can actually talk to people with the bot.
There's the one while loop that takes in the input from the ircserver and spits it out to console and responds to PINGs. I'm assuming I have to have another thread that takes the input from the user and then uses the same BufferedWriter to spit it out to the ircserver again but I can't get that figured out.
Any help would be awesome!
In the code you have linked to, the 'reader' and 'writer' instances, are indeed connected to respectively the ingoing and outgoing ends of the two-way socket you have established with the IRC server.
So in order to get input from the User, you do indeed new another thread which takes commands from the user in some fashion and acts upon these. The most basic model, would naturally be to use System.in for this, preferably wrapping it so that you can retrieve whole line inputs from the User, and parse these as a command.
To read whole lines from System.in you could do something like this:
BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = bin.readLine()) != null) {
// Do stuff
}
You could also consider using one of the CLI libraries that is out there for Java, like JLine
If you really want to do yourself a favour, I recommend (after having used it extensively) switching to pircbot. Pircbot really is a wonderful library and will let you get an IRC bot up and running in just a few minutes. Check out some of the examples on the site, it's super easy to use.
Related
I wrote multithreaded java server-client sockets app with messaging functionality but I encountered a problem with simultaneous console IO.Main server console is listening for keyboard input and simultaneously printing out messages from the clients. On client side there is a separate thread for printout.
Here is simplified code representation:
public class ServerThread{
....
BufferedReader in = ... (sock.getInputStream);
while(true){
System.out.println(in.readline());
....
public class ServerMain{
.....
BufferedReader keyb = ... (System.in);
while(true){
in = keyb.readLine();
....
The problem occurs while I'm typing something in the main server console and at the same time a message arrives from one of the clients.
That message is then concated to what I was typing on screen and cursor moves to the beginning of the next line waiting for input.
What was typed in previously is stuck in the keyboard buffer, and I cant edit it anymore. Same problem happens on client side.
The question is how can I print messages on screen without disrupting ongoing input?
(inputted text also needs to stay printed on screen as in readLine() default behavior)
I already tried some of the solutions suggested for other similar problems:
In Lanterna and JCurses libraries there's no support for native System.IO streams. I would have to reinvent the wheel and implement it all by myself manually from memory to screen, one char at a time plus build whole console GUI layer.
The other thing was using ANSI codes but I couldn't figure out how to do what I need with them. I could read one input char at a time instead of a whole line, then if message arrives clear the line, move cursor to the beginning and printout, but afterwards in nextline I don't know how to print previously buffered text and still be able to delete chars with backspace.
edit:
GUI is not an option as I want my code to be able to run on a headless server.(also assume that there will be only one terminal, console, shell, and app running per side)
A distinct non-answer, based on: there is only one console.
And that console is an artefact from times when multiple threads weren't a real problem. "Works nicely with multiple threads" was never a requirement for that low level console.
Thus: if you really want a sophisticated solution (that isn't a hack of some sort) simply consider: not using the stdin/stdout console(s).
Instead: write a simple Swing GUI application. Have one text entry field where input is collected, and one or maybe multiple text fields where your output goes. If you want to be fancy, make it a webapp. I am sure that using some framework, you could put together a working thing within a few hours. You will learn more valuable skills by doing that, instead of spending these hours "working around" the fact that you picked the wrong technology for your problem.
Update, given the comment by the OP: then the best I can think of: don't write to the console. Write to different files. Open multiple terminals, and use tools like "tail" to show you what is happening with your output file(s).
Ok, I found the ideal solution myself:
JLine library works in conjunction with default System.IO, also there is no need to create new Terminal objects (you can) or anything else. Simply instead of BufferedReader you use LineReader
String readLine(String prompt, Character mask, String buffer)
prompt (can be null) is the unexpanded prompt pattern that will be displayed to the user on the left of the input line
mask (can also be null) is the character used to hide user input (when reading a password for example)
buffer is the initial content of the input line
Edit: In JLine's docs i found an even better solution:
printAbove
void printAbove(AttributedString str)
Prints a string before the prompt and redraw everything. If the LineReader is not actually reading a line, the string will simply be
printed to the terminal.
Parameters:
str - the string to print*
I have a Java GUI and a C program. C program calculates given value(args). I want to call C calculator in Java, and change label to returned value in GUI (label changes almost every second).
I thought some ways,
Socket programming (probably not efficient in same computer)
File operations (Java writes input, c calculates then java reads calculated value)
JNICALL stuff, but i dont know how to get value from c file.
SharedMemory (i have no idea about windows shm)
What is the best way to solve this problem?
You could take a look at JNA, if your C program is a DLL with export functions.
Remember from a past project it works very nicely, without having to do the JNI bits yourself.
I had to do something similar at my job, I wrote a helper program in C++ to access some custom made database and my main application was in Java. The database API was only available to C++ programs.
What I did was to start the C++ process from Java and communicate via command line args and stdout.
List<String> cmdPathAndArgs = Arrays.asList("/path/to/binary", "--arg1", "--arg2");
ProcessBuilder pb = new ProcessBuilder(cmdPathAndArgs);
Processpp = pb.start();
InputStream stream = pp.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
InputStream errorStream = pp.getErrorStream();
BufferedReader errorBr = new BufferedReader(new InputStreamReader(errorStream));
If your progran generates output in both stdout and stderr you may get into a deadlock. You should empty both streams regularly.
If you can build your C code into a shared library, then JNI is probably your best bet. Sockets will be more than fast enough to handle 1 update a second. Using files will probably be slower than sockets. Shared memory is fine too, however I think sockets is probably a simpler interface for what you want to do.
My Java application has to work like this:
User select bash commands in GUI and press "send."
Application return distinct and independent answers for each command
(e.g. we could store them in different files).
Commands each run interactively, not in a batch (it can't be
something like "ls\n pwd \n" etc)
After each command, the application will wait and check if the
results are ok. If so, it will send the next command.
We need to execute su on the remote host.
I've used ExpectJ (with a little hack of output stream). It has resolved points 1,3,4,5.
But there is a problem with point 2. In my app I need to get separated answer. But we will not know their length. Command prompts can be different. Anyone knows how to "hack" ExpectJ so it will be some how more synchronized? I am looking for acting like this : send , wait for full answer, send, wait... I've tried some basic synchronization tricks but this end in timeouts and connection lost usually.
This question is related to my older one :
Java library to run multiple unrelated commands on a remote server via ssh
the problem basically is that expectj sends and listens at the same time, buffering inputs and outputs in separate threads, so you have to know when the response has ended so you can delimit each request/response block. If you don't care about expect "interact" mode, you can try to hack expect4J, expect-for-java (https://github.com/ronniedong/Expect-for-Java) or even apache mina sshd.
I am facing exactly the same problem right now, and since I need interact(), I don't have any other option right now. So, this solution below is not elegant, but may do the job. Too bad we don't have a decent expect java implementation. I hope we will in java 8, when (I hope) we'll have closure.
ExpectJ ex = new ExpectJ(50);
Spawn spawn = ex.spawn(new SshSpawn("192.168.56.101", 22, "alice", "password"));
String command = "hostname -s;expr 123456788 + 1";
spawn.send(command+"\n");
spawn.expect("123456789");
String lsResults = spawn.getCurrentStandardOutContents().split("123456788 \\+ 1\r\n")[2].split("123456789")[0];
String[] lsRows = lsResults.split("\r\n");
for(int i=0;i<lsRows.length;i++){
System.out.println(i+":"+lsRows[i]);
}
I'm kinda interested in with java sockets in these days and i want to read my mails from gmail with using java socket. is it possible?
Socket s;
s = new Socket("imap.gmail.com", 993);
InputStream in;
in = s.getInputStream();
BufferedReader sin = new BufferedReader(new InputStreamReader(in));
PrintWriter output = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
output.println("a001 LOGIN my-e-mail my-pass");
output.flush();
while ((line = sin.readLine()) != null)
System.out.println(line);
s.close();
what should i do after connecting to socket?
thanks in advance. (notice: i dont want to use java mail api, things get really easy with it, i'm just choosing this way to get familiar what's going on behind the scene)
edited the code.
If you feel like getting familiar with IMAP at GMail, you're going to have to put SSL/TLS on top of it. All GMail traffic is encrypted.
Once you have a socket you implement the IMAP protocol on it.
https://www.rfc-editor.org/rfc/rfc3501
+1 for the question.
EDIT: Yes, it is possible to speak to IMAP server using java sockets and in some cases it might be advisable to do so rather than using java mail library.
Using javamail is the easy way out. It is also appears to be the obvious solution but, there are cases when you do not want to go that route.
Javamail is highly unsuiatble for scaled out deployments with a large number of concurrent users that need to be kept notified on near real time basis.
Say, you want to service more than 1000 users per jvm and want to keep the overhead of creating imap connections low then, you will resort to implementing sockets yourself and write IMAP commands in the socket itself. Needless to say, other benefits include near instantaneous delivery of a new email to your user i.e if you are using AJAX.
Near instantaneous email is one of the few things left to like about Blackberry. Given RIMs scale, I don't think they would be using Javamail on top of IMAP to push out emails. That would be highly non-performant.
I want to execute this command:
/ceplinux_work3/myName/opt/myCompany/ourProduct/bin/EXECUTE_THIS -p cepamd64linux.myCompany.com:19021/ws1/project_name < /ceplinux_work3/myName/stressting/Publisher/uploadable/00000.bin >> /ceplinux_work3/myName/stressting/Publisher/stats/ws1.project_name.19021/2011-07-22T12-45-20_PID-2237/out.up
But it doesn't work because EXECUTE_THIS requires an input file via redirect, and simply passing this command to Runtime.exec doesn't work.
Side note: I searched all over on how to solve this before coming here to ask. There are many questions/articles on the web regarding Runtime.exec and Input/Output redirect. However, I cannot find any that deal with passing a file to a command and outputting the result to another file. Plus, I am totally unfamiliar with Input/Output streams, so I have a hard time putting all the info out there together for my specific situation.
That said, any help is much appreciated.
P.S. If there are multiple ways to do this, I prefer whatever is fastest in terms of throughput.
Edit: As discussed in my last question, I CANNOT change this to a bash call because the program must wait for this process to finish before proceeding.
Unless you are sending a file name to the standard input of the process, there is no distinction of whether the data came from a file or from any other data source.
You need to write to the OutputStream given by Process.getOutputStream(). The data you write to it you can read in from a file using a FileInputStream.
Putting that together might look something like this:
Process proc = Runtime.getRuntime().exec("...");
OutputStream standardInputOfChildProcess = proc.getOutputStream();
InputStream dataFromFile = new FileInputStream("theFileWithTheData.dat");
byte[] buff = new byte[1024];
for ( int count = -1; (count = dataFromFile.read(buff)) != -1; ) {
standardInputOfChildProcess.write(buff, 0, count);
}
I've left out a lot of details, this is just to get the gist of it. You'll want to safely close things, might want to consider buffering and you need to worry about the pitfalls of Runtime.exec().
Edit
Writing the output to a file is similar. Obtain a FileOutputStream pointing to the output file and write the data you read from Process.getInputStream() to that OutputStream. The major caveat here is that you must do this operation in a second thread, since accessing two blocking streams from the same thread will lead to deadlock (see the article above).