Initial Database Migration

This commit is contained in:
Isaac Parenteau
2019-10-06 20:07:47 -05:00
parent 38dbc5bbf5
commit af8e8fa52a
20 changed files with 1567 additions and 113 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@
/nbactions.xml
.bin
/bin/
/key.bin
/logs/
/conf/

View File

@ -148,7 +148,7 @@
<dependency>
<groupId>net.locusworks</groupId>
<artifactId>crypto</artifactId>
<version>1.0.3-RELEASE</version>
<version>1.0.5-RELEASE</version>
</dependency>
<dependency>

View File

@ -0,0 +1,156 @@
/**
*
* Project: Eight Track, File: EightTrackBeanConfiguration.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.database.config;
import java.util.HashSet;
import java.util.Properties;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.configuration.FluentConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration(value="net.locusworks.discord.eighttrack.database.config.EightTrackBeanConfiguration")
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {"net.locusworks.discord.eighttrack.database.repos"},
entityManagerFactoryRef = "eighttrackEntityManagerFactory",
transactionManagerRef = "eighttrackTransactionManager"
)
public class EightTrackBeanConfiguration {
public static final String PERSISTENCE_UNIT = "eighttrack_pu";
public static final HashSet<String> cacheNames = new HashSet<>();
private static final String[] PACKAGES_TO_SCAN = {
"net.locusworks.discord.eighttrack.database.entities"
};
private static final Properties hibernateProperties;
static {
hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.connection.zeroDateTimeBehavior", "convertToNull");
hibernateProperties.setProperty("hibernate.dbcp.maxActive", "50");
hibernateProperties.setProperty("hibernate.dbcp.maxIdle", "10");
hibernateProperties.setProperty("hibernate.dbcp.maxWait", "5000");
hibernateProperties.setProperty("hibernate.jdbc.batch_size property", "50");
hibernateProperties.setProperty("hibernate.connection.charSet", "utf8");
hibernateProperties.setProperty("hibernate.connection.characterEncoding", "utf8");
hibernateProperties.setProperty("hibernate.connection.useUnicode", "true");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
}
@Autowired
private DataSource dataSource;
@Autowired
private DataSource flywayDataSource;
/**
* Create the entity manager factory bean used in the database connection
* @return entityManagerFactoryBean
*/
@Primary
@Bean
@DependsOn("flyway")
public LocalContainerEntityManagerFactoryBean eighttrackEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(eighttrackJpaVendorAdapter());
lef.setPackagesToScan(PACKAGES_TO_SCAN);
lef.setJpaProperties(hibernateProperties);
lef.setPersistenceUnitName(PERSISTENCE_UNIT);
return lef;
}
/**
* Create the session factory bean
* @return sessionFactoryBean
*/
@Bean
public LocalSessionFactoryBean pseduobotSessionFactory() {
LocalSessionFactoryBean sessionBean = new LocalSessionFactoryBean();
sessionBean.setDataSource(dataSource);
sessionBean.setPackagesToScan(PACKAGES_TO_SCAN);
sessionBean.setHibernateProperties(hibernateProperties);
return sessionBean;
}
/**
* Create the JPA Vendor adaptor bean that is used in the entity manager factory
* @return jpaVendorAdaptor
*/
@Primary
@Bean
public JpaVendorAdapter eighttrackJpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(false);
hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
return hibernateJpaVendorAdapter;
}
/**
* Create the transaction manager bean
* @return transactionManager
*/
@Primary
@Bean
public PlatformTransactionManager eighttrackTransactionManager() {
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(eighttrackEntityManagerFactory().getObject());
return new JpaTransactionManager();
}
@Bean(name="flyway", initMethod="migrate")
public Flyway flyway() {
FluentConfiguration fc = Flyway.configure();
fc.schemas("eighttrack");
fc.table("_flyway_migration");
fc.locations("database/migration");
fc.outOfOrder(false);
fc.dataSource(flywayDataSource);
return fc.load();
}
}

View File

@ -0,0 +1,162 @@
/**
*
* Project: Eight Track, File: EightTrackDataSource.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.database.config;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.mariadb.jdbc.MariaDbDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import net.locusworks.discord.eighttrack.services.ConfigurationService;
@Primary
@Component
public class EightTrackDataSource {
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JNDI_STRING = "jdbc:mysql://%s:%d%s";
private static Map<String, String> mysqlProperties;
static {
mysqlProperties = new LinkedHashMap<>();
mysqlProperties.put("rewriteBatchedStatements", "true");
mysqlProperties.put("zeroDateTimeBehavior", "CONVERT_TO_NULL");
mysqlProperties.put("useSSL", "false");
mysqlProperties.put("serverTimezone", TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT));
}
private Logger logger = LoggerFactory.getLogger(EightTrackDataSource.class);
@Autowired
private ConfigurationService confService;
/**
* Create the data source bean
* @return the data source bean
* @throws Exception
*/
@Bean
public DataSource dataSource() throws Exception {
return getDataSource(false);
}
@Bean
public DataSource flywayDataSource() throws Exception {
logger.debug("Logging in with flyway for migrations");
String user = confService.getDatabaseRootUsername();
String passwd = confService.getDatabaseRootPassword();
String url = String.format("jdbc:mariadb://%s:%d?user=%s&password=%s",
confService.getDatabaseHost(), confService.getDatabasePort(),
user, passwd);
MariaDbDataSource mariadbDS = new MariaDbDataSource(url);
return mariadbDS;
}
private DataSource getDataSource(Boolean isFlyway) throws Exception {
logger.debug("Gettind datasource");
Class.forName(DRIVER).getDeclaredConstructor().newInstance();
String user = confService.getDatabaseUsername();
String passwd = confService.getDatabasePassword();
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", passwd);
List<String> params = mysqlProperties
.entrySet()
.stream()
.map(prop -> String.format("%s=%s", prop.getKey(), prop.getValue()))
.collect(Collectors.toList());
String host = confService.getDatabaseHost();
int port = confService.getDatabasePort();
String url = String.format(JNDI_STRING, host, port, "/eighttrack");
url = String.format("%s?%s", url, StringUtils.join(params, "&"));
logger.debug("Database connection string: %s", url);
ConnectionFactory cf = new DriverManagerConnectionFactory(url, props);
//Create the poolable connection factory
PoolableConnectionFactory pcf = new PoolableConnectionFactory(cf, null);
pcf.setValidationQuery("SELECT 1");
pcf.setDefaultAutoCommit(true);
GenericObjectPoolConfig<PoolableConnection> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMinIdle(10);
poolConfig.setMaxTotal(100);
AbandonedConfig abandonConfig = new AbandonedConfig();
abandonConfig.setRemoveAbandonedTimeout(60);
abandonConfig.setLogAbandoned(false);
abandonConfig.setRemoveAbandonedOnBorrow(true);
abandonConfig.setRemoveAbandonedOnMaintenance(true);
//Create the pool of connections
GenericObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(pcf, poolConfig);
connectionPool.setTestOnBorrow(true);
connectionPool.setTestWhileIdle(true);
connectionPool.setTimeBetweenEvictionRunsMillis(10000);
connectionPool.setMinEvictableIdleTimeMillis(1000);
connectionPool.setAbandonedConfig(abandonConfig);
pcf.setPool(connectionPool);
//Pooling data source itself
PoolingDataSource<PoolableConnection> dataSource = new PoolingDataSource<>(connectionPool);
return dataSource;
}
}

View File

@ -0,0 +1,145 @@
/**
*
* Project: Eight Track, File: DiscordGuild.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package net.locusworks.discord.eighttrack.database.entities;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
*
* @author isaac
*/
@Entity
@Table(name = "discord_guild", catalog = "eighttrack", schema = "")
@NamedQueries({
@NamedQuery(name = "DiscordGuild.findAll", query = "SELECT d FROM DiscordGuild d")})
public class DiscordGuild implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Long id;
@Basic(optional = false)
@Column(name = "guild_id")
private long guildId;
@Basic(optional = false)
@Column(name = "guild_name")
private String guildName;
@Column(name = "date_joined")
@Temporal(TemporalType.TIMESTAMP)
private Date dateJoined;
public DiscordGuild() {
}
public DiscordGuild(Long id) {
this.id = id;
}
public DiscordGuild(Long id, long guildId, String guildName) {
this.id = id;
this.guildId = guildId;
this.guildName = guildName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public long getGuildId() {
return guildId;
}
public void setGuildId(long guildId) {
this.guildId = guildId;
}
public String getGuildName() {
return guildName;
}
public void setGuildName(String guildName) {
this.guildName = guildName;
}
public Date getDateJoined() {
return dateJoined;
}
public void setDateJoined(Date dateJoined) {
this.dateJoined = dateJoined;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof DiscordGuild)) {
return false;
}
DiscordGuild other = (DiscordGuild) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "net.locusworks.discord.pseudobot.database.entities.DiscordGuild[ id=" + id + " ]";
}
}

View File

@ -0,0 +1,52 @@
/**
*
* Project: Eight Track, File: GuildRepository.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.database.repos;
import java.util.List;
import java.util.Set;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;
import net.locusworks.discord.eighttrack.database.entities.DiscordGuild;
public interface GuildRepository extends CrudRepository<DiscordGuild, Long> {
DiscordGuild findByGuildId(Long serverId);
@Query("SELECT g FROM DiscordGuild g WHERE g.guildId NOT IN ?1")
List<DiscordGuild> findGuildsNoLongerJoined(Set<Long> serverIds);
@Query("DELETE FROM DiscordGuild g WHERE g.guildId NOT IN ?1")
@Modifying
@Transactional
void deleteGuildsNoLongerJoined(Set<Long> guildIds);
}

View File

@ -0,0 +1,127 @@
/**
*
* Project: Eight Track, File: Configuration.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.enums;
public enum Configuration {
DB_ROOT_USER("dbAdmin"),
DB_ROOT_PASSWORD("dbAdminPassword"),
DB_USER("dbUser"),
DB_PASSWORD("dbUserPassword"),
DB_HOST("dbHost"),
DB_PORT("dbPort"),
LOG_LEVEL("logLevel"),
MUSIC_DIR("musicDir"),
DISCORD_TOKEN("discordToken");
private String value;
private Configuration(String value) {
this.value = value;
}
/**
* Get the current value of the enumeration
* @return value
*/
public String getValue() {
return this.value;
}
@Override
public String toString() {
return this.value;
}
/**
* Checks to see if the configuration is of a certain value
* @param confTypes types to check against
* @return true if the current configuration is of a certain enumeration, false otherwise
*/
public boolean is(Configuration... confTypes) {
for (Configuration confType : confTypes) {
if (this == confType) {
return true;
}
}
return false;
}
/**
* Checks to see if the configuration is not of a certain value
* @param confTypes Types to check against
* @return true if the current configuration is not of a certain enuermation, false otherwise
*/
public boolean isNot(Configuration... confTypes) {
return !is(confTypes);
}
/**
* Finds a specific enumeration
* @param value Value to find
* @return the found enumeration or null if nothing is found
*/
public static Configuration findEnum(String value) {
for (Configuration conf: values()) {
if (conf.getValue().equalsIgnoreCase(value)) {
return conf;
}
}
return null;
}
/**
* Checks to see if a specific value is in a set of configuration types
* @param value Value to look for
* @param confTypes types to compare against
* @return true if the string value is in a certain set of configuration enumerations, false otherwise
*/
public static boolean in(String value, Configuration... confTypes) {
Configuration ft = findEnum(value);
if (ft == null) {
return false;
}
for (Configuration confType : confTypes) {
if (ft == confType) {
return true;
}
}
return false;
}
/**
* Checks to see if a specific value is not in a set of configuration types
* @param value Value to look for
* @param confTypes types to compare against
* @return true if the string value is not in a certain set of configuration enumerations, false otherwise
*/
public static boolean notIn(String value, Configuration... confTypes) {
return !in(value, confTypes);
}
}

View File

@ -1,6 +1,6 @@
/**
*
* Project: Eight Track, File: MusicListenerAdaptor.java
* Project: Eight Track, File: DiscordEventHandler.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
@ -25,66 +25,71 @@
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.adaptors;
package net.locusworks.discord.eighttrack.handlers;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.Date;
import javax.annotation.PostConstruct;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
import net.locusworks.discord.eighttrack.database.entities.DiscordGuild;
import net.locusworks.discord.eighttrack.database.repos.GuildRepository;
import net.locusworks.discord.eighttrack.services.ConfigurationService;
import net.locusworks.discord.eighttrack.services.GuildMusicService;
import net.locusworks.logger.ApplicationLogger;
import net.locusworks.logger.ApplicationLoggerFactory;
public class MusicListenerAdaptor extends ListenerAdapter {
@Service
public class DiscordEventHandler extends ListenerAdapter {
private Path musicDir;
private ApplicationLogger logger;
private Map<Long, GuildMusicHandler> playerMap;
private JDA client;
private ApplicationLogger logger = ApplicationLoggerFactory.getLogger(DiscordEventHandler.class);
public MusicListenerAdaptor(Path musicDir, JDA client) throws IOException {
this.logger = ApplicationLoggerFactory.getLogger(MusicListenerAdaptor.class);
this.playerMap = new ConcurrentHashMap<>();
this.musicDir = musicDir;
this.client = client;
@Autowired
private ConfigurationService confService;
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleWithFixedDelay(()->checkPlayers(), 1, 1, TimeUnit.MINUTES);
@Autowired
private GuildRepository guildRepo;
@Autowired
private GuildMusicService musicService;
@Autowired
private Mp3UploadHandler uploadHandler;
@PostConstruct
private void init() throws IOException {
this.musicDir = confService.getMusicDirectory();
if (!Files.exists(this.musicDir.toAbsolutePath())) {
Files.createDirectories(this.musicDir.toAbsolutePath());
}
}
private void checkPlayers() {
logger.debug("Checking players to see if anyone is listening");
OffsetDateTime now = OffsetDateTime.now();
for(Iterator<Entry<Long, GuildMusicHandler>> iterator = playerMap.entrySet().iterator(); iterator.hasNext();) {
Entry<Long, GuildMusicHandler> entry = iterator.next();
GuildMusicHandler gmh = entry.getValue();
long guildId = entry.getKey();
@Override
public void onGuildJoin(GuildJoinEvent event) {
try {
long guildId = event.getGuild().getIdLong();
DiscordGuild discordGuild = guildRepo.findByGuildId(guildId);
if (discordGuild != null) return;
OffsetDateTime lastPlayed = gmh.getLastPlayed();
Duration duration = Duration.between(lastPlayed, now);
if (duration.getSeconds() > 300) {
Guild guild = client.getGuildById(guildId);
if (guild == null) {
iterator.remove();
continue;
}
guild.getAudioManager().closeAudioConnection();
iterator.remove();
}
logger.debug("Joining Server: " + event.getGuild().getName());
discordGuild = new DiscordGuild();
discordGuild.setGuildId(guildId);
discordGuild.setGuildName(event.getGuild().getName());
discordGuild.setDateJoined(new Date());
guildRepo.save(discordGuild);
} catch (Exception ex) {
logger.error("Unable to persist server information to database: " + ex.getMessage(), ex);
}
}
@ -100,13 +105,21 @@ public class MusicListenerAdaptor extends ListenerAdapter {
private void onGuildMessageReceivedHelper(GuildMessageReceivedEvent event) throws IOException {
if (!playerMap.containsKey(event.getGuild().getIdLong())) {
playerMap.put(event.getGuild().getIdLong(), new GuildMusicHandler(musicDir));
if (!musicService.containsKey(event.getGuild().getIdLong())) {
musicService.put(event.getGuild().getIdLong(), new GuildMusicHandler(musicDir, uploadHandler));
}
GuildMusicHandler gmh = playerMap.get(event.getGuild().getIdLong());
gmh.accept((id) -> playerMap.remove(id));
GuildMusicHandler gmh = musicService.get(event.getGuild().getIdLong());
gmh.accept((id) -> musicService.remove(id));
String command = event.getMessage().getContentRaw().trim().toLowerCase();
switch(command) {
case "-upload":
gmh.upload(event);
return;
}
/*
switch (command) {
case "-play":
gmh.isPlaying(true);
@ -132,5 +145,6 @@ public class MusicListenerAdaptor extends ListenerAdapter {
default:
return;
}
*/
}
}

View File

@ -27,6 +27,7 @@
*/
package net.locusworks.discord.eighttrack.handlers;
import java.awt.Color;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -45,6 +46,7 @@ import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.GuildChannel;
import net.dv8tion.jda.api.entities.Message.Attachment;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
@ -66,13 +68,14 @@ public class GuildMusicHandler {
private OffsetDateTime lastPlayed;
private Consumer<Long> callback;
private Mp3UploadHandler uploadHandler;
public GuildMusicHandler(Path musicDir) throws IOException {
public GuildMusicHandler(Path musicDir, Mp3UploadHandler uploadHandler) throws IOException {
this.logger = ApplicationLoggerFactory.getLogger(GuildMusicHandler.class);
this.playing = new AtomicBoolean(false);
this.musicDir = musicDir;
this.lastPlayed = OffsetDateTime.now();
this.uploadHandler = uploadHandler;
this.apm = new DefaultAudioPlayerManager();
AudioSourceManagers.registerLocalSource(apm);
@ -80,7 +83,6 @@ public class GuildMusicHandler {
this.ts = new TrackScheduler();
player.addListener(ts);
indexFiles();
}
public OffsetDateTime getLastPlayed() {
@ -200,4 +202,38 @@ public class GuildMusicHandler {
ts.trackLoaded(track);
}
}
public void upload(GuildMessageReceivedEvent event) {
if (!event.getMessage().getMember().hasPermission(Permission.ADMINISTRATOR, Permission.MANAGE_SERVER)) {
event.getChannel().sendMessage(String.format("Sorry <@%s> i can't do that. *psst: you have to have manage server, or administrator role*", event.getMember().getIdLong())).queue();
return;
}
for(Attachment attachment : event.getMessage().getAttachments()) {
attachment.retrieveInputStream().thenAccept((in) -> {
try {
Mp3UploadResults res = uploadHandler.parse(in);
MessageEmbed embed = new EmbedBuilder()
.setColor(Color.GREEN)
.setTitle("Upload Results")
.setDescription(res.toString())
.setTimestamp(OffsetDateTime.now())
.setFooter(event.getGuild().getSelfMember().getEffectiveName(), event.getGuild().getSelfMember().getUser().getAvatarUrl())
.build();
event.getChannel().sendMessage(embed).queue();
} catch (Exception ex) {
logger.error("Unable to get file information: %s", ex.getMessage());
logger.error(ex);
} finally {
event.getMessage().delete().queue();
}
}).exceptionally((err) ->{
return null;
});
}
}
}

View File

@ -1,3 +1,30 @@
/**
*
* Project: Eight Track, File: Mp3UploadHandler.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.handlers;
import java.io.IOException;
@ -9,23 +36,21 @@ import java.nio.file.Paths;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.mp3.LyricsHandler;
import org.apache.tika.parser.mp3.Mp3Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.springframework.stereotype.Component;
import org.xml.sax.SAXException;
@Component
public class Mp3UploadHandler {
private Path file;
public Mp3UploadHandler(Path file) {
this.file = file;
public Mp3UploadResults parse(Path file) throws IOException {
InputStream is = Files.newInputStream(file);
return parse(is);
}
public void parse() throws IOException, SAXException, TikaException {
InputStream is = Files.newInputStream(file);
public Mp3UploadResults parse(InputStream is) throws IOException {
try {
BodyContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
@ -34,27 +59,18 @@ public class Mp3UploadHandler {
parser.parse(is, handler, metadata, context);
LyricsHandler lyrics = new LyricsHandler(is, handler);
while(lyrics.hasLyrics()) {
System.out.println(lyrics.toString());
}
System.out.println("Contents of the document:" + handler.toString());
System.out.println("Metadata of the document:");
String[] metadataNames = metadata.names();
for(String name : metadataNames) {
System.out.println(name + ": " + metadata.get(name));
return new Mp3UploadResults(metadata);
} catch (Exception ex) {
throw new IOException(ex);
}
}
public static void main(String args[]) throws IOException, SAXException, TikaException {
String file = "S:\\Music\\Alan Walker\\01 Diamond Heart.mp3";
String file = "E:\\Music2\\Alan Walker\\Itinerary_ Dallas.pdf";
Path path = Paths.get(file);
Mp3UploadHandler fuh = new Mp3UploadHandler(path);
fuh.parse();
Mp3UploadHandler fuh = new Mp3UploadHandler();
fuh.parse(path);
}
}

View File

@ -1,15 +1,203 @@
/**
*
* Project: Eight Track, File: Mp3UploadResults.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.handlers;
import org.apache.tika.metadata.Metadata;
public class Mp3UploadResults {
private enum MetaDataField {
GENRE("xmpDM:genre"),
COMPOSER("xmpDM:composer"),
ALBUM("xmpDM:album"),
TRACK_NUMBER("xmpDM:trackNumber"),
DISC_NUMBER("xmpDM:discNumber"),
ARTIST("xmpDM:artist"),
TITLE("title"),
RELEASE_DATE("xmpDM:releaseDate"),
DURATION("xmpDM:duration");
private String value;
private MetaDataField(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}
private String genre;
private String composure;
private String album;
private String trackNumber;
private String discNumber;
private String artist;
private String title;
private String releaseDate;
private Long duration;
public Mp3UploadResults( Metadata metadata) {
parseResults(metadata);
}
private void parseResults(Metadata metadata) {
genre = metadata.get(MetaDataField.GENRE.getValue());
composure = metadata.get(MetaDataField.COMPOSER.getValue());
album = metadata.get(MetaDataField.ALBUM.getValue());
trackNumber = metadata.get(MetaDataField.TRACK_NUMBER.getValue());
discNumber = metadata.get(MetaDataField.DISC_NUMBER.getValue());
artist = metadata.get(MetaDataField.ARTIST.getValue());
title = metadata.get(MetaDataField.TITLE.getValue());
releaseDate = metadata.get(MetaDataField.RELEASE_DATE.getValue());
String durationStr = metadata.get(MetaDataField.DURATION.getValue()).trim();
if (durationStr != null) {
duration = Double.valueOf(metadata.get(MetaDataField.DURATION.getValue())).longValue();
}
}
/**
* @return the genre
*/
public final String getGenre() {
return genre;
}
/**
* @return the composure
*/
public final String getComposure() {
return composure;
}
/**
* @return the album
*/
public final String getAlbum() {
return album;
}
/**
* @return the trackNumber
*/
public final String getTrackNumber() {
return trackNumber;
}
/**
* @return the discNumber
*/
public final String getDiscNumber() {
return discNumber;
}
/**
* @return the artist
*/
public final String getArtist() {
return artist;
}
/**
* @return the title
*/
public final String getTitle() {
return title;
}
/**
* @return the releaseDate
*/
public final String getReleaseDate() {
return releaseDate;
}
/**
* @return the duration
*/
public final Long getDuration() {
return duration;
}
public boolean validFile() {
return getTitle() != null && !getTitle().isEmpty();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("```");
if (getTitle() != null)
sb.append(String.format("%-10s: %s%n", "Title", getTitle()));
if (getArtist() != null)
sb.append(String.format("%-10s: %s%n", "Artist", getArtist()));
if (getAlbum() != null)
sb.append(String.format("%-10s: %s%n", "Album", getAlbum()));
if (getTrackNumber() != null)
sb.append(String.format("%-10s: %s%n", "Track", getTrackNumber()));
if (getDiscNumber() != null)
sb.append(String.format("%-10s: %s%n", "Disc", getDiscNumber()));
if (getReleaseDate() != null)
sb.append(String.format("%-10s: %s%n", "Year", getReleaseDate()));
if (getGenre() != null)
sb.append(String.format("%-10s: %s%n", "Genre", getGenre()));
if (duration != null)
sb.append(String.format("%-10s: %s%n", "Duration", dateFormat(getDuration())));
sb.append("```");
return sb.toString();
}
private String dateFormat(long timeInMilliSeconds) {
long seconds = timeInMilliSeconds / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
long sec = seconds % 60;
long min = minutes % 60;
long hr = hours % 24;
String time = "" + sec;
if (min > 0) time = min + ":" + time;
if (hr > 0) time = hr + ":" + time;
if (days > 0) time = days + ":" + time;
return time;
}
}

View File

@ -1,6 +1,6 @@
/**
*
* Project: Eight Track, File: Entry.java
* Project: Eight Track, File: EightTrackLauncher.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
@ -28,33 +28,53 @@
package net.locusworks.discord.eighttrack.main;
import java.io.IOException;
import java.nio.file.Paths;
import javax.security.auth.login.LoginException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.scheduling.annotation.EnableScheduling;
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.locusworks.discord.eighttrack.adaptors.MusicListenerAdaptor;
import net.locusworks.discord.eighttrack.services.ConfigurationService;
import net.locusworks.discord.eighttrack.services.EightTrackService;
import net.locusworks.logger.ApplicationLogger;
import net.locusworks.logger.ApplicationLoggerFactory;
import net.locusworks.logger.ApplicationLoggerInitializer;
import net.locusworks.logger.LogLevel;
@SpringBootApplication(scanBasePackages = {"net.locusworks.discord.pseudobot"})
@SpringBootApplication(scanBasePackages = {"net.locusworks.discord.eighttrack"})
@EnableAutoConfiguration
@EnableScheduling
public class EightTrackLauncher {
public class EightTrackLauncher implements ApplicationRunner {
@Autowired
private ConfigurationService confService;
@Autowired
private EightTrackService service;
public static void main(String[] args) throws LoginException, IOException {
if (args.length < 1) throw new RuntimeException("no token provided");
new SpringApplicationBuilder(EightTrackLauncher.class).headless(true).run(args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
ApplicationLoggerFactory.init(new ApplicationLoggerInitializer() {
@Override
public LogLevel initialize() {
return LogLevel.getEnum(confService.getLogLevel());
}
});
ApplicationLogger logger = ApplicationLoggerFactory.getLogger(EightTrackLauncher.class);
logger.info("Starting Eight-Track");
JDA client = new JDABuilder(AccountType.BOT).setToken(args[0]).build();
service.begin();
client.addEventListener(new MusicListenerAdaptor(Paths.get(args[1])));
}
}

View File

@ -0,0 +1,74 @@
/**
*
* Project: Eight Track, File: AESService.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.services;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.annotation.PostConstruct;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import net.locusworks.crypto.AES;
@Service
public class AESService {
private AES aes;
@PostConstruct
private void init() throws IOException {
Path keyFile = Paths.get("key.bin");
if (!Files.exists(keyFile)) {
throw new IOException("Unable to find key.bin in local directory");
}
byte[] key = IOUtils.toByteArray(Files.newInputStream(keyFile));
this.aes = AES.createInstance(key);
}
public String encrypt(String plainText) {
return aes.encrypt(plainText);
}
public String decrypt(String encryptedText) {
return aes.decrypt(encryptedText);
}
public static void main(String[] args) throws IOException {
AESService service = new AESService();
service.init();
System.out.println(service.encrypt("zeGAPgbH9HFbqmjRjmwzUDKv"));
}
}

View File

@ -0,0 +1,229 @@
/**
*
* Project: Eight Track, File: ConfigurationService.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.services;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Properties;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.locusworks.crypto.configuration.PropertiesManager;
import net.locusworks.discord.eighttrack.enums.Configuration;
import net.locusworks.logger.ApplicationLogger;
import net.locusworks.logger.ApplicationLoggerFactory;
@Service
public class ConfigurationService {
private Properties configuration;
private Properties defaults = null;
private Path eightTrackConf = null;
private long lastModified = 0;
private static final String PROPERTIES_FILE = "eighttrack.properties";
private static ApplicationLogger logger = ApplicationLoggerFactory.getLogger(ConfigurationService.class);
@Autowired
private AESService aesService;
/**
* Initialize the configuration service
* This happens during server start up
* @throws IOException If the file cannot be read
* @throws Exception any other exception thrown
*/
@PostConstruct
private void init() throws IOException, Exception {
// load defaults when the webapp loads
try {
defaults = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE);
} catch (IOException ex) {
logger.error(String.format("Failed to load default %s: %s", PROPERTIES_FILE, ex.getMessage()));
throw ex;
}
// create portalConf File object
eightTrackConf = Paths.get("conf").resolve(PROPERTIES_FILE);
if (!Files.exists(eightTrackConf.getParent())) {
Files.createDirectories(eightTrackConf.getParent());
}
// initial config load
loadConf();
}
/**
* Load the configuration file
* @throws IOException
*/
private void loadConf() throws IOException {
// load the active config file
// ignore read error, we can continue with an empty configuration map
// and all default items will be added below and the file created
logger.info("Loading config file: " + eightTrackConf);
try {
configuration = PropertiesManager.loadConfiguration(eightTrackConf);
} catch (Exception e) {
logger.info("Config file: " + eightTrackConf + " will be created from template");
configuration = new Properties();
}
Map<String, String> results = PropertiesManager.addConfiguration(configuration, defaults);
boolean changed = !results.isEmpty();
if (!results.isEmpty()) {
logger.info(results, new StringBuilder("Added new configuration items:%n"));
}
results = PropertiesManager.removeConfiguration(configuration, defaults);
changed |= !results.isEmpty();
if (!results.isEmpty()) {
logger.info(results, new StringBuilder("Removed unused configuration items:%n"));
}
if (changed) {
PropertiesManager.saveConfiguration(configuration, eightTrackConf, "Patch Repository properties file");
}
lastModified = Files.getLastModifiedTime(eightTrackConf).toMillis();
}
public String getLogLevel() {
return configuration.getProperty(Configuration.LOG_LEVEL.getValue());
}
/**
* Save the configuration values to file
* @param confs Configuration property values to save
* @throws Exception general exception
*/
public void saveToConf(Properties confs) throws Exception {
PropertiesManager.saveConfiguration(confs, eightTrackConf, "Patch Repository properties file");
logger.info("Saved config file: " + eightTrackConf + ", " + confs.size() + " entries");
loadConf();
}
/**
* Get the database root user name.
* It first checks the catalina.properties file for the root user
* then checks the patchrepo.properties file
* @return root database username
*/
public String getDatabaseRootUsername() {
return configuration.getProperty(Configuration.DB_ROOT_USER.getValue());
}
/**
* Get the database root user password
* It first checks the catalina.properties file for the password
* then checks the patchrepo.properties file.
* The password must be encrypted in both locations
* @return root database password
*/
public String getDatabaseRootPassword() {
String dbPasswd = configuration.getProperty(Configuration.DB_ROOT_PASSWORD.getValue());
try {
return aesService.decrypt(dbPasswd);
} catch (Exception ex) {
logger.error("Unable to get db root password " + ex.getMessage());
return null;
}
}
/**
* Get the standard database user name
* @return portal database username
*/
public String getDatabaseUsername() {
return configuration.getProperty(Configuration.DB_USER.getValue());
}
/**
* Get the standard database password.
* The password is encrypted in the properties file
* @return patchrepo database password
*/
public String getDatabasePassword() {
String dbPasswd = configuration.getProperty(Configuration.DB_PASSWORD.getValue());
try {
return aesService.decrypt(dbPasswd);
} catch (Exception ex) {
logger.error("Unable to get db password " + ex.getMessage());
return null;
}
}
/**
* Get the database host url
* @return database host url
*/
public String getDatabaseHost() {
return configuration.getProperty(Configuration.DB_HOST.getValue());
}
/**
* Get the database host port
* @return the database port
*/
public Integer getDatabasePort() {
return Integer.parseInt(configuration.getProperty(Configuration.DB_PORT.getValue()));
}
/**
* Get the discord token
* @return discord token
*/
public String getDiscordToken() {
String token = configuration.getProperty(Configuration.DISCORD_TOKEN.getValue(), "");
return token;
}
public Path getMusicDirectory() {
String dir = configuration.getProperty(Configuration.MUSIC_DIR.getValue(), "");
return Paths.get(dir);
}
/**
* Get the last time the configuration file was modified
* @return last modified
*/
public long getLastModified() {
return lastModified;
}
}

View File

@ -0,0 +1,113 @@
/**
*
* Project: Eight Track, File: DatabaseCleanupService.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.services;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Iterator;
import java.util.Set;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.locusworks.discord.eighttrack.database.repos.GuildRepository;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
@Service
public class DatabaseCleanupService {
private static final long SECOND = 1000;
private static final long MINUTE = 60 * SECOND;
private static final long HOUR = 60 * MINUTE;
private static final long DAY = 24 * HOUR;
private Logger logger = LoggerFactory.getLogger(DatabaseCleanupService.class);
@Autowired
private GuildRepository guildRepo;
@Autowired
private GuildMusicService musicService;
private JDA client;
public void setClient(JDA client) {
this.client = client;
}
@Scheduled(fixedRate = 5 * MINUTE)
private void checkPlayers() {
if (client == null) {
logger.warn("Discord client is null. Unable to do cleanup");
return;
}
logger.debug("Checking players to see if anyone is listening");
OffsetDateTime now = OffsetDateTime.now();
for(Iterator<Entry<Long, GuildMusicHandler>> iterator = musicService.entrySet().iterator(); iterator.hasNext();) {
Entry<Long, GuildMusicHandler> entry = iterator.next();
GuildMusicHandler gmh = entry.getValue();
long guildId = entry.getKey();
OffsetDateTime lastPlayed = gmh.getLastPlayed();
Duration duration = Duration.between(lastPlayed, now);
if (duration.getSeconds() > 300) {
Guild guild = client.getGuildById(guildId);
if (guild == null) {
iterator.remove();
continue;
}
guild.getAudioManager().closeAudioConnection();
iterator.remove();
}
}
}
@Scheduled(fixedRate = DAY)
private void cleanDatabase() {
if (client == null) {
logger.warn("Discord client is null. Unable to do cleanup");
return;
}
Set<Long> currentGuildsIds = client.getSelfUser().getMutualGuilds().stream().map(guild -> guild.getIdLong()).collect(Collectors.toSet());
try {
guildRepo.deleteGuildsNoLongerJoined(currentGuildsIds);
} catch (Exception ex) {
logger.error("Unable to clean up servers: " + ex.getMessage());
}
}
}

View File

@ -0,0 +1,69 @@
/**
*
* Project: Eight Track, File: EightTrackService.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.services;
import javax.security.auth.login.LoginException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.locusworks.discord.eighttrack.handlers.DiscordEventHandler;
import net.locusworks.logger.ApplicationLogger;
import net.locusworks.logger.ApplicationLoggerFactory;
@Service
public class EightTrackService {
private ApplicationLogger logger = ApplicationLoggerFactory.getLogger(EightTrackService.class);
private JDA client;
@Autowired
private ConfigurationService confService;
@Autowired
private DiscordEventHandler eventListener;
@Autowired
private DatabaseCleanupService dcs;
public void begin() throws LoginException {
String token = confService.getDiscordToken();
logger.debug("Logging in with token %s", token);
client = new JDABuilder(AccountType.BOT).setToken(token).build();
client.addEventListener(eventListener);
dcs.setClient(client);
}
}

View File

@ -0,0 +1,41 @@
/**
*
* Project: Eight Track, File: GuildMusicService.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.services;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Service;
import net.locusworks.discord.eighttrack.handlers.GuildMusicHandler;
@Service
public class GuildMusicService extends ConcurrentHashMap<Long, GuildMusicHandler> {
private static final long serialVersionUID = -120204711554552975L;
}

View File

@ -13,11 +13,11 @@ BEGIN
DECLARE foo BIGINT DEFAULT 0;
SELECT COUNT(*) INTO foo FROM mysql.user WHERE User = 'eighttrackAdmin' and Host = 'localhost';
IF foo = 0 THEN
CREATE USER 'eighttrackAdmin'@'localhost' IDENTIFIED BY 'eighttrackAdmin2017!';
CREATE USER 'eighttrackAdmin'@'localhost' IDENTIFIED BY 'zeGAPgbH9HFbqmjRjmwzUDKv';
END IF;
SELECT COUNT(*) INTO foo FROM mysql.user WHERE User = 'eighttrackAdmin' and Host = '%';
IF foo = 0 THEN
CREATE USER 'eighttrackAdmin'@'%' IDENTIFIED BY 'eighttrackAdmin2017!';
CREATE USER 'eighttrackAdmin'@'%' IDENTIFIED BY 'zeGAPgbH9HFbqmjRjmwzUDKv';
END IF;
END ;$$
@ -29,6 +29,6 @@ DROP PROCEDURE set_optimizer_switch_on;
CALL create_user();
DROP PROCEDURE create_user;
GRANT SELECT,INSERT,UPDATE,DELETE ON pseudobot.* TO 'eighttrackAdmin'@'localhost';
GRANT SELECT,INSERT,UPDATE,DELETE ON pseudobot.* TO 'eighttrackAdmin'@'%';
GRANT SELECT,INSERT,UPDATE,DELETE ON eighttrack.* TO 'eighttrackAdmin'@'localhost';
GRANT SELECT,INSERT,UPDATE,DELETE ON eighttrack.* TO 'eighttrackAdmin'@'%';
FLUSH PRIVILEGES;

View File

@ -0,0 +1,10 @@
dbAdmin=root
dbAdminPassword=gSkjsvZbQTQtogOrPYqorCuuzp4WUpGFVtPYtMVj47U=
dbUser=eighttrackAdmin
dbUserPassword=RaamWDMgA2p09R3kAiKHqauu6mmKU2HLQ4nAfEGMNOs=
dbHost=devops.locusworks.net
dbPort=3306
logLevel=INFO
musicDir=E:/Music
discordToken=NjI5MTQ0OTk1ODA2MzE0NTA5.XZVlRQ.7hiB0u4Zp5pxPrPfvdOdyr4TCh4

View File

@ -3,7 +3,6 @@
<Configuration status="WARN" shutdownHook="disable"
packages="net.locusworks.discord.eighttrack">
<Properties>
<property name="logLevel">${sys:LOG_LEVEL:-INFO}</property>
<Property name="logFormat">%d{dd-MMM-yyyy HH:mm:ss.SSS} [%-5p] [%c{1}] %m%n</Property>
</Properties>
<Appenders>
@ -11,8 +10,8 @@
<PatternLayout pattern="${logFormat}" />
</Console>
<RollingFile name="eighttrack"
fileName="eighttrack.log"
filePattern="eighttrack-%d{yyyy-MM-dd}.log.gz">
fileName="logs/eighttrack.log"
filePattern="logs/eighttrack-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="${logFormat}" />
<Policies>
<TimeBasedTriggeringPolicy />
@ -22,8 +21,8 @@
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="ConsoleAppender" level="${logLevel}" />
<AppenderRef ref="eighttrack" level="${logLevel}" />
<AppenderRef ref="ConsoleAppender" level="INFO" />
<AppenderRef ref="eighttrack" level="INFO" />
</Root>
</Loggers>
</Configuration>