/images/profile_no_background.png

김영천 블로그

Google App Engine Image API 삽질 후기

오늘은 GAE에서 제공하는 Image API를 사용하면서 겪은 어려움과 후기를 공유하고자 한다.

요구사항

  • GAE를 통해 업로드 된 이미지를 Google Cloud Storage(이하 GCS)에 보관, 파일 관련 정보를 datastore에 별도로 저장한다(업로드 한 사용자, 업로드 파일명, 업로드 날짜 등등). 이 이미지를 웹사이트를 통해 서비스를 하고싶다. 이 이미지는 사이즈가 모두 제각각인데 DSLR로 찍은 수십메가짜리 이미지부터 조그마한 썸네일 이미지까지 크기가 천차만별이다.
  • 동일한 이미지를 여러가지 사이즈로 출력해야 한다. 가령 DSLR로 찍은 이미지를 제공할 경우 우선 100px짜리 썸네일로 제공, 사용자가 썸네일을 클릭할 경우 이미지의 원본을 보여주고 싶다.
  • 사용자가 주로 모바일을 통해 서비스를 사용할것으로 예측되는데 사용자의 디바이스마다 최적화 된 크기의 이미지를 제공하고 싶다.

고민

위와 같은 요구사항을 충족시키기 위해 인터넷을 꽤 오래 뒤지고 다녔다. 처음에는 비트윈의 블로그 글을 보고 이걸 따라하면 되겠다 싶었다. 하지만 문제가 있었다. 이미지 업로드를 GAE에서 구현하다보니 이미지를 webp 형태로 변환하는 golang 라이브러리를 쓸 수가 없었다. 마찬가지로 온디멘드 리사이징도 GAE 위에서 돌리기엔 문제가 좀 있었다(내가 해결책을 못 찾은걸수도 있다). 결국 며칠동안 고민만 하고 코드를 한줄도 작성을 못해서 일단 무식한 방법으로라도 구현을 해보기로 했다. 그래서 아래와 같은 방법을 후보로 선정했다.

datastore에서 projection query 실행 시 time.Time이 int64로 반환되는 문제 해결하기

요구사항

datastore에 내 프로필을 방문한 사용자의 ID와 방문시간을 각각 string, time.Time 형식으로 저장하고 있다. 구조체로 보면 다음과 같다.

type Visitor struct {
	UserId string //조회한 프로필의 Id
	VisitorId string //방문자 Id
	VisitTime time.Time
}

이 데이터를 단순히 조회하면 한 사용자가 나를 여러번 방문할 경우 결과 리스트에 그 방문자가 여러번 출력된다. 나는 동일한 사용자가 여러번 반복해도 가장 최근에 방문한 기록만 보길 원했다. 즉 datastore에서 SQL 문법의 group by를 사용하고 싶었다. 내 요구사항을 SQL로 표현하자면 아래와 같다.

emacs 명령어 목록

emacs 명령어 목록

이맥스를 쓰면서 개인적으로 유용하게 쓰고있는 명령어 리스트, 대부분 M-x를 누른 후 실행한다.

common

  • grep : grep을 이용한 문자열 검색 (lgrep, rgrep도 있다.). 위키링크

emacs 단축키 목록

emacs 단축키 목록

아래의 단축키들은 그누 이맥스 시작하기(한빛미디어) 책을 보면서 정리한 내용들입니다.

common

  • C-x s : 모든 버퍼 저장(y, n 또는 !)
  • C-x C-q : 버퍼 읽기/쓰기 전용상태로 swap
  • C-x C-x : 선택영역 끝간 이동
  • C-t : 글자 순서 바꾸기(toggle)
  • M-t : 단어 순서 바꾸기
  • C-x C-t : 문장 순서 바꾸기
  • M-c : 단어의 첫 글자만 대문자로 바꾸기
  • M-u : 한 단어를 대문자로 바꾼다.
  • M-l : 한 단어를 소문자로 바꾼다.
  • C-s C-w : 커서가 있는 곳의 단어를 탐색 문자열로 사용해 점진적 탐색을 시작한다.
  • C-r : 재귀 편집
  • C-M-c : 재귀 편집 종료
  • C-x { : 윈도우 가로폭 줄이기
  • C-x } : 윈도우 가로폭 늘리기
  • C-x ^ : 윈도우 세로폭 늘리기

버퍼목록(C-x C-b) 작업

  • d or k : 버퍼 삭제
  • DEL : 지정명령 취소
  • x : 명령 실행
  • ~ : 버퍼를 수정하지 않은 상태로 표시
  • % : 읽기전용/읽기쓰기 전환
  • 1 : 버퍼를 전체화면으로 띄운다.
  • 2 : 현재 버퍼와 다음 것을 수평으로 나눈 윈도우에 띄운다.
  • m : 윈도우에 띄울 버퍼 선택
  • v : 선택한 버퍼들 수평으로 띄우기
  • f : 버퍼 목록 윈도우를 선택한 버퍼로 바꾼다.
  • o : 다른 윈도우를 선택한 버퍼로 바꾼다.
  • q : 버퍼 목록 끝내기

북마크 작업

  • C-x r m : 현재 커서위치에 북마크 생성
  • C-x r b : 북마크로 이동
  • M-x bookmark-rename : 북마크 이름변경
  • M-x bookmark-delete : 북마크 삭제

북마크 목록(C-x r l) 작업

  • d : 삭제할 북마크 표시
  • r : 북마크 이름을 변경한다.
  • s : 나열된 북마크를 저장한다.
  • f : 현재 커서가 위치한 북마크를 화면에 띄운다.
  • m : 여러 개의 윈도우에 띄우기 위한 북마크를 표시한다.
  • v : 표시한 북마크를 화면에 띄우거나, 아무것도 표시된 것이 없으면 커서가 위치해 있는 북마크를 표시한다.
  • t : 북마크와 관련된 파일 경로의 표시를 바꾼다.
  • w : 북마크와 관련된 파일의 위치를 표시한다.
  • x: 삭제 표시된 북마크를 삭제한다.
  • u : 북마크 목록에서 표시한 것을 취소한다.
  • DEL : 북마크 목록의 이전 줄에 표시한 것을 취소한다.
  • q : 북마크 목록을 종료한다.
  • M-| : shell command on region
  • C-c C-o : 이전 명령으로 인한 출력을 자동으로 지운다.

Dired(C-x d) 명령

  • C : 파일 복사
  • d : 삭제할 파일 지정
  • D : 즉시 삭제여부를 묻는다.
  • e : 파일 편집
  • g : 디스크로부터 디렉토리를 다시 읽어온다.
  • G : 그룹 퍼미션 변경
  • k : 목록에서 해당 파일 삭제(디스크에는 남아있음)
  • o : 다른 윈도우에 파일을 열고, 그 윈도우로 이동한다.
  • C-o : 다른 윈도우에 파일을 열고, 그 윈도우로 이동하지 않는다.
  • P : 파일 출력
  • q : dired 종료
  • Q : 표시한 파일의 문자열을 질의-치환 한다.
  • x : 삭제 실행
  • m : 파일 선택
  • R : 파일명을 바꾼다.
  • u : 표시를 취소한다.
  • M-DEL : 모든 파일의 표시를 없앤다.
  • Z : 파일을 압축 또는 해제한다.
  • ! : 커서가 위치한 파일을 대상으로 shell 명령 실행
  • M-} : * 또는 D로 표시된 다음 파일로 이동
  • M-{ : * 또는 D로 표시된 이전 파일로 이동
  • %d : 정규표현식과 일치하는 파일에 삭제표시 한다.
  • %m : 파일을 선택하기 위한 정규식을 묻는다.
  • + : 디렉토리 생성
  • = : 현재 파일을 표시해둔 다른 파일과 비교한다.
  • > : 다음 디렉토리로 이동
  • < : 이전 디렉토리로 이동
  • s : Dired의 화면 표시를 날짜나 파일명 순으로 재정렬(toggle)

매크로 명령

  • C-x ( : 매크로 정의 시작
  • C-x ) : 매크로 정의 종료
  • C-x e : 매크로 실행

프로그래머를 위한 이맥스(C, C++ 모드 기준, 대부분 go-mode에서도 동작되는것으로 보인다)

  • C-M \ : 커서와 마크 사이의 각 줄을 들여쓴다.
  • M m : 현재 줄의 첫번째 비공백 문자로 이동한다.
  • M ^ : 현재 줄을 이전 줄에 붙인다.
  • M j : indent-new-comment-line
  • M a : 현재 명령문의 처음으로 이동한다.
  • M e : 현재 명령문의 끝으로 이동한다.
  • M q : 주석 내에 있다면 들여쓰기와 장식 등을 유지하면서 단락을 채운다.
  • C-M a : 현 지점을 둘러싸고 있는 함수 내부의 시작점으로 이동한다.
  • C-M e : 함수의 끝으로 이동한다.
  • C-M h : 커서를 함수의 시작점으로 이동하고, 끝에 마크한다.
  • C-c C-q : 들여쓰기 스타일에 따라 함수 전체를 들여쓴다.
  • C-c C-u : 현재 전처리 조건문의 시작 위치로 이동한다.
  • C-c C-p : 이전 전처리 조건문으로 이동한다.
  • C-c C-n : 다음 전처리 조건문으로 이동한다.