(rough) 타입스크립트를 이용한 풀스택 강좌 - 임시서버 구현하기

44523·2024년 1월 26일

PromiseRPC를 러프하게 구현해놓으면 호출 하는 입장에서는 상관 없고, 프론트엔드에 집중 작업한 이후 서버와 통신하는 코드로 깔끔하게 교체할 예정이다.

rpc.ts 파일을 수정할때 마다 cp명령어를 통해서 프로젝트 안으로 복사해주는 세팅을 하려고 한다.

쉘 스크립트

쉘 스크립트란 간단히 말하자면 Unix커맨드등을 나열해서 실행하는 것이다. 언제 어떤 조건으로 어떠한 명령을 실행시킬 것인가, 파일을 컨텐츠를 읽어 들일 것인가, 로그 파일을 작성하는 것 등을 할 수 있다.

  • 터미널에 치는 명령어를 미리 써놓고 나중에 실행 가능.

cprpc.sh 파일을 만들어 아래와같이 작성한다.

#!/bin/bash //shebang
cp rpc.ts frontend/src/rpcgen.ts
//cd <원본 파일> <복사된 파일>
-> rpc.ts 파일을 frontend/src/rpcgen.ts로 복사한다

shebang 이란?

#! 은 2 Byte 의 매직 넘버 (Magic Number) 로 스크립트의 맨 앞에서 이 파일이 어떤 명령어 해석기의 명령어 집합인지를 시스템에 알려주는 역할을 합니다.
#! 바로 뒤에 나오는 것은 경로명으로, 명령어들을 해석할 프로그램의 위치를 나타냅니다.
가장 일반적으로 사용되는건 #!/bin/bash 이며 앞으로 나올 명령어들을 주석을 제외하고 순서대로 실행시킵니다.
만약 경로가 정확하지 않다면 bad interpreter 가 발생하고 다른 인터프리터를 지정하면 문법 오류로 실패합니다.
결론적으로 스크립트 파일에서 어떤 프로그램으로 해당 파일을 실행시킬 지 결정합니다.

이후 맥에서는 권한설정때문에 다음과같은 명령어를 실행해주어야 한다.

chmod 755 cprpc.sh

첫자리 7은 모든권한 두번째 5는 그룹, 아더는 읽기/실행 권한만 부여한다.

chmod 755?(권한 설정)

chmod 는 change mode 의 약어로 시스템의 모드(권한) 를 바꾸는 명령어 이다.
파일의 권한은 읽기(r) 4 / 쓰기(w) 2 / 실행(x) 1 로 분류된다.
각 숫자의 합에 따라 권한이 결정된다. 
ex)
7 => 모든 권한 
5 => 읽기 / 실행 권한
또한 각 자리수마다 의미가 다르다. (ex 755)
첫번째는 소유자(user) 권한 / 두번째는 그룹 사용자(group) 권한 / 세번째는 기타 사용자(other) 권한이다.

임시서버 만들기

import { Post, PromiseRpc, User, Comment } from "./rpcgen";

const server: PromiseRpc = {
  //서버 변수에 PromiseRPC의 기본 틀을 잡는다.
  createPost: async (req) => {
    //데이터 추가
    posts.push({
      body: req.body,
      comments: [],
      id: posts.length,
      author: user,
      timestamp: Date.now(),
    });
    return {}; //그냥 값을 반환하는것 처럼 보여도 외부적으fh Promise가 붙음
  },
  createComment: async (req) => {
    //댓글추가
    const post = findPost(req.postId);
    post.comments.push({
      id: post.comments.length,
      author: user,
      body: req.body,
      timestamp: Date.now(),
    });
    return {};
  },
  readPost: async (req) => {
    return { post: findPost(req.postId) };
  },
  readRandomPost: async () => {
    return { post: findPost(Math.floor(Math.random() * posts.length)) };
  },
  readProfile: async () => {
    return { user };
  },
  readPreview: async () => {
    //미리보기 구현
    const comments: Comment[] = [];
    posts.forEach((p) => {
      p.comments.forEach((c) => {
        if (c.author.id === user.id) {
          comments.push(c);
        }
      });
    });

    return { posts: posts.filter((p) => p.author.id === user.id), comments };
  },
  updateProfile: async (req) => {
    user.name = req.name;
    return {};
  },
};

export default server;

const user: User = { id: 3, name: "내 이름" }; //유저라는 정보로 로그인이된 상태.
const user2: User = { id: 4, name: "다른 유저" };
const posts: Post[] = [
  //더미데이터
  {
    id: 0,
    body: "내용1",
    author: user,
    timestamp: Date.now() - 2345432,
    comments: [],
  },
  {
    id: 1,
    body: "내용2",
    author: user2,
    timestamp: Date.now() - 2131231231,
    comments: [{ body: "댓글2", author: user2, timestamp: Date.now(), id: 2 }],
  },
  {
    id: 2,
    body: "내용3",
    author: user2,
    timestamp: Date.now(),
    comments: [{ body: "댓글1", author: user, timestamp: Date.now(), id: 1 }],
  },
];

function findPost(postId: number): Post {
  //아이디로 글을 찾고 없으면 예외를 던지는 함수.
  const post = posts.find((p) => p.id === postId); //그냥 find만 쓰면 undefined 에 대한 타입처리를 항상 해줘야되어 함수로 따로 뺴줌.
  if (!post) {
    throw Error("no post");
  }
  return post;
}

0개의 댓글