featureflag for DisableVoice & DontMarkQuestsion
This commit is contained in:
parent
9e4f5e13c0
commit
59f32b94d9
9 changed files with 55 additions and 18 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
export class FeatureFlagsConsts {
|
export class FeatureFlagsConsts {
|
||||||
static EnableEndgamePoints = 'EnableEndgamePoints';
|
static EnableEndgamePoints = 'EnableEndgamePoints';
|
||||||
|
static DontMarkQuestionsAsCompleted = 'DontMarkQuestionsAsCompleted';
|
||||||
|
static DisableVoice = 'DisableVoice';
|
||||||
}
|
}
|
||||||
|
|
@ -45,6 +45,6 @@ import { FeatureflagService } from './featureflag/featureflag.service';
|
||||||
],
|
],
|
||||||
controllers: [AppController, FeatureflagController],
|
controllers: [AppController, FeatureflagController],
|
||||||
providers: [AppService, SocketGateway, SchedulerService, FeatureflagService],
|
providers: [AppService, SocketGateway, SchedulerService, FeatureflagService],
|
||||||
exports: [AppService, SocketGateway],
|
exports: [AppService, SocketGateway, FeatureflagService],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {Injectable, Logger} from '@nestjs/common';
|
import {Injectable, Logger} from '@nestjs/common';
|
||||||
import {SharedService} from "../shared/shared.service";
|
import {SharedService} from "../shared/shared.service";
|
||||||
|
import {SocketEvents} from "../shared/events.consts";
|
||||||
|
|
||||||
export interface IFeatureFlagStatus {
|
export interface IFeatureFlagStatus {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -13,17 +14,25 @@ export class FeatureflagService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFeatureFlag(id: string): Promise<IFeatureFlagStatus> {
|
async getFeatureFlag(id: string): Promise<IFeatureFlagStatus> {
|
||||||
this.logger.verbose(`Getting feature flag status for ${id}`);
|
this.logger.verbose(`[getFeatureFlag] Getting feature flag status for ${id}`);
|
||||||
const state = await this.sharedService.getConfig(`featureflag/${id}`);
|
const configRecord = await this.sharedService.getConfig(`featureflag/${id}`);
|
||||||
|
let ffState;
|
||||||
|
if(!configRecord) {
|
||||||
|
ffState = false;
|
||||||
|
} else {
|
||||||
|
ffState = configRecord.value !== 'false'
|
||||||
|
}
|
||||||
|
this.logger.verbose(`[getFeatureFlag] Feature flag status for ${id} is ${ffState}`);
|
||||||
return {
|
return {
|
||||||
name: id,
|
name: id,
|
||||||
state: state.value !== 'false',
|
state: ffState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setFeatureFlag(id: string, status: boolean) : Promise<IFeatureFlagStatus> {
|
async setFeatureFlag(id: string, status: boolean) : Promise<IFeatureFlagStatus> {
|
||||||
this.logger.verbose(`Setting feature flag status for ${id} to ${status} `);
|
this.logger.verbose(`Setting feature flag status for ${id} to ${status} `);
|
||||||
const result = await this.sharedService.setConfig(`featureflag/${id}`, status.toString());
|
const result = await this.sharedService.setConfig(`featureflag/${id}`, status.toString());
|
||||||
|
this.sharedService.sendSocketNotificationToAllClients(SocketEvents.FEATURE_FLAG_CHANGED, {});
|
||||||
return {
|
return {
|
||||||
name: id,
|
name: id,
|
||||||
state: result.value !== 'false',
|
state: result.value !== 'false',
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.
|
||||||
import {GameQueueTypes} from "../schemas/game-queue.schema";
|
import {GameQueueTypes} from "../schemas/game-queue.schema";
|
||||||
import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player-winning-rate.command";
|
import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player-winning-rate.command";
|
||||||
import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command";
|
import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command";
|
||||||
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
|
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
||||||
|
|
||||||
@Injectable({ scope: Scope.TRANSIENT })
|
@Injectable({ scope: Scope.TRANSIENT })
|
||||||
export class QuizService {
|
export class QuizService {
|
||||||
|
|
@ -30,6 +32,7 @@ export class QuizService {
|
||||||
private sharedService: SharedService,
|
private sharedService: SharedService,
|
||||||
private eventBus: EventBus,
|
private eventBus: EventBus,
|
||||||
private commandBus: CommandBus,
|
private commandBus: CommandBus,
|
||||||
|
private featureFlagService: FeatureflagService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +57,6 @@ export class QuizService {
|
||||||
async validateAnswer(answer: string, id: number) {
|
async validateAnswer(answer: string, id: number) {
|
||||||
this.logger.verbose(`enter validate answer ${answer} ${id}`);
|
this.logger.verbose(`enter validate answer ${answer} ${id}`);
|
||||||
const question = await this.get();
|
const question = await this.get();
|
||||||
//question.answered = true;
|
|
||||||
await question.save();
|
await question.save();
|
||||||
const regexp = new RegExp(
|
const regexp = new RegExp(
|
||||||
Object.keys(this.answerNumbers)
|
Object.keys(this.answerNumbers)
|
||||||
|
|
@ -82,7 +84,6 @@ export class QuizService {
|
||||||
await question.save();
|
await question.save();
|
||||||
this.logger.verbose("question saved with user details")
|
this.logger.verbose("question saved with user details")
|
||||||
if (question.valid === filtered) {
|
if (question.valid === filtered) {
|
||||||
//question.answered = true;
|
|
||||||
question.answeredBy = id;
|
question.answeredBy = id;
|
||||||
this.logger.verbose(`extra ${question.note}`);
|
this.logger.verbose(`extra ${question.note}`);
|
||||||
this.eventBus.publish(
|
this.eventBus.publish(
|
||||||
|
|
@ -126,6 +127,11 @@ export class QuizService {
|
||||||
|
|
||||||
private async calculateScore() {
|
private async calculateScore() {
|
||||||
const question = await this.get();
|
const question = await this.get();
|
||||||
|
if(!await this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.DontMarkQuestionsAsCompleted)) {
|
||||||
|
this.logger.verbose(`[proceedWithGame]: DontMarkQuestionsAsCompleted disabled, marking as complete`);
|
||||||
|
question.answered = true;
|
||||||
|
await question.save();
|
||||||
|
}
|
||||||
this.logger.verbose(`[calculateScore] enter `);
|
this.logger.verbose(`[calculateScore] enter `);
|
||||||
const playerAnswers = question.userAnswers.map((answer) => {
|
const playerAnswers = question.userAnswers.map((answer) => {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,5 @@ export enum SocketEvents {
|
||||||
GAME_PAUSED = 'game_paused',
|
GAME_PAUSED = 'game_paused',
|
||||||
GAME_RESUMED = 'game_resumed',
|
GAME_RESUMED = 'game_resumed',
|
||||||
NOTIFICATION = 'notification',
|
NOTIFICATION = 'notification',
|
||||||
|
FEATURE_FLAG_CHANGED = 'feature_flag_changed',
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { ClientProxyFactory, Transport } from '@nestjs/microservices';
|
||||||
import * as process from "process";
|
import * as process from "process";
|
||||||
import {ConfigModule} from "@nestjs/config";
|
import {ConfigModule} from "@nestjs/config";
|
||||||
import {CqrsModule} from "@nestjs/cqrs";
|
import {CqrsModule} from "@nestjs/cqrs";
|
||||||
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
@ -17,7 +18,7 @@ import {CqrsModule} from "@nestjs/cqrs";
|
||||||
GameModule,
|
GameModule,
|
||||||
MongooseModule.forFeature([{ name: Config.name, schema: ConfigSchema }]),
|
MongooseModule.forFeature([{ name: Config.name, schema: ConfigSchema }]),
|
||||||
],
|
],
|
||||||
providers: [SharedService, {
|
providers: [SharedService,FeatureflagService, {
|
||||||
provide: 'Telegram',
|
provide: 'Telegram',
|
||||||
useFactory: () =>
|
useFactory: () =>
|
||||||
ClientProxyFactory.create({
|
ClientProxyFactory.create({
|
||||||
|
|
@ -31,7 +32,7 @@ import {CqrsModule} from "@nestjs/cqrs";
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}],
|
}],
|
||||||
exports: [SharedService, 'Telegram'],
|
exports: [SharedService, 'Telegram',FeatureflagService],
|
||||||
})
|
})
|
||||||
export class SharedModule {
|
export class SharedModule {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ export class SharedService {
|
||||||
key,
|
key,
|
||||||
})
|
})
|
||||||
.exec();
|
.exec();
|
||||||
|
if(!res) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
key: res.key,
|
key: res.key,
|
||||||
value: res.value,
|
value: res.value,
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,39 @@
|
||||||
import { Controller, Get, Header, NotFoundException, Query, StreamableFile } from '@nestjs/common';
|
import {Controller, Get, Header, Logger, NotFoundException, Query, StreamableFile} from '@nestjs/common';
|
||||||
import { VoiceService } from './voice.service';
|
import { VoiceService } from './voice.service';
|
||||||
import { TtsRequestDto, TtsRequestWithVars } from './models/TtsRequestDto';
|
import { TtsRequestDto, TtsRequestWithVars } from './models/TtsRequestDto';
|
||||||
import { invalidPrefixDict } from './dicts/invalid-prefix.dict';
|
import { invalidPrefixDict } from './dicts/invalid-prefix.dict';
|
||||||
import { validPrefixDict } from './dicts/valid-prefix.dict';
|
import { validPrefixDict } from './dicts/valid-prefix.dict';
|
||||||
import * as translit from 'latin-to-cyrillic';
|
import * as translit from 'latin-to-cyrillic';
|
||||||
import {ConfigService} from "@nestjs/config";
|
import {ConfigService} from "@nestjs/config";
|
||||||
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
|
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
|
||||||
@Controller('voice')
|
@Controller('voice')
|
||||||
export class VoiceController {
|
export class VoiceController {
|
||||||
constructor(private voiceService: VoiceService, private configService: ConfigService) {}
|
private voiceEnabled = false;
|
||||||
|
private logger = new Logger(VoiceController.name)
|
||||||
|
constructor(private voiceService: VoiceService, private configService: ConfigService,private featureFlagService: FeatureflagService) {
|
||||||
|
setInterval(() => {
|
||||||
|
this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.DisableVoice).then(r => this.voiceEnabled = !r.state);
|
||||||
|
}, 30000);
|
||||||
|
this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.DisableVoice).then(r => {
|
||||||
|
this.voiceEnabled = !r.state;
|
||||||
|
console.log(`Voice enabled: ${this.voiceEnabled}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Get('ssml')
|
@Get('ssml')
|
||||||
@Header('content-type', 'audio/opus')
|
@Header('content-type', 'audio/opus')
|
||||||
@Header('content-disposition', 'inline')
|
@Header('content-disposition', 'inline')
|
||||||
async textToSpeechSSML(@Query() dto: TtsRequestDto) {
|
async textToSpeechSSML(@Query() dto: TtsRequestDto) {
|
||||||
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
|
this.logger.verbose(`[textToSpeechSSML] enter, FF state is: ${this.voiceEnabled}`);
|
||||||
//return new StreamableFile(await this.voiceService.textToFile(dto, true));
|
if (this.voiceEnabled) {
|
||||||
|
return new StreamableFile(await this.voiceService.textToFile(dto, true));
|
||||||
} else {
|
} else {
|
||||||
return new NotFoundException('Voice disabled');
|
return new NotFoundException('Voice disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('tts')
|
@Get('tts')
|
||||||
|
|
@ -26,8 +41,8 @@ export class VoiceController {
|
||||||
@Header('content-disposition', 'inline')
|
@Header('content-disposition', 'inline')
|
||||||
async getText(@Query() dto: TtsRequestDto) {
|
async getText(@Query() dto: TtsRequestDto) {
|
||||||
dto.text = translit(dto.text);
|
dto.text = translit(dto.text);
|
||||||
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
|
if (this.voiceEnabled) {
|
||||||
//return new StreamableFile(await this.voiceService.textToFile(dto));
|
return new StreamableFile(await this.voiceService.textToFile(dto));
|
||||||
} else {
|
} else {
|
||||||
return new NotFoundException('Voice disabled');
|
return new NotFoundException('Voice disabled');
|
||||||
}
|
}
|
||||||
|
|
@ -36,8 +51,7 @@ export class VoiceController {
|
||||||
@Header('content-type', 'audio/opus')
|
@Header('content-type', 'audio/opus')
|
||||||
@Header('content-disposition', 'inline')
|
@Header('content-disposition', 'inline')
|
||||||
async announceValid(@Query() dto: TtsRequestWithVars) {
|
async announceValid(@Query() dto: TtsRequestWithVars) {
|
||||||
console.log(this.configService.get<boolean>('ENABLE_VOICE'));
|
if (this.voiceEnabled) {
|
||||||
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
|
|
||||||
const vars = JSON.parse(dto.vars);
|
const vars = JSON.parse(dto.vars);
|
||||||
dto.text = this.voiceService.buildTemplate(dto, vars, validPrefixDict);
|
dto.text = this.voiceService.buildTemplate(dto, vars, validPrefixDict);
|
||||||
return new StreamableFile(await this.voiceService.textToFile(dto));
|
return new StreamableFile(await this.voiceService.textToFile(dto));
|
||||||
|
|
@ -50,7 +64,7 @@ export class VoiceController {
|
||||||
@Header('content-type', 'audio/opus')
|
@Header('content-type', 'audio/opus')
|
||||||
@Header('content-disposition', 'inline')
|
@Header('content-disposition', 'inline')
|
||||||
async announceInvalid(@Query() dto: TtsRequestWithVars) {
|
async announceInvalid(@Query() dto: TtsRequestWithVars) {
|
||||||
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
|
if (this.voiceEnabled) {
|
||||||
const vars = JSON.parse(dto.vars);
|
const vars = JSON.parse(dto.vars);
|
||||||
dto.text = this.voiceService.buildTemplate(dto, vars, invalidPrefixDict);
|
dto.text = this.voiceService.buildTemplate(dto, vars, invalidPrefixDict);
|
||||||
return new StreamableFile(await this.voiceService.textToFile(dto));
|
return new StreamableFile(await this.voiceService.textToFile(dto));
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ import { AxiosRequestConfig } from 'axios';
|
||||||
import * as translit from 'latin-to-cyrillic';
|
import * as translit from 'latin-to-cyrillic';
|
||||||
import { TGD_Config } from 'app.config';
|
import { TGD_Config } from 'app.config';
|
||||||
import {ConfigService} from "@nestjs/config";
|
import {ConfigService} from "@nestjs/config";
|
||||||
|
import {FeatureflagService} from "../featureflag/featureflag.service";
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class VoiceService {
|
export class VoiceService {
|
||||||
private apiUrl = 'https://tts.api.cloud.yandex.net/speech/v1/tts:synthesize';
|
private apiUrl = 'https://tts.api.cloud.yandex.net/speech/v1/tts:synthesize';
|
||||||
private apiKey: string;
|
private apiKey: string;
|
||||||
private readonly logger = new Logger(VoiceService.name);
|
private readonly logger = new Logger(VoiceService.name);
|
||||||
constructor(private httpService: HttpService, private configService: ConfigService) {
|
constructor(private httpService: HttpService, private configService: ConfigService, private featureFlagService: FeatureflagService) {
|
||||||
this.apiKey = this.configService.get<string>("VOICE_APIKEY");
|
this.apiKey = this.configService.get<string>("VOICE_APIKEY");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue