Migrate to fly.io, add Genre type
This commit is contained in:
@@ -37,16 +37,17 @@ import { RedisModule, RedisModuleOptions } from '@liaoliaots/nestjs-redis';
|
||||
RedisModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService): Promise<RedisModuleOptions> => {
|
||||
useFactory: async (
|
||||
configService: ConfigService,
|
||||
): Promise<RedisModuleOptions> => {
|
||||
return {
|
||||
config: {
|
||||
host: configService.get<string>('redis.host'),
|
||||
port: configService.get<number>('redis.port'),
|
||||
password: configService.get<string>('redis.password'),
|
||||
url: configService.get<string>('redis.url'),
|
||||
db: configService.get<number>('redis.db'),
|
||||
}
|
||||
family: 6,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
}),
|
||||
CacheModule.registerAsync<RedisClientOptions>({
|
||||
isGlobal: true,
|
||||
@@ -54,12 +55,9 @@ import { RedisModule, RedisModuleOptions } from '@liaoliaots/nestjs-redis';
|
||||
imports: [ConfigModule],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
store: redisStore,
|
||||
socket: {
|
||||
host: configService.get<string>('redis.host'),
|
||||
port: configService.get<number>('redis.port'),
|
||||
},
|
||||
url: configService.get<string>('redis.url'),
|
||||
family: 6,
|
||||
database: configService.get<number>('redis.db'),
|
||||
password: configService.get<string>('redis.password'),
|
||||
}),
|
||||
}),
|
||||
BullModule.forRootAsync({
|
||||
@@ -68,10 +66,9 @@ import { RedisModule, RedisModuleOptions } from '@liaoliaots/nestjs-redis';
|
||||
useFactory: async (configService: ConfigService) => {
|
||||
const config = {
|
||||
redis: {
|
||||
password: configService.get<string>('redis.password'),
|
||||
host: configService.get<string>('redis.host'),
|
||||
port: configService.get<number>('redis.port'),
|
||||
url: configService.get<string>('redis.url'),
|
||||
db: configService.get<number>('redis.db'),
|
||||
family: 6,
|
||||
},
|
||||
};
|
||||
return config;
|
||||
@@ -103,4 +100,4 @@ import { RedisModule, RedisModuleOptions } from '@liaoliaots/nestjs-redis';
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule { }
|
||||
export class AppModule {}
|
||||
|
@@ -7,7 +7,7 @@ export default () => ({
|
||||
userAgent: 'api.us.dev/@chip@talking.dev',
|
||||
rapidApiKey: process.env.RAPID_API_KEY || '',
|
||||
irc: {
|
||||
enabled: process.env.IRC_SERVER === "" ? false : true,
|
||||
enabled: process.env.IRC_SERVER === '' ? false : true,
|
||||
server: process.env.IRC_SERVER,
|
||||
tls: process.env.IRC_TLS === 'true',
|
||||
port: parseInt(process.env.IRC_PORT ?? '6697'),
|
||||
@@ -19,19 +19,22 @@ export default () => ({
|
||||
: 'us-dev',
|
||||
},
|
||||
redis: {
|
||||
host: process.env.REDIS_HOST ?? 'redis-master',
|
||||
port: parseInt(process.env.REDIS_PORT ?? '6379'),
|
||||
password: process.env.REDIS_PASS ?? '',
|
||||
url: process.env.REDIS_URL ?? '',
|
||||
db: parseInt(process.env.REDIS_DB ?? '1'),
|
||||
},
|
||||
file: {
|
||||
bucketName: process.env.FILE_BUCKET_NAME ?? process.env.S3_BUCKET ?? 'api.us.dev-files',
|
||||
bucketName:
|
||||
process.env.FILE_BUCKET_NAME ??
|
||||
process.env.S3_BUCKET ??
|
||||
'api.us.dev-files',
|
||||
// default file ttl in seconds
|
||||
defaultTtl: parseInt(process.env.FILE_DEFAULT_TTL ?? (30 * 24 * 60 * 60).toString()),
|
||||
defaultTtl: parseInt(
|
||||
process.env.FILE_DEFAULT_TTL ?? (30 * 24 * 60 * 60).toString(),
|
||||
),
|
||||
},
|
||||
focoLive: {
|
||||
airtable: {
|
||||
apiKey: process.env.FOCO_LIVE_AIRTABLE_APIKEY ?? '',
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@@ -11,116 +11,142 @@ import { Gauge } from 'prom-client';
|
||||
import { filter, pipe } from 'ramda';
|
||||
|
||||
const tables = {
|
||||
venues: 'tblRi4wDorKqNJJbs',
|
||||
events: 'tbl4RZ75QF5WefE7L',
|
||||
}
|
||||
venues: 'tblRi4wDorKqNJJbs',
|
||||
events: 'tbl4RZ75QF5WefE7L',
|
||||
};
|
||||
|
||||
const compareDates = (a: any, b: any) => new Date(a.Date).getTime() - new Date(b.Date).getTime();
|
||||
const compareDates = (a: any, b: any) =>
|
||||
new Date(a.Date).getTime() - new Date(b.Date).getTime();
|
||||
|
||||
const beforeFilter = (before?: Date) => (a: Event) => before ? new Date(a.Date) <= before : true;
|
||||
const afterFilter = (after?: Date) => (a: Event) => after ? new Date(a.Date) >= after : true;
|
||||
const beforeFilter = (before?: Date) => (a: Event) =>
|
||||
before ? new Date(a.Date) <= before : true;
|
||||
const afterFilter = (after?: Date) => (a: Event) =>
|
||||
after ? new Date(a.Date) >= after : true;
|
||||
|
||||
export interface Event {
|
||||
"Date": string,
|
||||
"Music Start Time": string,
|
||||
"Bar or Venue Name": string,
|
||||
"Band/DJ/Musician Name": string,
|
||||
"Cost Select": string;
|
||||
Cost: string,
|
||||
"Date Select": string
|
||||
'"Specials" at Venue': string,
|
||||
id: string;
|
||||
Date: string;
|
||||
'Music Start Time': string;
|
||||
'Bar or Venue Name': string;
|
||||
'Band/DJ/Musician Name': string;
|
||||
'Cost Select': string;
|
||||
Cost: string;
|
||||
'Date Select': string;
|
||||
'"Specials" at Venue': string;
|
||||
Genre?: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Venue {
|
||||
id: string;
|
||||
"Bar or Venue Name": string,
|
||||
"Street Address": string,
|
||||
"City": string,
|
||||
"Zip Code": number,
|
||||
State: string,
|
||||
"Phone Number": string,
|
||||
Website: string,
|
||||
"Has Calendar Of Events": string,
|
||||
"Facebook Page": string,
|
||||
"Instagram": string,
|
||||
"Twitter Account": string,
|
||||
id: string;
|
||||
'Bar or Venue Name': string;
|
||||
'Street Address': string;
|
||||
City: string;
|
||||
'Zip Code': number;
|
||||
State: string;
|
||||
'Phone Number': string;
|
||||
Website: string;
|
||||
'Has Calendar Of Events': string;
|
||||
'Facebook Page': string;
|
||||
Instagram: string;
|
||||
'Twitter Account': string;
|
||||
}
|
||||
|
||||
const cacheKeys = {
|
||||
allEvents: 'foco_live_events',
|
||||
allVenues: 'foco_live_venues',
|
||||
}
|
||||
allEvents: 'foco_live_events',
|
||||
allVenues: 'foco_live_venues',
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class FocoLiveService {
|
||||
private readonly airtableBase: AirtableBase;
|
||||
private readonly logger = new Logger(FocoLiveService.name);
|
||||
private readonly airtableBase: AirtableBase;
|
||||
private readonly logger = new Logger(FocoLiveService.name);
|
||||
|
||||
constructor(
|
||||
private readonly config: ConfigService,
|
||||
@InjectMetric('event_count') public eventCount: Gauge<string>,
|
||||
@InjectMetric('event_cache_misses') public cacheMisses: Gauge<string>,
|
||||
@Inject(CACHE_MANAGER) private cacheManager: Cache
|
||||
) {
|
||||
this.airtableBase = new Airtable({
|
||||
apiKey: config.get('focoLive.airtable.apiKey'),
|
||||
}).base('app1SjPrn5qrhr59J');
|
||||
}
|
||||
constructor(
|
||||
private readonly config: ConfigService,
|
||||
@InjectMetric('event_count') public eventCount: Gauge<string>,
|
||||
@InjectMetric('event_cache_misses') public cacheMisses: Gauge<string>,
|
||||
@Inject(CACHE_MANAGER) private cacheManager: Cache,
|
||||
) {
|
||||
this.airtableBase = new Airtable({
|
||||
apiKey: config.get('focoLive.airtable.apiKey'),
|
||||
}).base('app1SjPrn5qrhr59J');
|
||||
}
|
||||
|
||||
async getAllEvents(): Promise<Event[]> {
|
||||
return ((await this.airtableBase('Events').select({
|
||||
view: "Grid view",
|
||||
}).all())
|
||||
.map(record => ({
|
||||
id: record.id,
|
||||
...record.fields
|
||||
})) as any as Event[])
|
||||
.sort(compareDates)
|
||||
.reverse();
|
||||
}
|
||||
async getAllEvents(): Promise<Event[]> {
|
||||
return (
|
||||
(
|
||||
await this.airtableBase('Events')
|
||||
.select({
|
||||
view: 'Grid view',
|
||||
})
|
||||
.all()
|
||||
).map((record) => ({
|
||||
id: record.id,
|
||||
...record.fields,
|
||||
})) as any as Event[]
|
||||
)
|
||||
.sort(compareDates)
|
||||
.reverse();
|
||||
}
|
||||
|
||||
async getAllEventsCached(): Promise<Event[]> {
|
||||
let events: Event[] | null | undefined = await this.cacheManager.get(cacheKeys.allEvents);
|
||||
if (!events) {
|
||||
events = await this.getAllEvents();
|
||||
this.cacheMisses.inc();
|
||||
this.cacheManager.set(cacheKeys.allEvents, events, 10 * 60 * 1000);
|
||||
}
|
||||
this.eventCount.set(events.length);
|
||||
return events;
|
||||
async getAllEventsCached(): Promise<Event[]> {
|
||||
let events: Event[] | null | undefined = await this.cacheManager.get(
|
||||
cacheKeys.allEvents,
|
||||
);
|
||||
if (!events) {
|
||||
events = await this.getAllEvents();
|
||||
this.cacheMisses.inc();
|
||||
this.cacheManager.set(cacheKeys.allEvents, events, 10 * 60 * 1000);
|
||||
}
|
||||
this.eventCount.set(events.length);
|
||||
return events;
|
||||
}
|
||||
|
||||
async getAllVenues(): Promise<Venue[]> {
|
||||
return ((await this.airtableBase('Venues').select({
|
||||
view: "Grid view",
|
||||
}).all())
|
||||
.map(record => ({
|
||||
id: record.id,
|
||||
...record.fields
|
||||
})) as any as Venue[])
|
||||
.sort(compareDates)
|
||||
.reverse();
|
||||
}
|
||||
async getAllVenues(): Promise<Venue[]> {
|
||||
return (
|
||||
(
|
||||
await this.airtableBase('Venues')
|
||||
.select({
|
||||
view: 'Grid view',
|
||||
})
|
||||
.all()
|
||||
).map((record) => ({
|
||||
id: record.id,
|
||||
...record.fields,
|
||||
})) as any as Venue[]
|
||||
)
|
||||
.sort(compareDates)
|
||||
.reverse();
|
||||
}
|
||||
|
||||
async getAllVenuesCached(): Promise<Venue[]> {
|
||||
return await this.cacheManager.get(cacheKeys.allVenues) || await this.getAllVenues();
|
||||
}
|
||||
async getAllVenuesCached(): Promise<Venue[]> {
|
||||
return (
|
||||
(await this.cacheManager.get(cacheKeys.allVenues)) ||
|
||||
(await this.getAllVenues())
|
||||
);
|
||||
}
|
||||
|
||||
@Cron("0 */5 * * * *")
|
||||
async refreshEvents() {
|
||||
this.logger.verbose("Refreshing events cache.");
|
||||
await this.getAllEventsCached();
|
||||
}
|
||||
@Cron('0 */5 * * * *')
|
||||
async refreshEvents() {
|
||||
this.logger.verbose('Refreshing events cache.');
|
||||
await this.getAllEventsCached();
|
||||
}
|
||||
|
||||
async getEvents(options: { venue?: string, before?: Date, after?: Date } = {}) {
|
||||
const events = await this.getAllEventsCached();
|
||||
const results = pipe(
|
||||
filter((a: Event) => a["Bar or Venue Name"] === (options.venue ?? a["Bar or Venue Name"])),
|
||||
filter(beforeFilter(options.before)),
|
||||
filter(afterFilter(options.after)),
|
||||
)(events);
|
||||
this.logger.verbose(`Returning ${results.length} events, ${events.length} total events in database.`);
|
||||
return results
|
||||
}
|
||||
async getEvents(
|
||||
options: { venue?: string; before?: Date; after?: Date } = {},
|
||||
) {
|
||||
const events = await this.getAllEventsCached();
|
||||
const results = pipe(
|
||||
filter(
|
||||
(a: Event) =>
|
||||
a['Bar or Venue Name'] === (options.venue ?? a['Bar or Venue Name']),
|
||||
),
|
||||
filter(beforeFilter(options.before)),
|
||||
filter(afterFilter(options.after)),
|
||||
)(events);
|
||||
this.logger.verbose(
|
||||
`Returning ${results.length} events, ${events.length} total events in database.`,
|
||||
);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ export class MinioService {
|
||||
useSSL: this.configService.get<string>('S3_USE_SSL', 'true') === 'true',
|
||||
accessKey: this.configService.get<string>('S3_ACCESS_KEY', ''),
|
||||
secretKey: this.configService.get<string>('S3_SECRET_KEY', ''),
|
||||
region: this.configService.get<string>('S3_REGION', 'auto'),
|
||||
});
|
||||
this.defaultBucketName = this.configService.get<string>('S3_BUCKET', '');
|
||||
}
|
||||
|
Reference in New Issue
Block a user