From 47a298af2fd197e2209dfb2fa6b1cee57dc13703 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 6 Jun 2020 18:45:42 +0200 Subject: [PATCH] Add cli module --- cli/.gitignore | 2 + cli/build.gradle | 46 ++++++ .../messenger/cli/ConsoleUserInterface.java | 21 +++ .../mercury_im/messenger/cli/MercuryCli.java | 132 ++++++++++++++++++ .../messenger/cli/ScannerUserInterface.java | 18 +++ .../messenger/cli/UserInterface.java | 8 ++ .../cli/di/component/CliComponent.java | 22 +++ .../cli/di/module/CliPersistenceModule.java | 66 +++++++++ settings.gradle | 4 +- 9 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 cli/.gitignore create mode 100644 cli/build.gradle create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/ConsoleUserInterface.java create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/ScannerUserInterface.java create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/UserInterface.java create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java create mode 100644 cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 0000000..60bf954 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1,2 @@ +/build +testcredentials.properties diff --git a/cli/build.gradle b/cli/build.gradle new file mode 100644 index 0000000..b135bd3 --- /dev/null +++ b/cli/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java' + id 'application' +} + +group 'org.mercury_im' +version '1.0' +mainClassName = "org.mercury_im.messenger.cli.MercuryCli" + +repositories { + mavenCentral() +} + +// Add the generated folder to the source directories so that we can work with generated classes +// This is apparently necessary for use with requery. +sourceSets { + main.java.srcDirs += "${buildDir}/generated/sources/annotationProcessor/java/main/" + test.java.srcDirs += "${buildDir}/generated/sources/annotationProcessor/java/test/" +} + +dependencies { + implementation project(':domain') + implementation project(':data') + + implementation "io.requery:requery:$requeryVersion" + implementation "com.h2database:h2:1.4.200" + + // RxJava2 + implementation "io.reactivex.rxjava2:rxjava:$rxJava2Version" + + // Dagger 2 for dependency injection + implementation "com.google.dagger:dagger:$daggerVersion" + annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" + + compileOnly "org.projectlombok:lombok:$lombokVersion" + annotationProcessor "org.projectlombok:lombok:$lombokVersion" + + implementation 'org.igniterealtime.smack:smack-tcp' + implementation 'org.igniterealtime.smack:smack-java8-full' + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +run { + standardInput = System.in +} + diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/ConsoleUserInterface.java b/cli/src/main/java/org/mercury_im/messenger/cli/ConsoleUserInterface.java new file mode 100644 index 0000000..d3a895f --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/ConsoleUserInterface.java @@ -0,0 +1,21 @@ +package org.mercury_im.messenger.cli; + +import java.io.Console; + +public class ConsoleUserInterface implements UserInterface { + + public static boolean isSupported() { + return System.console() != null; + } + + @Override + public String readText() { + Console console = System.console(); + return console.readLine(); + } + + @Override + public String readPassword() { + return new String(System.console().readPassword()); + } +} diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java b/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java new file mode 100644 index 0000000..3aa72db --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/MercuryCli.java @@ -0,0 +1,132 @@ +package org.mercury_im.messenger.cli; + +import org.jivesoftware.smack.util.StringUtils; +import org.jxmpp.jid.DomainBareJid; +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Localpart; +import org.jxmpp.stringprep.XmppStringprepException; +import org.mercury_im.messenger.cli.di.component.CliComponent; +import org.mercury_im.messenger.cli.di.component.DaggerCliComponent; +import org.mercury_im.messenger.core.Messenger; +import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel; +import org.mercury_im.messenger.core.xmpp.MercuryConnection; + +import java.util.List; + +import javax.inject.Inject; + +import io.reactivex.disposables.Disposable; + +public class MercuryCli { + + private final UserInterface userInterface; + Disposable connectionStateDisposable; + + @Inject + Messenger messenger; + + @Inject + LoginViewModel loginViewModel; + + public static void main(String[] args) { + MercuryCli cli = new MercuryCli(); + cli.loginDialog(); + System.out.println("Login successful."); + cli.loop(); + } + + /** + * Create the Dependency Injection graph. + */ + public CliComponent createCliComponent() { + CliComponent cliComponent = DaggerCliComponent.builder() + .build(); + + cliComponent.inject(this); + + return cliComponent; + } + + public MercuryCli() { + createCliComponent(); + userInterface = ConsoleUserInterface.isSupported() ? new ConsoleUserInterface() : new ScannerUserInterface(); + //connectionStateDisposable = messenger.getConnectionCenter().observeConnectionPoolState().subscribe(System.out::println); + } + + private void loginDialog() { + System.out.println("Format is 'Username'@'Service'."); + + String username = promptForUsername(); + DomainBareJid service = promptForServiceDomain(); + String password = promptForPassword(); + + EntityBareJid jid = JidCreate.entityBareFrom(Localpart.formUnescapedOrNull(username), service); + + loginViewModel.onLoginUsernameChanged(jid.toString()); + loginViewModel.onLoginPasswordChanged(password); + + loginViewModel.login(); + } + + private String promptForPassword() { + System.out.println("Enter password:"); + String password = userInterface.readPassword(); + if (StringUtils.isNullOrEmpty(password)) { + System.out.println("Password too short."); + return promptForPassword(); + } + return password; + } + + private DomainBareJid promptForServiceDomain() { + System.out.println("Enter service:"); + String service = userInterface.readText(); + try { + return JidCreate.domainBareFrom(service); + } catch (XmppStringprepException e) { + System.out.println("Invalid service domain."); + return promptForServiceDomain(); + } + } + + private String promptForUsername() { + System.out.println("Please enter username:"); + String username = userInterface.readText(); + try { + Localpart.from(username); + } catch (XmppStringprepException e) { + System.out.println("Invalid username."); + return promptForUsername(); + } + return username; + } + + private void loop() { + String input = userInterface.readText(); + if (StringUtils.isNullOrEmpty(input)) { + loop(); + return; + } + + String[] command = input.split(" "); + switch (command[0]) { + case "/exit": + System.out.println("Shutting down."); + messenger.getConnectionManager().doShutdownAllConnections(); + connectionStateDisposable.dispose(); + return; + + case "/contacts": + List connectionList = messenger.getConnectionManager().getConnections(); + + + break; + + case "/msg": + break; + } + loop(); + } + +} diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/ScannerUserInterface.java b/cli/src/main/java/org/mercury_im/messenger/cli/ScannerUserInterface.java new file mode 100644 index 0000000..d4a5bb5 --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/ScannerUserInterface.java @@ -0,0 +1,18 @@ +package org.mercury_im.messenger.cli; + +import java.util.Scanner; + +public class ScannerUserInterface implements UserInterface { + + private final Scanner scanner = new Scanner(System.in); + + @Override + public String readText() { + return scanner.nextLine(); + } + + @Override + public String readPassword() { + return scanner.nextLine(); + } +} diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/UserInterface.java b/cli/src/main/java/org/mercury_im/messenger/cli/UserInterface.java new file mode 100644 index 0000000..8a9e97a --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/UserInterface.java @@ -0,0 +1,8 @@ +package org.mercury_im.messenger.cli; + +public interface UserInterface { + + String readText(); + + String readPassword(); +} diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java b/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java new file mode 100644 index 0000000..ca36e05 --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/di/component/CliComponent.java @@ -0,0 +1,22 @@ +package org.mercury_im.messenger.cli.di.component; + +import org.mercury_im.messenger.cli.MercuryCli; +import org.mercury_im.messenger.cli.di.module.CliPersistenceModule; +import org.mercury_im.messenger.core.di.module.ViewModelModule; +import org.mercury_im.messenger.data.di.RepositoryModule; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component( + modules = { + CliPersistenceModule.class, + RepositoryModule.class, + ViewModelModule.class + }) +public interface CliComponent { + + void inject(MercuryCli mercuryCli); +} diff --git a/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java b/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java new file mode 100644 index 0000000..e86085c --- /dev/null +++ b/cli/src/main/java/org/mercury_im/messenger/cli/di/module/CliPersistenceModule.java @@ -0,0 +1,66 @@ +package org.mercury_im.messenger.cli.di.module; + +import org.h2.jdbcx.JdbcDataSource; +import org.mercury_im.messenger.core.util.ThreadUtils; +import org.mercury_im.messenger.data.model.Models; + +import java.util.concurrent.Executors; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import io.reactivex.Scheduler; +import io.reactivex.schedulers.Schedulers; +import io.requery.Persistable; +import io.requery.cache.EmptyEntityCache; +import io.requery.reactivex.ReactiveEntityStore; +import io.requery.reactivex.ReactiveSupport; +import io.requery.sql.Configuration; +import io.requery.sql.ConfigurationBuilder; +import io.requery.sql.EntityDataStore; +import io.requery.sql.SchemaModifier; +import io.requery.sql.TableCreationMode; + +@Module +public class CliPersistenceModule { + + private static Scheduler scheduler = Schedulers.newThread(); + + @Provides + @Singleton + static ReactiveEntityStore provideDatabase() { + JdbcDataSource dataSource = new JdbcDataSource(); + dataSource.setUrl("jdbc:h2:~/mercury_req_db"); + dataSource.setUser("sa"); + dataSource.setPassword("sa"); + + // override onUpgrade to handle migrating to a new version + Configuration configuration = new ConfigurationBuilder(dataSource, Models.DEFAULT) + .useDefaultLogging() + .setEntityCache(new EmptyEntityCache()) + .setWriteExecutor(Executors.newSingleThreadExecutor()) + .build(); + + SchemaModifier tables = new SchemaModifier(configuration); + tables.createTables(TableCreationMode.DROP_CREATE); + System.out.println(tables.createTablesString(TableCreationMode.DROP_CREATE)); + + return ReactiveSupport.toReactiveStore(new EntityDataStore<>(configuration)); + } + + @Provides + @Named(value = ThreadUtils.SCHEDULER_IO) + @Singleton + static Scheduler provideDatabaseThread() { + return Schedulers.io(); + } + + @Provides + @Named(value = ThreadUtils.SCHEDULER_UI) + @Singleton + static Scheduler providerUIThread() { + return scheduler; + } +} diff --git a/settings.gradle b/settings.gradle index 7f2ec34..c24ad32 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,7 @@ include ':entity', ':data', ':domain', - ':app' - // ':core-old' + ':app', + ':cli' includeBuild 'libs/Smack'