Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/main/java/flipnote/user/application/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ public TokenValidateResult validateToken(String token) {
}
});

findActiveUser(claims.userId());

return new TokenValidateResult(claims.userId(), claims.email(), claims.role());
}

Expand Down
11 changes: 4 additions & 7 deletions src/main/java/flipnote/user/application/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
import flipnote.image.grpc.v1.Type;
import flipnote.user.application.command.UpdateProfileCommand;
import flipnote.user.application.result.MyInfoResult;
import flipnote.user.application.result.TokenValidateResult;
import flipnote.user.application.result.UserInfoResult;
import flipnote.user.application.result.UserResult;
import flipnote.user.application.result.UserUpdateResult;
import flipnote.user.domain.AuthErrorCode;
import flipnote.user.domain.ImageErrorCode;
import flipnote.user.domain.TokenClaims;
import flipnote.user.domain.UserErrorCode;
import flipnote.user.domain.common.BizException;
import flipnote.user.domain.entity.User;
Expand All @@ -38,6 +37,7 @@ public class UserService {
private final UserRepository userRepository;
private final SessionInvalidationRepository sessionInvalidationRepository;
private final JwtProvider jwtProvider;
private final AuthService authService;
private final ImageCommandServiceGrpc.ImageCommandServiceBlockingStub imageCommandServiceStub;

public MyInfoResult getMyInfo(Long userId) {
Expand Down Expand Up @@ -108,11 +108,8 @@ public Optional<UserResult> findActiveUserByEmail(String email) {
}

public UserResult findUserByToken(String token) {
if (!jwtProvider.isTokenValid(token)) {
throw new BizException(AuthErrorCode.INVALID_TOKEN);
}
TokenClaims claims = jwtProvider.extractClaims(token);
return UserResult.from(findActiveUser(claims.userId()));
TokenValidateResult tokenResult = authService.validateToken(token);
return UserResult.from(findActiveUser(tokenResult.userId()));
}

private User findActiveUser(Long userId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,56 @@
package flipnote.user.interfaces.grpc;

import org.springframework.grpc.server.exception.GrpcExceptionHandler;
import org.springframework.stereotype.Component;

import flipnote.user.domain.common.BizException;
import flipnote.user.domain.common.ErrorCode;
import io.grpc.Status;
import io.grpc.StatusException;
import io.grpc.StatusRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.grpc.server.exception.GrpcExceptionHandler;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class GrpcExceptionHandlerImpl implements GrpcExceptionHandler {

@Override
public StatusException handleException(Throwable t) {
if (t instanceof BizException e) {
ErrorCode errorCode = e.getErrorCode();
log.warn("gRPC BizException: code={}, status={}, message={}",
errorCode.getCode(), errorCode.getStatus(), errorCode.getMessage());
return toGrpcStatus(errorCode)
.withDescription(errorCode.getMessage())
.asException();
}
if (t instanceof StatusException e) {
log.warn("gRPC StatusException: status={}, description={}",
e.getStatus().getCode(), e.getStatus().getDescription());
return e;
}
if (t instanceof StatusRuntimeException e) {
log.warn("gRPC StatusRuntimeException: status={}, description={}",
e.getStatus().getCode(), e.getStatus().getDescription());
return e.getStatus().asException(e.getTrailers());
}
log.error("gRPC Unhandled exception", t);
return Status.INTERNAL.withDescription("Internal server error").asException();
}
@Override
public StatusException handleException(Throwable t) {
switch (t) {
case BizException e -> {
ErrorCode errorCode = e.getErrorCode();
log.warn("gRPC BizException: code={}, status={}, message={}",
errorCode.getCode(), errorCode.getStatus(), errorCode.getMessage());
return toGrpcStatus(errorCode)
.withDescription(errorCode.getMessage())
.asException();
}
case StatusException e -> {
log.warn("gRPC StatusException: status={}, description={}",
e.getStatus().getCode(), e.getStatus().getDescription());
return e;
}
case StatusRuntimeException e -> {
log.warn("gRPC StatusRuntimeException: status={}, description={}",
e.getStatus().getCode(), e.getStatus().getDescription());
return e.getStatus().asException(e.getTrailers());
}
default -> {
}
}
log.error("gRPC Unhandled exception", t);
return Status.INTERNAL.withDescription("Internal server error").asException();
}

private Status toGrpcStatus(ErrorCode errorCode) {
return switch (errorCode.getStatus()) {
case 400 -> Status.INVALID_ARGUMENT;
case 401 -> Status.UNAUTHENTICATED;
case 403 -> Status.PERMISSION_DENIED;
case 404 -> Status.NOT_FOUND;
case 409 -> Status.ALREADY_EXISTS;
case 429 -> Status.RESOURCE_EXHAUSTED;
default -> Status.INTERNAL;
};
}
private Status toGrpcStatus(ErrorCode errorCode) {
return switch (errorCode.getStatus()) {
case 400 -> Status.INVALID_ARGUMENT;
case 401 -> Status.UNAUTHENTICATED;
case 403 -> Status.PERMISSION_DENIED;
case 404 -> Status.NOT_FOUND;
case 409 -> Status.ALREADY_EXISTS;
case 429 -> Status.RESOURCE_EXHAUSTED;
default -> Status.INTERNAL;
};
}
}
142 changes: 73 additions & 69 deletions src/main/java/flipnote/user/interfaces/grpc/GrpcUserQueryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.grpc.server.service.GrpcService;

import flipnote.user.application.UserService;
import flipnote.user.application.result.UserResult;
Expand All @@ -18,76 +18,80 @@
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@GrpcService
@RequiredArgsConstructor
@Slf4j
public class GrpcUserQueryService extends UserQueryServiceGrpc.UserQueryServiceImplBase {

private final UserService userService;

@Override
public void getUser(GetUserRequest request, StreamObserver<GetUserResponse> responseObserver) {
UserResult user = userService.findActiveUserById(request.getUserId())
.orElseThrow(() -> Status.NOT_FOUND
.withDescription("사용자를 찾을 수 없습니다.")
.asRuntimeException());

responseObserver.onNext(toUserResponse(user));
responseObserver.onCompleted();
}

@Override
public void getUsers(GetUsersRequest request, StreamObserver<GetUsersResponse> responseObserver) {
List<Long> userIds = request.getUserIdsList();
List<UserResult> users = userService.findActiveUsersByIds(userIds);

GetUsersResponse response = GetUsersResponse.newBuilder()
.addAllUsers(users.stream().map(this::toUserResponse).toList())
.build();

responseObserver.onNext(response);
responseObserver.onCompleted();
}

@Override
public void getUserByEmail(GetUserByEmailRequest request, StreamObserver<GetUserByEmailResponse> responseObserver) {
userService.findActiveUserByEmail(request.getEmail())
.ifPresentOrElse(
user -> responseObserver.onNext(
GetUserByEmailResponse.newBuilder()
.setExists(true)
.setUser(toUserResponse(user))
.build()
),
() -> responseObserver.onNext(
GetUserByEmailResponse.newBuilder()
.setExists(false)
.build()
)
);

responseObserver.onCompleted();
}

@Override
public void getUserByToken(GetUserByTokenRequest request, StreamObserver<GetUserByTokenResponse> responseObserver) {
UserResult user = userService.findUserByToken(request.getAccessToken());

responseObserver.onNext(
GetUserByTokenResponse.newBuilder()
.setUserId(user.id())
.setNickname(user.nickname())
.build()
);
responseObserver.onCompleted();
}

private GetUserResponse toUserResponse(UserResult user) {
return GetUserResponse.newBuilder()
.setId(user.id())
.setEmail(user.email())
.setNickname(user.nickname())
.setProfileImageUrl(user.profileImageUrl())
.build();
}
private final UserService userService;

@Override
public void getUser(GetUserRequest request, StreamObserver<GetUserResponse> responseObserver) {
UserResult user = userService.findActiveUserById(request.getUserId())
.orElseThrow(() -> Status.NOT_FOUND
.withDescription("사용자를 찾을 수 없습니다.")
.asRuntimeException());

responseObserver.onNext(toUserResponse(user));
responseObserver.onCompleted();
}

@Override
public void getUsers(GetUsersRequest request, StreamObserver<GetUsersResponse> responseObserver) {
List<Long> userIds = request.getUserIdsList();
List<UserResult> users = userService.findActiveUsersByIds(userIds);

GetUsersResponse response = GetUsersResponse.newBuilder()
.addAllUsers(users.stream().map(this::toUserResponse).toList())
.build();

responseObserver.onNext(response);
responseObserver.onCompleted();
}

@Override
public void getUserByEmail(GetUserByEmailRequest request, StreamObserver<GetUserByEmailResponse> responseObserver) {
userService.findActiveUserByEmail(request.getEmail())
.ifPresentOrElse(
user -> responseObserver.onNext(
GetUserByEmailResponse.newBuilder()
.setExists(true)
.setUser(toUserResponse(user))
.build()
),
() -> responseObserver.onNext(
GetUserByEmailResponse.newBuilder()
.setExists(false)
.build()
)
);

responseObserver.onCompleted();
}

@Override
public void getUserByToken(GetUserByTokenRequest request, StreamObserver<GetUserByTokenResponse> responseObserver) {
log.debug("getUserByToken accessToken [{}]", request.getAccessToken());

UserResult user = userService.findUserByToken(request.getAccessToken());

responseObserver.onNext(
GetUserByTokenResponse.newBuilder()
.setUserId(user.id())
.setNickname(user.nickname())
.build()
);
responseObserver.onCompleted();
}

private GetUserResponse toUserResponse(UserResult user) {
return GetUserResponse.newBuilder()
.setId(user.id())
.setEmail(user.email())
.setNickname(user.nickname())
.setProfileImageUrl(user.profileImageUrl())
.build();
}
}
Loading