Final version source code

This commit is contained in:
saad 2023-10-02 22:26:20 -07:00
parent 8a8a5c6831
commit 371de2fd83
16 changed files with 922 additions and 0 deletions

View File

@ -1,2 +1,3 @@
# MessagingApp # MessagingApp
A simple messaging app with a nodejs server and Swing front end

BIN
engine.io-client-2.0.0.jar Normal file

Binary file not shown.

BIN
json-20090211.jar Normal file

Binary file not shown.

BIN
messagingapp.jar Normal file

Binary file not shown.

BIN
okhttp-3.12.12.jar Normal file

Binary file not shown.

BIN
okio-1.15.0.jar Normal file

Binary file not shown.

179
server.js Normal file
View File

@ -0,0 +1,179 @@
// Express is used for HTTP and URL routing
const express = require('express');
const path = require('path');
const PORT = process.env.PORT || 5000;
// Library to generate unique identifiers
const { v4: uuidv4 } = require('uuid');
const uuid = require('uuid');
// We need the crypto library for sha512 encryption of passwords in the database
var crypto = require("crypto");
// psql driver
const { Pool } = require('pg');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server, {
cors: {
origin: "*"
}
});
/*
Connects to database on deployed app.
*/
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false
}
});
app.use(express.json())
app.use(express.urlencoded({
extended: true
}))
users = {}
io.on("connection", (socket) => {
socket.emit("hello", {"hello": "world"});
socket.on('disconnect', () => {
console.log('user disconnected');
delete users[socket.id];
socket.broadcast.emit('users', getUsers());
});
socket.on("hello", (arg) => {
console.log("hello" + arg); // world
});
socket.on("message", (arg) => {
socket.broadcast.emit('message', arg);
saveMessage(users[socket.id], arg);
});
socket.on("privateMessage", (msg, to) => {
var socketID = [];
for (user in users){
console.log(user);
if (users[user].toString() == to.toString()){
}
}
console.log("Private message to " + to + " " + socketID[0]);
io.to(socketID[0]).emit('privateMessage', users[socket.id], msg);
saveMessage(users[socket.id], users[socketID[0]], msg);
});
socket.on("login", (data) => {
data = data.split(",");
var username = data[0];
var pw = data[1];
pool.query(`SELECT username,password FROM accounts where username='${username}'`, (err, result) => {
if (err){
error('A critical database error occured while user was attempting to login');
socket.emit('logInError', 'A critical database error occured while user was attempting to login');
}
else if (result.rowCount == 0){
socket.emit('logInError', `Invalid credentials`);
}
else if (result.rows[0].username == username && result.rows[0].password == sha512(pw)){
var uhash = sha512(username);
socket.emit('users', getUsers());
users[socket.id] = username;
socket.broadcast.emit('users', getUsers());
socket.emit('loggedIn', `${username}`);
getMessages();
log('User logged in');
}
else {
socket.emit('logInError', `Invalid credentials`);
}
});
});
socket.on("register", (data) => {
data = data.split(",");
var id = uuidv4();
var username = data[0];
var pw = data[1];
pool.query(`SELECT * FROM accounts where username='${username}'`, (err, result) => {
if (err) {
error(err);
error('A critical database error occured while user was attempting to create an account');
socket.emit('registerError', 'A critical database error occured while user was attempting to create an account');
}
else {
if (result.rowCount == 0){
var pwhash = sha512(pw);
var uhash = sha512(username);
pool.query(`insert into accounts values('${id}', '${username}', '${pwhash}')`, (err, result) => {
console.log(err);
console.log(result);
if (err){
socket.emit('registerError', 'A critical database error occured while user was attempting to create an account');
}
else {
socket.username = username;
socket.emit('registered', `${username}`);
log(`${username} registered with ${id}`);
}
});
}
else {
socket.emit('registerError', `Username already exists`);
}
}
})
});
function getMessages(){
pool.query(`SELECT MESSAGE FROM message where TO_USER='all'`, (err, result) => {
//console.log(result.rows);
console.log("GETTING MESSAGES");
socket.emit('messages', result.rows);
});
}
});
/**
* hash password with sha512.
* @function
* @param {string} password - List of required fields.
* @param {string} salt - Data to be validated.
*/
var sha512 = function(password, salt = "messaging"){
var hash = crypto.createHmac('sha512', salt); /** Hashing algorithm sha512 */
hash.update(password);
var value = hash.digest('hex');
return value;
};
server.listen(PORT, function(){ log("Listening on port " + PORT); })
function getUsers(){
u = [];
for (user in users){
u.push(users[user]);
}
return u;
}
function saveMessage(from, msg){
pool.query(`insert into message values('${from}', 'all', '${msg}')`, (err, result) => {});
}
function savePrivateMessage(from, to, msg){
pool.query(`insert into message values('${from}', '${to}', '${msg}')`, (err, result) => {});
}
function log(input){
console.log(input);
}
function error(input){
console.error(input);
}

BIN
socket.io-client-2.0.0.jar Normal file

Binary file not shown.

40
src/App.java Normal file
View File

@ -0,0 +1,40 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import io.socket.engineio.client.Transport;
import io.socket.engineio.client.transports.Polling;
import io.socket.engineio.client.transports.WebSocket;
import javafx.application.Application;
import javafx.stage.Stage;
import okhttp3.OkHttpClient;
public class App extends Application {
static Client socket;
static String username;
static ArrayList<String> activeUsers = new ArrayList<String>();
static ArrayList<String> messages = new ArrayList<String>();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) throws Exception {
socket = new Client(primaryStage);
primaryStage.setTitle("Messaging app");
primaryStage.setResizable(false);
primaryStage.setScene(LoginPage.makeLoginPage(primaryStage, socket));
primaryStage.show();
}
@Override
public void stop(){
System.out.println("disconnecting");
socket.disconnect();
}
}

236
src/Client.java Normal file
View File

@ -0,0 +1,236 @@
import java.net.URI;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Client {
Socket socket;
Stage primaryStage;
Client client;
public Client(Stage primaryStage) {
this.client = this;
this.primaryStage = primaryStage;
socket = IO.socket(URI.create("http://messagingappsoftwareeng.herokuapp.com"));
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Connected to server!");
socket.emit("hello", " world");
}
});
socket.on("hello", new Emitter.Listener() {
@Override
public void call(Object... args) {
JSONObject response = (JSONObject) args[0];
try {
System.out.println("Hello " + response.getString("hello"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
socket.on("users", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println(args[0]);
Platform.runLater(new Runnable() {
@Override
public void run() {
App.activeUsers.clear();
JSONArray jsonArray = (JSONArray) args[0];
String[] users = toStringArray(jsonArray);
if (users != null && users.length > 0)
{
for (int i = 0; i < users.length; i++) {
if (users[i].equals(App.username)) {
continue;
}
else {
App.activeUsers.add(users[i]);
}
}
MainLobby.updateUsers();
}
}
});
}
});
socket.on("message", new Emitter.Listener() {
@Override
public void call(Object... args) {
App.messages.add((String) args[0]);
MainLobby.updateMessages((String) args[0]);
}
});
socket.on("privateMessage", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println((String)args[0]);
System.out.println((String)args[1]);
Platform.runLater(new Runnable() {
@Override
public void run() {
String username = (String) args[0];
if (MainLobby.privateMessageWindows.get(username) != null && MainLobby.privateMessageWindows.containsKey(username)) {
MainLobby.privateMessageWindows.get(username).show();
MainLobby.privateMessageWindows.get(username).updateMessages((String) args[1]);
}
else {
MainLobby.privateMessageWindows.put(username, new Conversation(username, client));
MainLobby.privateMessageWindows.get(username).updateMessages((String) args[1]);
}
}
});
}
});
socket.on("messages", new Emitter.Listener() {
@Override
public void call(Object... args) {
String messages = "";
JSONArray msgs = (JSONArray)args[0];
for (int i = 0; i < msgs.length(); i++) {
try {
messages += msgs.optJSONObject(i).getString("message") + "\n";
} catch (JSONException e) {
break;
}
}
try{
Thread.sleep(2000);
}catch(InterruptedException ex){
//do stuff
}
MainLobby.updateMessages(messages);
}
});
socket.on("registered", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Registration successful " + args[0]);
Platform.runLater(new Runnable() {
@Override
public void run() {
new MessageBox("Registered", "Successfully registered with username '" + (String) args[0]
+ "'.\n You can log in now!");
}
});
}
});
socket.on("registerError", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Couldn't register: " + args[0]);
Platform.runLater(new Runnable() {
@Override
public void run() {
new MessageBox("Register Error", (String) args[0]);
}
});
}
});
socket.on("loggedIn", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Login successful " + args[0]);
Platform.runLater(new Runnable() {
@Override
public void run() {
App.username = (String) args[0];
new MainLobby(primaryStage, client);
}
});
}
});
socket.on("logInError", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Couldn't login: " + args[0]);
Platform.runLater(new Runnable() {
@Override
public void run() {
new MessageBox("Login Error", (String) args[0]);
}
});
}
});
socket.connect();
}
public void register(String username, String password) {
socket.emit("register", username + "," + password);
}
public void login(String username, String password) {
socket.emit("login", username + "," + password);
}
public void message(String message) {
socket.emit("message", message);
}
public void privateMessage(String message, String to) {
socket.emit("privateMessage", message, to);
}
public void disconnect() {
socket.disconnect();
}
public static String[] toStringArray(JSONArray array) {
if(array==null)
return null;
String[] arr=new String[array.length()];
for(int i=0; i<arr.length; i++) {
arr[i]=array.optString(i);
}
return arr;
}
}

88
src/Conversation.java Normal file
View File

@ -0,0 +1,88 @@
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
public class Conversation {
Stage stage;
Client client;
TextArea messageList;
String username;
Conversation(String username, Client client)
{
this.client = client;
this.username = username;
BorderPane border = new BorderPane();
Text title = new Text(username);
StackPane stack = new StackPane();
stack.setPadding(new Insets(15, 12, 15, 12));
title.prefWidth(800);
title.setTextAlignment(TextAlignment.CENTER);
title.setFont(new Font(24));
stack.getChildren().add(title);
border.setTop(stack);
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
//hbox.setStyle("-fx-background-color: #336699;");
TextField messageTextField = new TextField();
messageTextField.setPrefSize(600, 20);
Button buttonCurrent = new Button("Send message");
buttonCurrent.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
String message = App.username + ": " + messageTextField.getText();
client.privateMessage(message, username);
messageTextField.setText("");
updateMessages(message);
}
});
buttonCurrent.setPrefSize(200, 20);
hbox.getChildren().addAll(messageTextField, buttonCurrent);
border.setBottom(hbox);
ScrollPane scroll = new ScrollPane();
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
scroll.setPadding(new Insets(15, 12, 15, 12));
messageList = new TextArea();
String messages = "";
messageList.setText(messages);
messageList.setEditable(false);
messageList.setWrapText(true);
messageList.setPrefSize(525, 500);
scroll.setContent(messageList);
border.setCenter(scroll);
stage = new Stage();
stage.setResizable(false);
stage.setTitle("Conversation | " + username);
stage.setScene(new Scene(border, 800, 600));
stage.show();
}
public void updateMessages(String text) {
messageList.appendText(text + "\n");
}
public void show() {
stage.show();
}
}

79
src/LoginPage.java Normal file
View File

@ -0,0 +1,79 @@
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class LoginPage {
public static Scene makeLoginPage(Stage primaryStage, Client client) {
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
Text scenetitle = new Text("Login");
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
grid.add(scenetitle, 0, 0, 2, 1);
Label userName = new Label("User Name:");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
grid.add(userTextField, 1, 1);
Label pw = new Label("Password:");
grid.add(pw, 0, 2);
PasswordField pwBox = new PasswordField();
grid.add(pwBox, 1, 2);
Button btn = new Button("Register");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 0, 4);
Button btn2 = new Button("Sign in");
HBox hbBtn2 = new HBox(10);
hbBtn2.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn2.getChildren().add(btn2);
grid.add(hbBtn2, 1, 4);
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
/* Change the scene of the primaryStage */
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
// do stuff
}
primaryStage.close();
primaryStage.setScene(RegisterPage.makeRegisterPage(primaryStage, client));
primaryStage.show();
}
});
btn2.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
client.login(userTextField.getText(), pwBox.getText());
}
});
return new Scene(grid, 400, 400);
}
}

152
src/MainLobby.java Normal file
View File

@ -0,0 +1,152 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
public class MainLobby {
static Stage primaryStage;
static BorderPane border = new BorderPane();
static Scene scene;
Client client;
static TextArea messageList;
static ListView userList;
//static HashMap<String, String> privateMessages = new HashMap<String, String>();
static HashMap<String, Conversation> privateMessageWindows = new HashMap<String, Conversation>();
static Image image;
MainLobby(Stage primaryStage, Client client) {
this.client = client;
primaryStage.close();
primaryStage.setTitle("Main Lobby");
//Text lobbytitle = new Text("Lobby");
try {
image = new Image(new FileInputStream("Officon_Logo.png"));
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ImageView imageView = new ImageView(image);
//Setting the preserve ratio of the image view
imageView.setPreserveRatio(true);
imageView.setFitHeight(46);
StackPane stack = new StackPane();
stack.setPadding(new Insets(15, 12, 15, 12));
//lobbytitle.prefWidth(800);
//lobbytitle.setTextAlignment(TextAlignment.CENTER);
//lobbytitle.setFont(new Font(20));
stack.getChildren().add(imageView);
border.setTop(stack);
VBox vbox = new VBox();
vbox.setPadding(new Insets(15, 12, 15, 12));
Text listtitle = new Text("Online users");
StackPane liststack = new StackPane();
liststack.setPadding(new Insets(15, 12, 15, 12));
liststack.getChildren().add(listtitle);
userList = new ListView();
for (String user : App.activeUsers) {
userList.getItems().add(user);
}
userList.setPrefHeight(600);
Button button = new Button("Message User");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
String username = (String) userList.getSelectionModel().getSelectedItem();
if (privateMessageWindows.get(username) != null && privateMessageWindows.containsKey(username)) {
privateMessageWindows.get(username).show();
}
else {
privateMessageWindows.put(username, new Conversation(username, client));
}
}
});
button.setPrefWidth(250);
vbox.getChildren().addAll(liststack, userList, button);
border.setLeft(vbox);
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
// hbox.setStyle("-fx-background-color: #336699;");
TextField messageTextField = new TextField();
messageTextField.setText("");
messageTextField.setPrefSize(600, 20);
Button buttonCurrent = new Button("Send message");
buttonCurrent.setPrefSize(200, 20);
buttonCurrent.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
String message = App.username + ": " + messageTextField.getText();
client.message(message);
App.messages.add(message);
messageTextField.setText("");
updateMessages(message);
}
});
hbox.getChildren().addAll(messageTextField, buttonCurrent);
border.setBottom(hbox);
ScrollPane scroll = new ScrollPane();
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
scroll.setPadding(new Insets(15, 12, 15, 12));
messageList = new TextArea();
String messages = "";
if (App.messages != null) {
for (String message: App.messages) {
messages += message +"\n";
}
}
messageList.setText(messages);
messageList.setEditable(false);
messageList.setWrapText(true);
messageList.setPrefSize(525, 500);
scroll.setContent(messageList);
border.setCenter(scroll);
scene = new Scene(border, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
this.primaryStage = primaryStage;
}
public static void updateUsers() {
for (String user : App.activeUsers) {
userList.getItems().add(user);
}
userList.refresh();
}
public static void updateMessages(String text) {
messageList.appendText(text + "\n");
}
}

52
src/MessageBox.java Normal file
View File

@ -0,0 +1,52 @@
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MessageBox {
MessageBox(String title, String message){
BorderPane border = new BorderPane();
StackPane stack = new StackPane();
Text msg = new Text(message);
//msg.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
stack.getChildren().add(msg);
StackPane bstack = new StackPane();
bstack.setPadding(new Insets(0, 12, 30, 12));
Button btn = new Button("OK");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
Stage stage = (Stage) btn.getScene().getWindow();
stage.close();
}
});
bstack.getChildren().add(btn);
border.setCenter(stack);
border.setBottom(bstack);
Stage stage = new Stage();
stage.setTitle(title);
stage.setScene(new Scene(border, 300, 100));
stage.setResizable(false);
stage.setAlwaysOnTop(true);
stage.show();
}
}

92
src/RegisterPage.java Normal file
View File

@ -0,0 +1,92 @@
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class RegisterPage {
public static Scene makeRegisterPage(Stage primaryStage, Client client) {
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
Text scenetitle = new Text("Register");
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
grid.add(scenetitle, 0, 0, 2, 1);
Label userName = new Label("User Name:");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
grid.add(userTextField, 1, 1);
Label pw = new Label("Password:");
grid.add(pw, 0, 2);
PasswordField pwBox = new PasswordField();
grid.add(pwBox, 1, 2);
Label cpw = new Label("Confirm password:");
grid.add(cpw, 0, 3);
PasswordField cpwBox = new PasswordField();
grid.add(cpwBox, 1, 3);
Button btn = new Button("Register");
HBox hbBtn = new HBox(25);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 1, 5);
Button btn2 = new Button("Back");
HBox hbBtn2 = new HBox(10);
hbBtn2.setAlignment(Pos.BOTTOM_LEFT);
hbBtn2.getChildren().add(btn2);
grid.add(hbBtn2, 0, 5);
final Text actiontarget = new Text();
grid.add(actiontarget, 1, 6);
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
actiontarget.setFill(Color.FIREBRICK);
if (pwBox.getText().equals(cpwBox.getText())) {
client.register(userTextField.getText(), pwBox.getText());
}
else {
new MessageBox("Register Error", "Password fields don't match");
cpwBox.setText("");
pwBox.setText("");
}
}
});
btn2.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
primaryStage.close();
primaryStage.setScene(LoginPage.makeLoginPage(primaryStage, client));
primaryStage.show();
}
});
return new Scene(grid, 400, 400);
}
}

3
tables.sql Normal file
View File

@ -0,0 +1,3 @@
CREATE TABLE ACCOUNTS (ACCOUNT_ID TEXT PRIMARY KEY NOT NULL, USERNAME TEXT NOT NULL, PASSWORD TEXT NOT NULL);
CREATE TABLE MESSAGE (FROM_USER TEXT NOT NULL, TO_USER TEXT NOT NULL, MESSAGE TEXT);