featureflag for DisableVoice & DontMarkQuestsion

This commit is contained in:
Kirill Ivlev 2024-11-11 18:16:33 +04:00
parent 9e4f5e13c0
commit 59f32b94d9
9 changed files with 55 additions and 18 deletions

View file

@ -1,3 +1,5 @@
export class FeatureFlagsConsts {
static EnableEndgamePoints = 'EnableEndgamePoints';
static DontMarkQuestionsAsCompleted = 'DontMarkQuestionsAsCompleted';
static DisableVoice = 'DisableVoice';
}

View file

@ -45,6 +45,6 @@ import { FeatureflagService } from './featureflag/featureflag.service';
],
controllers: [AppController, FeatureflagController],
providers: [AppService, SocketGateway, SchedulerService, FeatureflagService],
exports: [AppService, SocketGateway],
exports: [AppService, SocketGateway, FeatureflagService],
})
export class AppModule {}

View file

@ -1,5 +1,6 @@
import {Injectable, Logger} from '@nestjs/common';
import {SharedService} from "../shared/shared.service";
import {SocketEvents} from "../shared/events.consts";
export interface IFeatureFlagStatus {
name: string;
@ -13,17 +14,25 @@ export class FeatureflagService {
}
async getFeatureFlag(id: string): Promise<IFeatureFlagStatus> {
this.logger.verbose(`Getting feature flag status for ${id}`);
const state = await this.sharedService.getConfig(`featureflag/${id}`);
this.logger.verbose(`[getFeatureFlag] Getting feature flag status for ${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 {
name: id,
state: state.value !== 'false',
state: ffState
}
}
async setFeatureFlag(id: string, status: boolean) : Promise<IFeatureFlagStatus> {
this.logger.verbose(`Setting feature flag status for ${id} to ${status} `);
const result = await this.sharedService.setConfig(`featureflag/${id}`, status.toString());
this.sharedService.sendSocketNotificationToAllClients(SocketEvents.FEATURE_FLAG_CHANGED, {});
return {
name: id,
state: result.value !== 'false',

View file

@ -16,6 +16,8 @@ import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.
import {GameQueueTypes} from "../schemas/game-queue.schema";
import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player-winning-rate.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 })
export class QuizService {
@ -30,6 +32,7 @@ export class QuizService {
private sharedService: SharedService,
private eventBus: EventBus,
private commandBus: CommandBus,
private featureFlagService: FeatureflagService,
) {
}
@ -54,7 +57,6 @@ export class QuizService {
async validateAnswer(answer: string, id: number) {
this.logger.verbose(`enter validate answer ${answer} ${id}`);
const question = await this.get();
//question.answered = true;
await question.save();
const regexp = new RegExp(
Object.keys(this.answerNumbers)
@ -82,7 +84,6 @@ export class QuizService {
await question.save();
this.logger.verbose("question saved with user details")
if (question.valid === filtered) {
//question.answered = true;
question.answeredBy = id;
this.logger.verbose(`extra ${question.note}`);
this.eventBus.publish(
@ -126,6 +127,11 @@ export class QuizService {
private async calculateScore() {
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 `);
const playerAnswers = question.userAnswers.map((answer) => {
return {

View file

@ -12,4 +12,5 @@ export enum SocketEvents {
GAME_PAUSED = 'game_paused',
GAME_RESUMED = 'game_resumed',
NOTIFICATION = 'notification',
FEATURE_FLAG_CHANGED = 'feature_flag_changed',
}

View file

@ -8,6 +8,7 @@ import { ClientProxyFactory, Transport } from '@nestjs/microservices';
import * as process from "process";
import {ConfigModule} from "@nestjs/config";
import {CqrsModule} from "@nestjs/cqrs";
import {FeatureflagService} from "../featureflag/featureflag.service";
@Global()
@Module({
imports: [
@ -17,7 +18,7 @@ import {CqrsModule} from "@nestjs/cqrs";
GameModule,
MongooseModule.forFeature([{ name: Config.name, schema: ConfigSchema }]),
],
providers: [SharedService, {
providers: [SharedService,FeatureflagService, {
provide: 'Telegram',
useFactory: () =>
ClientProxyFactory.create({
@ -31,7 +32,7 @@ import {CqrsModule} from "@nestjs/cqrs";
},
}),
}],
exports: [SharedService, 'Telegram'],
exports: [SharedService, 'Telegram',FeatureflagService],
})
export class SharedModule {
constructor() {

View file

@ -20,6 +20,9 @@ export class SharedService {
key,
})
.exec();
if(!res) {
return null;
}
return {
key: res.key,
value: res.value,

View file

@ -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 { TtsRequestDto, TtsRequestWithVars } from './models/TtsRequestDto';
import { invalidPrefixDict } from './dicts/invalid-prefix.dict';
import { validPrefixDict } from './dicts/valid-prefix.dict';
import * as translit from 'latin-to-cyrillic';
import {ConfigService} from "@nestjs/config";
import {FeatureflagService} from "../featureflag/featureflag.service";
import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts";
@Controller('voice')
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')
@Header('content-type', 'audio/opus')
@Header('content-disposition', 'inline')
async textToSpeechSSML(@Query() dto: TtsRequestDto) {
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
//return new StreamableFile(await this.voiceService.textToFile(dto, true));
this.logger.verbose(`[textToSpeechSSML] enter, FF state is: ${this.voiceEnabled}`);
if (this.voiceEnabled) {
return new StreamableFile(await this.voiceService.textToFile(dto, true));
} else {
return new NotFoundException('Voice disabled');
}
}
@Get('tts')
@ -26,8 +41,8 @@ export class VoiceController {
@Header('content-disposition', 'inline')
async getText(@Query() dto: TtsRequestDto) {
dto.text = translit(dto.text);
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
//return new StreamableFile(await this.voiceService.textToFile(dto));
if (this.voiceEnabled) {
return new StreamableFile(await this.voiceService.textToFile(dto));
} else {
return new NotFoundException('Voice disabled');
}
@ -36,8 +51,7 @@ export class VoiceController {
@Header('content-type', 'audio/opus')
@Header('content-disposition', 'inline')
async announceValid(@Query() dto: TtsRequestWithVars) {
console.log(this.configService.get<boolean>('ENABLE_VOICE'));
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
if (this.voiceEnabled) {
const vars = JSON.parse(dto.vars);
dto.text = this.voiceService.buildTemplate(dto, vars, validPrefixDict);
return new StreamableFile(await this.voiceService.textToFile(dto));
@ -50,7 +64,7 @@ export class VoiceController {
@Header('content-type', 'audio/opus')
@Header('content-disposition', 'inline')
async announceInvalid(@Query() dto: TtsRequestWithVars) {
if (Boolean(this.configService.get<boolean>('ENABLE_VOICE')) === true) {
if (this.voiceEnabled) {
const vars = JSON.parse(dto.vars);
dto.text = this.voiceService.buildTemplate(dto, vars, invalidPrefixDict);
return new StreamableFile(await this.voiceService.textToFile(dto));

View file

@ -7,12 +7,13 @@ import { AxiosRequestConfig } from 'axios';
import * as translit from 'latin-to-cyrillic';
import { TGD_Config } from 'app.config';
import {ConfigService} from "@nestjs/config";
import {FeatureflagService} from "../featureflag/featureflag.service";
@Injectable()
export class VoiceService {
private apiUrl = 'https://tts.api.cloud.yandex.net/speech/v1/tts:synthesize';
private apiKey: string;
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");
}