1. 언어의 선택 과정
2. 라이브러리의 선택 과정
3. 설계 과정
4. 코드 리뷰
언어의 선택은 고민이 깊지 않았습니다.
HTTP 프로토콜의 저수준 프로그래밍이 필요할 것이라고 예상했고, Windows OS 가 아닌 플랫폼에 이식해야 하는 경우도 예상해야 하기 때문에 C++과 Python 중 골라야 했지만 C++ 은 OS API preprocess, wrapping을 해야 했기 때문에 개발기간이 매우 길어질 것으로 예상하여 Python으로 개발을 결정했습니다.
라이브러리의 선택또한 개발 언어로 Python을 채택한 덕분에 수월한 편이었습니다.
Python 외부 라이브러리는 다음과 같이 사용했습니다.
설계 과정은 많은 고심이 있었습니다.
최대 접속자 수는 얼마나 정해야 하는가부터, 키보드와 마우스 이벤트를 실시간으로 전달함과 동시에 화면 공유를 하고, 컴퓨팅 자원을 최소한으로 사용하는 설계와 구현, 접근 과정은 다음과 같았습니다.
```
1. 하나의 연결당 하나의 ID를 부여하여 관리를 용이하게 한다
2. ID 를 사용한 매우 빠른 예외 처리가 가능하여야 한다. 이를 통해 TDD와 추후 debugging의 용이함을 가질 수 있다.
3. CPU, RAM의 사용은 최소한으로 사용한다. 마우스와 키보드의 이벤트 발생에 지연이 생기는 것을 방지하여야 한다.
4. 화면 공유 기능의 지연을 방지하여야 한다. 다른 이벤트 발생 시에 지연되면 사용자는 불편함을 겪는다.
5. ID를 get parameter로 전달하여 RESTFUL API를 실행시킨다. 특정 시간 동안 해당 ID의 RESTFUL API 실행이 없다면 해당 ID는 폐기 처리하여 timeout 정책을 구현한다. 이는 3, 4번 정책을 위해 존재한다.
```
이제 코드 리뷰를 진행합니다.
처음에는 화면 공유 기능부터 시작했습니다.
CPU, RAM의 사용을 덜기 위해서 화면을 JPEG로 만드는 함수를 thread로 만들어서 따로 실행시켰지만, 막상 실행 속도는 느리지 않아서 추후에는 RESTFUL API 실행 시마다 호출하는 방식으로 변경했습니다.
먼저 모니터의 정보를 얻습니다. 해상도를 먼저 얻지 않는 이유는 다중 모니터일 가능성이 있기 때문입니다.
ImageGrab.grab의 인자 중, all_screens = True를 사용하여 모든 스크린의 상태를 저장합니다.
이후에 getScreenCapture 함수의 인자 값으로 받은 monitorIndex 변수를 사용하여 스크린을 선택합니다.
xPlus, yPlus는 bbox의 개념입니다. bbox 란 bounding box 의 약자로써 4개의 멤버를 가진 리스트입니다.
pseudo code로 표현하면 bbox = [ x_position_start, y_position_start, x_postion_end, y_position_end ]과 같습니다.
이는 2차원 좌표상에서 특정한 구역을 정하는데 필요한 정보입니다. 스크린은 2차원 좌표임으로 편집을 위해서는 bbox 가 필요합니다. 따라서 2개 이상의 화면을 공유하기 위한 구현으로 image.crop을 사용했습니다. crop 함수의 인자 값은 bbox입니다. 이후에는 ByteIO 객체를 선언하여 JPEG 파일을 메모리에서 얻습니다.
화면 공유에 대한 구현을 위해서 이제 http 요청에 대한 대응을 준비합니다. ( 앞으로 routing 이라 부르겠습니다.)
/createUser 요청에 대한 대응입니다.
사용자의 ID는 time module의 perf_counter_ns 함수를 활용합니다.
해당 함수는 performance counter의 값을 nano second로 바꾼 값을 리턴합니다.
또한 사용자의 ID를 생성한 시간을 기록합니다. 이는 사용자가 일정 시간 동안 요청이 없을 시에 timeout 을 진행하기 위해 기록합니다.
앞으로 자주 사용될 것 같은 사용자 인증 routine 은 함수화하여 보관합니다.
화면을 전송하는 routine 입니다. GET parameter 로 사용자의 ID 를 전달받고 인증을 거친 이후에 인자로 받은 index 로 화면을 잘라내어서 전송합니다.
화면이 몇개인지 전달해주기 위해서 routing 이 필요합니다.
앞으로 이런식으로 routing 을 진행할텐데, IO routine 주변에 이런 코드가 있으면 개발이 어려워지겠지요.
그래서 IOSubRoutine 이라는 이름으로 중간 함수를 구현했습니다.
file routing 또한 해당 함수 내에서 구현했습니다.
이제 마우스를 움직여야하는데, pyautogui module 내에 moveTo 함수로 구현되어있었습니다.
처음에는 moveTo 함수를 직접 호출했지만, moveTo 함수가 실행되는 시간이 응답속도에 영향을 주어서 thread 를 사용하여 처리했습니다.
xPlus, yPlus 는 multiple screen 을 지원하기 위해 계산하는 값 입니다.
keyboard event 처리는 다음과 같이 구현했습니다.
GET parameter 로 key 의 정보를 받은 다음 처리합니다.
이에 대응하여 JS 에서 key down, key up 등의 event 를 처리하여야합니다.
JS 에서 event 를 처리하기 때문에 몇몇 key 는 pyautogui module 이 사용하는 key 이름과 맞지 않습니다.
따라서 key re-mapping 을 진행하여야합니다.
사용된 key re-mapping list 는 다음과 같습니다.
중요한 중간 함수에 대한 내용은 이정도로 끝내고, 이제 네트워크 처리에 대한 설명을 적겠습니다.
네트워크 처리는 select module 의 select 함수를 사용했습니다.
이런식으로 select 함수를 사용하면 서버의 응답속도와 자원을 모두 아낄 수 있습니다.
실제 client 와의 IO 는 다음과 같이 구현했습니다. python 을 사용하니 정말 간편했습니다.
clientIOSubRoutine 에서 http request 에 대한 response 를 결정하고 리턴시켜주는 방식의 설계를 사용하니 코드가 참 간결해졌습니다.