Skip to content

Commit

Permalink
Merge pull request #130 from Arios67/feat/#129
Browse files Browse the repository at this point in the history
[#129]feat: 경매 API socket 추가
  • Loading branch information
Arios67 committed Apr 3, 2022
2 parents cfc489c + cec14f6 commit edee8fb
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 28 deletions.
2 changes: 2 additions & 0 deletions ars/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
"@nestjs/jwt": "^8.0.0",
"@nestjs/passport": "^8.1.0",
"@nestjs/platform-express": "^8.0.0",
"@nestjs/platform-socket.io": "^8.4.3",
"@nestjs/schedule": "^1.0.2",
"@nestjs/typeorm": "^8.0.3",
"@nestjs/websockets": "^8.4.3",
"@types/cache-manager": "^3.4.3",
"apollo-server-express": "^3.6.2",
"axios": "^0.26.0",
Expand Down
9 changes: 9 additions & 0 deletions ars/src/adapters/socket-io.adapters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IoAdapter } from '@nestjs/platform-socket.io';

export class SocketIoAdapter extends IoAdapter {
createIOServer(port: number, options?: any): any {
const server = super.createIOServer(port, options);

return server;
}
}
3 changes: 3 additions & 0 deletions ars/src/apis/art/art.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArtImage } from '../artImage/entities/artImage.entity';
import { Engage } from '../engage/entities/engage.entity';
import { EventGateway } from '../event/event.gateway';
import { EventModule } from '../event/event.module';
import { FileService } from '../file/file.service';
import { LikeArtService } from '../likeArt/likeArt.service';
import { Payment } from '../payment/entities/payment.entity';
Expand All @@ -31,6 +33,7 @@ import { LikeArt } from './entities/likeArt.entity';
ElasticsearchModule.register({
node: 'http://elasticsearch:9200',
}),
EventModule,
],
providers: [
ArtResolver, //
Expand Down
8 changes: 1 addition & 7 deletions ars/src/apis/art/entities/likeArt.entity.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { User } from 'src/apis/user/entities/user.entity';
import {
Column,
Entity,
ManyToOne,
PrimaryColumn,
PrimaryGeneratedColumn,
} from 'typeorm';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Art } from './art.entity';

@Entity()
Expand Down
32 changes: 32 additions & 0 deletions ars/src/apis/event/event.gateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
WebSocketGateway,
WebSocketServer,
OnGatewayConnection,
OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({
cors: {
origin: ['http://localhost:3000', 'https://mybackend.arios67.shop'],
},
namespace: /./,
})
export class EventGateway implements OnGatewayConnection, OnGatewayDisconnect {
constructor() {}
@WebSocketServer()
server: Server;

//소켓 연결시 유저목록에 추가
public handleConnection(client: Socket): void {
console.log('connected', client.id);
client.leave(client.id);
client.data.roomId = `room:lobby`;
client.join('room:lobby');
}

//소켓 연결 해제시 유저목록에서 제거
public handleDisconnect(client: Socket): void {
console.log('disonnected', client.id);
}
}
8 changes: 8 additions & 0 deletions ars/src/apis/event/event.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { EventGateway } from './event.gateway';

@Module({
providers: [EventGateway],
exports: [EventGateway],
})
export class EventModule {}
23 changes: 17 additions & 6 deletions ars/src/apis/likeArt/likeArt.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,26 @@ export class LikeArtService {
async find(userId, page) {
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
await queryRunner.startTransaction('SERIALIZABLE');
try {
let arts = [];
if (page) {
arts = await queryRunner.manager.find(Art, {
arts = await queryRunner.manager.find(LikeArt, {
take: 10,
skip: 10 * (page - 1),
where: { userId: userId },
relations: ['art'],
lock: { mode: 'pessimistic_write' },
});
} else {
arts = await queryRunner.manager.find(LikeArt, {
where: { userId },
relations: ['art'],
lock: { mode: 'pessimistic_write' },
});
}

await queryRunner.commitTransaction();
return arts.map((ele) => ele.art);
} catch (error) {
await queryRunner.rollbackTransaction();
Expand All @@ -43,14 +48,20 @@ export class LikeArtService {
async like(artId, userId) {
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
await queryRunner.startTransaction('SERIALIZABLE');
try {
const art = await queryRunner.manager.findOne(Art, { id: artId });
const art = await queryRunner.manager.findOne(Art, {
where: { id: artId },
lock: { mode: 'pessimistic_write' },
});
console.log(art);
const prevLike = await queryRunner.manager.findOne(LikeArt, {
where: {
userId: userId,
art: artId,
art: art,
},
relations: ['art'],
lock: { mode: 'pessimistic_write' },
});
if (!prevLike) {
await queryRunner.manager.save(LikeArt, {
Expand All @@ -60,7 +71,7 @@ export class LikeArtService {
await queryRunner.commitTransaction();
return true;
} else {
await queryRunner.manager.delete(LikeArt, { art: artId });
await queryRunner.manager.delete(LikeArt, { art: art });
await queryRunner.commitTransaction();
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion ars/src/apis/payment/payment.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Module } from '@nestjs/common';
import { ElasticsearchService } from '@nestjs/elasticsearch';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArtService } from '../art/art.service';
import { Art } from '../art/entities/art.entity';
import { ArtImage } from '../artImage/entities/artImage.entity';
import { Engage } from '../engage/entities/engage.entity';
import { EventModule } from '../event/event.module';
import { User } from '../user/entities/user.entity';
import { UserService } from '../user/user.service';
import { Payment } from './entities/payment.entity';
Expand All @@ -20,6 +20,7 @@ import { PaymentService } from './payment.service';
Payment,
Engage,
]),
EventModule,
],
providers: [
PaymentResolver, //
Expand Down
4 changes: 3 additions & 1 deletion ars/src/apis/payment/payment.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class PaymentResolver {
}
}

// 즉시 구매
@UseGuards(GqlAuthAccessGuard)
@Mutation(() => String)
async instantBid(
Expand All @@ -55,7 +56,7 @@ export class PaymentResolver {
return artId;
}

// 입찰 API(임시)
// 레디스에 입찰 정보(작품, 현재 입찰가, 현재 상위 입찰자)
@UseGuards(GqlAuthAccessGuard)
@Mutation(() => [String])
async Bid(
Expand All @@ -66,6 +67,7 @@ export class PaymentResolver {
return await this.paymentService.call(artId, bid_price, currentUser.email);
}

// DB 저장
@UseGuards(GqlAuthAccessGuard)
@Mutation(() => String)
async saveBid(
Expand Down
9 changes: 6 additions & 3 deletions ars/src/apis/payment/payment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Cache } from 'cache-manager';
import { Connection, LessThan, Repository } from 'typeorm';
import { Art } from '../art/entities/art.entity';
import { Engage } from '../engage/entities/engage.entity';
import { EventGateway } from '../event/event.gateway';
import { History } from '../history/entities/history.entity';
import { User } from '../user/entities/user.entity';
import { Payment } from './entities/payment.entity';
Expand All @@ -23,6 +24,8 @@ export class PaymentService {
@Inject(CACHE_MANAGER)
private readonly cacheManager: Cache,

private eventGateway: EventGateway,

private readonly connection: Connection,
) {}

Expand Down Expand Up @@ -98,10 +101,9 @@ export class PaymentService {
await this.artRepository.softDelete({ id: artId });
}

// 입찰
// 레디스에 입찰 정보(작품, 현재 입찰가, 현재 상위 입찰자)
async call(artId, bid_price, email) {
const art = await this.artRepository.findOne(artId);

const utc = new Date();
const KR_TIME_DIFF = 9 * 60 * 60 * 1000;
const currentTime = new Date(Number(utc) + Number(KR_TIME_DIFF));
Expand All @@ -114,7 +116,9 @@ export class PaymentService {
return [bid_price, email];
}

// DB 저장
async save(artId, userId, bid_price) {
this.eventGateway.server.emit('message', bid_price);
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
Expand All @@ -125,7 +129,6 @@ export class PaymentService {
art: artId,
},
});

await queryRunner.manager.update(
Art,
{ id: artId },
Expand Down
4 changes: 2 additions & 2 deletions ars/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ProfileModule } from './apis/profile/profile.module';
import { HistoryModule } from './apis/history/history.module';
import { ScheduleModule } from '@nestjs/schedule';
import { PaymentModule } from './apis/payment/payment.module';
import { setgroups } from 'process';
import { EventModule } from './apis/event/event.module';

@Module({
imports: [
Expand All @@ -28,6 +28,7 @@ import { setgroups } from 'process';
UserModule,
PaymentModule,
PointTransactionModule,
EventModule,
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
Expand All @@ -48,7 +49,6 @@ import { setgroups } from 'process';
entities: [__dirname + '/apis/**/*.entity.*'],
synchronize: true,
logging: true,
timezone: 'Asia/seoul',
}),
CacheModule.register<RedisClientOptions>({
store: redisStore,
Expand Down
6 changes: 4 additions & 2 deletions ars/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cors from 'cors';
import { graphqlUploadExpress } from 'graphql-upload';
import { SocketIoAdapter } from './adapters/socket-io.adapters';
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.enableCors({
origin: 'http://localhost:3000',
credentials: true,
});
app.use(graphqlUploadExpress());
app.useWebSocketAdapter(new SocketIoAdapter(app));
await app.listen(3000);
}
bootstrap();
Loading

0 comments on commit edee8fb

Please sign in to comment.