feat: Command Line Interface
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package ru.di9.ihc;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
|
||||
@@ -27,6 +28,10 @@ public class IhcClient {
|
||||
|
||||
private boolean isAuth = false;
|
||||
|
||||
public IhcClient() {
|
||||
this("https://my.ihc.ru");
|
||||
}
|
||||
|
||||
public IhcClient(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.httpClient = HttpClientBuilder.create().build();
|
||||
|
||||
56
src/main/java/ru/di9/ihc/cli/AddDomainRecordCommand.java
Normal file
56
src/main/java/ru/di9/ihc/cli/AddDomainRecordCommand.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine;
|
||||
import ru.di9.ihc.Domain;
|
||||
import ru.di9.ihc.IhcClient;
|
||||
import ru.di9.ihc.RecordType;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@CommandLine.Command(
|
||||
name = "add",
|
||||
description = "Добавить запись домена")
|
||||
public class AddDomainRecordCommand implements Callable<Integer> {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
|
||||
@CommandLine.Option(names = {"-u", "--username"}, description = "Имя пользователя", required = true)
|
||||
private String username;
|
||||
|
||||
@CommandLine.Option(names = {"-p", "--password"}, description = "Пароль пользователя", required = true, arity = "0..1", interactive = true)
|
||||
private String password;
|
||||
|
||||
@CommandLine.Parameters(index = "0", description = "Имя домена")
|
||||
private String domainName;
|
||||
|
||||
@CommandLine.Option(names = {"--name"}, description = "Имя записи")
|
||||
private String recordName;
|
||||
|
||||
@CommandLine.Option(names = {"--type"}, description = "Тип записи", converter = CliRecordTypeConverter.class, required = true)
|
||||
private RecordType recordType;
|
||||
|
||||
@CommandLine.Option(names = {"--content"}, description = "Контент", required = true)
|
||||
private String recordContent;
|
||||
|
||||
@CommandLine.Option(names = {"--priority"}, description = "Приоритет")
|
||||
private Integer recordPriority;
|
||||
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
IhcClient ihc = new IhcClient();
|
||||
if (!ihc.auth(username, password)) {
|
||||
System.err.println("Неверное имя пользователя или пароль");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Domain domain = ihc.getDomains().stream().filter(d -> d.name().equalsIgnoreCase(domainName)).findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("DOMAIN '%s' NOT EXISTS".formatted(domainName)));
|
||||
|
||||
ihc.addDomainRecord(domain, recordName, recordType, recordContent, recordPriority);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
39
src/main/java/ru/di9/ihc/cli/CliApp.java
Normal file
39
src/main/java/ru/di9/ihc/cli/CliApp.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@Setter
|
||||
@ToString
|
||||
@CommandLine.Command(
|
||||
name = "app",
|
||||
description = "IHC DNS Tools",
|
||||
subcommands = {
|
||||
DomainsListCommand.class,
|
||||
DomainRecordCommand.class
|
||||
},
|
||||
version = "1.0-SNAPSHOT")
|
||||
public class CliApp {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
|
||||
@CommandLine.Option(names = {"-v", "--version"}, description = "Версия программы", versionHelp = true)
|
||||
private boolean flagVersion;
|
||||
|
||||
public static void main(String[] args) {
|
||||
CliApp cliApp = new CliApp();
|
||||
CommandLine commandLine = new CommandLine(cliApp);
|
||||
commandLine.parseArgs(args);
|
||||
|
||||
if (cliApp.flagHelp) {
|
||||
CommandLine.usage(cliApp, System.out);
|
||||
return;
|
||||
} else if (cliApp.flagVersion) {
|
||||
commandLine.printVersionHelp(System.out);
|
||||
return;
|
||||
}
|
||||
|
||||
System.exit(commandLine.execute(args));
|
||||
}
|
||||
}
|
||||
11
src/main/java/ru/di9/ihc/cli/CliRecordTypeConverter.java
Normal file
11
src/main/java/ru/di9/ihc/cli/CliRecordTypeConverter.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import ru.di9.ihc.RecordType;
|
||||
|
||||
public class CliRecordTypeConverter implements CommandLine.ITypeConverter<RecordType> {
|
||||
@Override
|
||||
public RecordType convert(String s) {
|
||||
return RecordType.valueOf(s.toUpperCase());
|
||||
}
|
||||
}
|
||||
50
src/main/java/ru/di9/ihc/cli/DeleteDomainRecordCommand.java
Normal file
50
src/main/java/ru/di9/ihc/cli/DeleteDomainRecordCommand.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine;
|
||||
import ru.di9.ihc.Domain;
|
||||
import ru.di9.ihc.DomainRecord;
|
||||
import ru.di9.ihc.IhcClient;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@CommandLine.Command(
|
||||
name = "delete",
|
||||
description = "Удалить запись домена")
|
||||
public class DeleteDomainRecordCommand implements Callable<Integer> {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
|
||||
@CommandLine.Option(names = {"-u", "--username"}, description = "Имя пользователя", required = true)
|
||||
private String username;
|
||||
|
||||
@CommandLine.Option(names = {"-p", "--password"}, description = "Пароль пользователя", required = true, arity = "0..1", interactive = true)
|
||||
private String password;
|
||||
|
||||
@CommandLine.Parameters(index = "0", description = "Имя домена")
|
||||
private String domainName;
|
||||
|
||||
@CommandLine.Parameters(index = "1", description = "Имя записи")
|
||||
private String recordName;
|
||||
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
IhcClient ihc = new IhcClient();
|
||||
if (!ihc.auth(username, password)) {
|
||||
System.err.println("Неверное имя пользователя или пароль");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Domain domain = ihc.getDomains().stream().filter(d -> d.name().equalsIgnoreCase(domainName)).findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("DOMAIN '%s' NOT EXISTS".formatted(domainName)));
|
||||
|
||||
DomainRecord record = ihc.getDomainRecords(domain).stream().filter(r -> r.getName().equals(recordName)).findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("RECORD '%s' FOR DOMAIN '%s' NOT EXISTS".formatted(recordName, domainName)));
|
||||
|
||||
ihc.removeDomainRecord(domain, record.getId());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
21
src/main/java/ru/di9/ihc/cli/DomainRecordCommand.java
Normal file
21
src/main/java/ru/di9/ihc/cli/DomainRecordCommand.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@CommandLine.Command(
|
||||
name = "domain-record",
|
||||
description = "Работа с записями домена",
|
||||
subcommands = {
|
||||
DomainRecordsListCommand.class,
|
||||
AddDomainRecordCommand.class,
|
||||
EditDomainRecordCommand.class,
|
||||
DeleteDomainRecordCommand.class
|
||||
})
|
||||
public class DomainRecordCommand {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
}
|
||||
62
src/main/java/ru/di9/ihc/cli/DomainRecordsListCommand.java
Normal file
62
src/main/java/ru/di9/ihc/cli/DomainRecordsListCommand.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine;
|
||||
import ru.di9.ihc.Domain;
|
||||
import ru.di9.ihc.DomainRecord;
|
||||
import ru.di9.ihc.IhcClient;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@CommandLine.Command(
|
||||
name = "list",
|
||||
description = "Список записей доменов")
|
||||
public class DomainRecordsListCommand implements Callable<Integer> {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
|
||||
@CommandLine.Option(names = {"-u", "--username"}, description = "Имя пользователя", required = true)
|
||||
private String username;
|
||||
|
||||
@CommandLine.Option(names = {"-p", "--password"}, description = "Пароль пользователя", required = true, arity = "0..1", interactive = true)
|
||||
private String password;
|
||||
|
||||
@CommandLine.Parameters(index = "0", description = "Имя домена")
|
||||
private String domainName;
|
||||
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
IhcClient ihc = new IhcClient();
|
||||
if (!ihc.auth(username, password)) {
|
||||
System.err.println("Неверное имя пользователя или пароль");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Domain domain = ihc.getDomains().stream().filter(d -> d.name().equalsIgnoreCase(domainName)).findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("DOMAIN '%s' NOT EXISTS".formatted(domainName)));
|
||||
List<DomainRecord> domainRecords = ihc.getDomainRecords(domain);
|
||||
|
||||
var colId = new TableCol("ID");
|
||||
var colName = new TableCol("Запись");
|
||||
var colType = new TableCol("Тип");
|
||||
var colPriority = new TableCol("Приоритет");
|
||||
var colContent = new TableCol("Контент");
|
||||
var colReadOnly = new TableCol("Только для чтения");
|
||||
|
||||
for (DomainRecord record : domainRecords) {
|
||||
colId.putRow(record.getId());
|
||||
colName.putRow(record.getName());
|
||||
colType.putRow(record.getType().name());
|
||||
colPriority.putRow(record.getPriority());
|
||||
colContent.putRow(record.getContent());
|
||||
colReadOnly.putRow(record.isReadOnly() ? "да" : "нет");
|
||||
}
|
||||
|
||||
System.out.println(new Table(colId, colName, colType, colPriority, colContent, colReadOnly).print());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
50
src/main/java/ru/di9/ihc/cli/DomainsListCommand.java
Normal file
50
src/main/java/ru/di9/ihc/cli/DomainsListCommand.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine;
|
||||
import ru.di9.ihc.Domain;
|
||||
import ru.di9.ihc.IhcClient;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@CommandLine.Command(
|
||||
name = "domains",
|
||||
description = "Список доменов")
|
||||
public class DomainsListCommand implements Callable<Integer> {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
|
||||
@CommandLine.Option(names = {"-u", "--username"}, description = "Имя пользователя", required = true)
|
||||
private String username;
|
||||
|
||||
@CommandLine.Option(names = {"-p", "--password"}, description = "Пароль пользователя", required = true, arity = "0..1", interactive = true)
|
||||
private String password;
|
||||
|
||||
@Override
|
||||
public Integer call() {
|
||||
IhcClient ihc = new IhcClient();
|
||||
if (!ihc.auth(username, password)) {
|
||||
System.err.println("Неверное имя пользователя или пароль");
|
||||
return -1;
|
||||
};
|
||||
|
||||
List<Domain> domains = ihc.getDomains();
|
||||
|
||||
var colId = new TableCol("ID");
|
||||
var colDomain = new TableCol("Домен");
|
||||
var colPunycode = new TableCol("Punycode");
|
||||
|
||||
for (Domain domain : domains) {
|
||||
colId.putRow(domain.id());
|
||||
colDomain.putRow(domain.name());
|
||||
colPunycode.putRow(domain.punycode());
|
||||
}
|
||||
|
||||
System.out.println(new Table(colId, colDomain, colPunycode).print());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
64
src/main/java/ru/di9/ihc/cli/EditDomainRecordCommand.java
Normal file
64
src/main/java/ru/di9/ihc/cli/EditDomainRecordCommand.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine;
|
||||
import ru.di9.ihc.Domain;
|
||||
import ru.di9.ihc.DomainRecord;
|
||||
import ru.di9.ihc.IhcClient;
|
||||
import ru.di9.ihc.RecordType;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@CommandLine.Command(
|
||||
name = "edit",
|
||||
description = "Изменить запись домена")
|
||||
public class EditDomainRecordCommand implements Callable<Integer> {
|
||||
@CommandLine.Option(names = {"-h", "--help"}, description = "Страница помощи", usageHelp = true)
|
||||
private boolean flagHelp;
|
||||
|
||||
@CommandLine.Option(names = {"-u", "--username"}, description = "Имя пользователя", required = true)
|
||||
private String username;
|
||||
|
||||
@CommandLine.Option(names = {"-p", "--password"}, description = "Пароль пользователя", required = true, arity = "0..1", interactive = true)
|
||||
private String password;
|
||||
|
||||
@CommandLine.Parameters(index = "0", description = "Имя домена")
|
||||
private String domainName;
|
||||
|
||||
@CommandLine.Parameters(index = "1", description = "Имя записи")
|
||||
private String recordName;
|
||||
|
||||
@CommandLine.Option(names = {"--name"}, description = "Новое имя записи")
|
||||
private String recordNewName;
|
||||
|
||||
@CommandLine.Option(names = {"--content"}, description = "Контент")
|
||||
private String recordContent;
|
||||
|
||||
@CommandLine.Option(names = {"--priority"}, description = "Приоритет")
|
||||
private Integer recordPriority;
|
||||
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
IhcClient ihc = new IhcClient();
|
||||
if (!ihc.auth(username, password)) {
|
||||
System.err.println("Неверное имя пользователя или пароль");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Domain domain = ihc.getDomains().stream().filter(d -> d.name().equalsIgnoreCase(domainName)).findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("DOMAIN '%s' NOT EXISTS".formatted(domainName)));
|
||||
|
||||
DomainRecord record = ihc.getDomainRecords(domain).stream().filter(r -> r.getName().equals(recordName)).findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("RECORD '%s' FOR DOMAIN '%s' NOT EXISTS".formatted(recordName, domainName)));
|
||||
|
||||
if (recordNewName != null) record.setName(recordNewName);
|
||||
if (recordContent != null) record.setContent(recordContent);
|
||||
if (recordPriority != null) record.setPriority(recordPriority);
|
||||
|
||||
ihc.updateDomainRecord(domain, record);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
63
src/main/java/ru/di9/ihc/cli/Table.java
Normal file
63
src/main/java/ru/di9/ihc/cli/Table.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Table {
|
||||
private final List<TableCol> cols = new ArrayList<>();
|
||||
|
||||
public Table(TableCol... cols) {
|
||||
this.cols.addAll(Arrays.asList(cols));
|
||||
}
|
||||
|
||||
public String print() {
|
||||
Object[] headers = new Object[cols.size()];
|
||||
String formatRow;
|
||||
String strLine;
|
||||
int maxRows = 0;
|
||||
|
||||
{
|
||||
StringBuilder sbFormatRow = new StringBuilder();
|
||||
StringBuilder sbStrLine = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < cols.size(); i++) {
|
||||
TableCol col = cols.get(i);
|
||||
|
||||
headers[i] = col.getHeader();
|
||||
maxRows = Math.max(maxRows, col.getRows().size());
|
||||
|
||||
sbFormatRow.append(" %%-%ds ".formatted(col.getSize()));
|
||||
sbStrLine.append("-".repeat(col.getSize() + 2));
|
||||
|
||||
if (i < cols.size() - 1) {
|
||||
sbFormatRow.append('|');
|
||||
sbStrLine.append('|');
|
||||
}
|
||||
}
|
||||
|
||||
formatRow = sbFormatRow.toString();
|
||||
strLine = sbStrLine.toString();
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(formatRow.formatted(headers)).append('\n')
|
||||
.append(strLine).append('\n');
|
||||
|
||||
Object[] cells;
|
||||
for (int i = 0; i < maxRows; i++) {
|
||||
cells = new Object[headers.length];
|
||||
for (int j = 0; j < cols.size(); j++) {
|
||||
cells[j] = cols.get(j).getRows().get(i);
|
||||
}
|
||||
|
||||
result.append(formatRow.formatted(cells));
|
||||
|
||||
if (i < maxRows - 1) {
|
||||
result.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
41
src/main/java/ru/di9/ihc/cli/TableCol.java
Normal file
41
src/main/java/ru/di9/ihc/cli/TableCol.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package ru.di9.ihc.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TableCol {
|
||||
private final List<String> rows = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private final String header;
|
||||
|
||||
@Getter
|
||||
private int size;
|
||||
|
||||
public TableCol(String header) {
|
||||
this.header = header;
|
||||
this.size = header.length();
|
||||
}
|
||||
|
||||
public void putRow(Integer row) {
|
||||
if (row == null) putRow((String) null);
|
||||
else putRow(String.valueOf(row));
|
||||
}
|
||||
|
||||
public void putRow(String row) {
|
||||
if (row == null) {
|
||||
rows.add("");
|
||||
return;
|
||||
}
|
||||
|
||||
rows.add(row);
|
||||
size = Math.max(size, row.length());
|
||||
}
|
||||
|
||||
public List<String> getRows() {
|
||||
return Collections.unmodifiableList(rows);
|
||||
}
|
||||
}
|
||||
1
src/main/java/ru/di9/ihc/lombok.config
Normal file
1
src/main/java/ru/di9/ihc/lombok.config
Normal file
@@ -0,0 +1 @@
|
||||
lombok.log.flagUsage=error
|
||||
Reference in New Issue
Block a user