Rath World » me2day

Archive

Archive for the ‘me2day’ Category

me2terminal 프로젝트를 도와주실 분을 찾습니다.

September 18th, 2009 16 comments

몇년동안 제쳐놓게 되는 일들이 있습니다. 그 중 하나가 제겐 ncurses를 이용한 프로그래밍이였지요. api가 간단하여 만들기 제일 만만한(?) 미투데이 클라이언트를 만들기로 하고 오랜만에 python을 열어 ncurses로 콘솔 베이스 미투데이 클라이언트를 만들었습니다.

me2terminal은 github 위에서 오픈소스 프로젝트로 진행되고 있는데요, 로그에도 나와있듯이 2일간 커밋이 없는 상태입니다. 몇가지 이슈들이 있는데 다른 일들에 치이다보니 python 경험이 거의 없어서 휙휙 앞으로 나아가지 못하고 있네요.

제 개발환경은 Mac OS X 이고, 기본 탑재된 Python의 curses 모듈이 wide-character를 지원하지 않아 파이썬 2.6 소스코드를 내려받아 제 장비에서 빌드해서 쓰고 있습니다. 그런데 me2terminal을 쓰려는 사용자에게 .. “저기, python.org 사이트에 가셔서요. 소스를 받으시고요. configure 하시고 make; make install 하시면 되요. 아, 그리고 만약 시스템에 libcursesw 가 없으면요, 그거 받은 다음 파이썬을 빌드해야됩니다.” 라고 말하는 것은 센스빵점이잖아요? 오픈소스가 안팔리는 이유 중 하나가 설치와 설정이 어렵다는 말도 있습니다.

제 로컬에 설치되어있는 이슈트래커를 보면 me2terminal 프로젝트 다음과 같은 할 일이 남아있습니다.

  • 미투포토를 출력하기 위한 Image to ASCII 변환 알고리즘 찾기 & 적용
  • 네비게이션 히스토리 관리 (브라우저의 back / forward 와 같은)
  • 미투 박스와 댓글 창에서 미친의 미투데이로 갈 수 있도록 keymap 넣기
  • me2API socket timeout 시 오류처리
  • 파이썬 프로그램을 적절히 배포할 방법 찾기
  • 데스크탑 쉬운 인증 넣기
  • me2API.track_comments 기능 넣기
  • 터미널 크기 변경시 이를 감지하여 자동으로 화면을 갱신하기.
  • 본문에 포함된 링크에 밑줄을 표시하고, a 키를 누르면 URL을 표시하기. 만약 내부링크면 해당 포스트로 점프하기.
  • stomppy로 알리미 API 적용 (세부 계획 없는 상태)

무엇보다 배포 문제가 지금 제 마음을 꾹 틀어막고 있습니다. 배포 문제가 머리속에 들어온 뒤로 어떠한 이슈 해결도 안하고 있습니다. 열심히 만들어서 혼자 쓰기가 아까워서요!

배포 문제가 깔끔히 해결되지 않는다면, 일괄포팅에 문제가 없도록 일단 파이썬으로 구현을 마친 뒤, 쉬운 배포를 위해 c로 포팅하여 ncurses를 static link한 플랫폼별 바이너리를 만들까도 생각중입니다. 윈도우즈에서 curses가 어느정도의 캐퍼를 보이는지도 궁금하고요.

관심있으신 분들의 참여를 부탁드리겠습니다. 파이썬 프로그램 배포에 대한 어떠한 조언도 환영합니다.

미투 구글리더 개발 후기 : Ext GWT

September 10th, 2009 2 comments

미투 구글리더 개발 후기입니다.

미투 구글리더는 3개월전에 개발되어 계속 혼자 써오던 것이였는데요. 런던에 온지 6주가 다 되어 가는데, 아무런 준비도 없이 온지라 딱히 직업도 없고 -_- 와이프는 학교 왔다갔다 하느라 혼자 있는 시간이 많아서 평소에 미뤄왔던 일들을 하나 둘씩 하다보니 이녀석을 개발하게 되었답니다.

미투 구글리더의 프론트엔드는 Ext GWT를 이용해 만들었습니다. 3개월동안에는 허접한 HTML만으로 만든 페이지로 운영되었지만 뭐 혼자 쓰는 것이니 운영이랄 것도 없었지요. 아무래도 java awt/swing 으로 개발을 시작해서 그런지 swing 개발 스타일로 웹을 만들 수 있는 GWT가 많이 끌렸습니다. 그런데 제가 비주얼 디자인에 약하다보니.. 자연스럽게 GXT로 눈을 돌리게 되었지요. $329 라는 가격이 그리 만만한 가격은 아니지만 런던에서 첫 수입생기면 바로 지를 생각하고 ^^ 일단 개발을 시작했습니다.

프론트 엔드에서는 미투데이 아이콘을 가져오기 위한 me2DAY API get_person 을 이용하고, 구글리더 피드 주소를 쉽게 가져올 수 있게 하도록 GetGoogleReaderGRLD 란 클래스를 쓰고 있습니다. GetGoogleReaderGRLD가 뭐냐면, 구글리더 공유 피드 URL은

http://www.google.com/reader/public/atom/user/12212200999016560865/state/com.google/broadcast

이런 형식으로 구성되어 있습니다. 다른 부분은 다 똑같은데.. /user/ 뒤의 숫자가 핵심인거지요. 이 숫자만 알면 사용자로 하여금 미투 구글리더를 쓰기 위해

1) 구글리더에 접속
2) 공유 피드 URL 주소가 어디에 있는지 뒤적뒤적
3) 이 URL이 맞는거 같지만 확신이 안서서 갈등
4) 복사해서 붙이기

이런 귀찮은 과정을 줄여줄 수 있습니다. 그래서 GetGoogleReaderGRLD 클래스가 하는 일은 HttpClient를 이용하여 GRLD (/user/ 뒤의 숫자를 GRLD라고 지칭하더군요) 를 긁어오는 것입니다.

어쩔 수 없이 자신의 구글 아이디와 패스워드를 입력해야하는데요, 물론 저장은 하지 않습니다. 원래는 무조건 이 방법만을 강요하게 할까 하다가 아무래도 신뢰 문제가 걸려서 자신이 직접 공유피드URL를 입력할 수도 있게 해두었지요.

GXT와 함께 하는 프론트엔드 개발에서 가장 애를 많이 먹었던 것은 미투데이 아이콘을 표시해주는 ListView 를 개발하는 것이였는데요, 미투 아이콘은 44×44 라 아이콘 하나를 한줄에 표시하기에는 공간 낭비가 심해서 이를 가로로 나열하고 자동으로 wrap 되게 하고 싶었는데.. 생각대로 되지 않아서 애를 많이 먹었습니다. 결국 IE6 에서는 제대로 렌더링 되지 않는 display: inline-block 를 쓰고야 말았습니다. 구글링을 하다보니 inline-block 효과를 모든 브라우저에서 가능하게 하는 법들이 종종 보였는데요, 공간 낭비가 심해지는 디스플레이가 치명적인 결함도 아니고 해서 ^_^ 그냥 inline-block을 써버리고 말았지요.

프론트엔드에서 사용되는 RPC 콜은 총 5개 입니다. Eclipse의 Google plugin 덕분에 RPC 부분에서는 조금도 삽질을 하지 않았습니다.

public interface UtilityServiceAsync {
void setAccountEnabled(String me2id, boolean enable, AsyncCallback<Void> callback);
void getMe2dayProfile(String userid, AsyncCallback<Person> callback);
void getMe2dayIcons(String userid, AsyncCallback<List<Icon>> callback);
void getGoogleReaderAtomUrl(String email, String password, AsyncCallback<String> callback);
void updateAccount(String me2id, String atomURL, int me2dayIconIndex, boolean forwardWhenNote, boolean forwardWhenMe2day,
AsyncCallback<String> callback);
}

이 요청들을 처리하는 GWT의 RemoteServiceServlet 에서는 인증체크를 위한 세션과 쿠키 체크가 들어가있는 것 말고는 별 게 없습니다. 다만 여기서 파라미터로 me2day-api java 의 Person 클래스와 Icon 클래스가 왔다갔다 하는 것을 보실 수 있는데요. 이것을 위해 me2day-api java에 GWT 지원을 넣어 0.6 릴리즈를 하기도 했습니다.

GWT에서 legacy POJO를 RPC의 파라미터나 리턴값으로 쓰려면.. 일단 해당 클래스들이 GWT에서 제공하는 클래스 외의 것들을 쓰고 있는지 확인해야 합니다. me2day-api 의 경우에 가장 골치아팠던 점은 java.net.URL 클래스였지요. GWT 에서는 java.net.URL 클래스를 지원하지 않습니다. 그래서 URL 필드들을 모두 String 으로 바꿔야 되는 지경에 이르렀는데요, 그렇다고 GWT 와 상관없이 개발하는 사람들도 다 String을 써야한다는 것은 웃기는 일이지요. 그래서 기존 클래스들은 그대로 두고 각 클래스에 toGWT() 란 녀석을 하나 심어서 GWT 호환 객체로 clone 해주는 인터페이스를 만들었습니다. 이렇게 되면 하위호환성도 지키면서 GWT 지원 엔티티 클래스들도 확보할 수 있게 되지요.

하지만 이렇게 GWT 호환 클래스를 만드는 것만으로는 부족했습니다. GXT 에서는 MVC 모델을 적용하기 적합한 List, Tree, Table 에 대해서는 RpcProxy 란 것을 제공합니다. 이녀석이 뭔가 하니 각 컴포넌트의 모델 부분에 대해 네트워크 관련 코딩을 직접하지 않고 rpc 이름만 지정해주면 지가 혼자 알아서 요청도 날리고 데이터가 오면 뷰에 뿌려주기까지.. 하는 녀석이지요.

RpcProxy<List<Icon>> proxy = new RpcProxy<List<Icon>>() {
@Override
protected void load(Object loadConfig, AsyncCallback<List<Icon>> callback) {
service.getMe2dayIcons(me2dayId, callback);
}
};
ListLoader<ListLoadResult<Icon>> loader = new BaseListLoader<ListLoadResult<Icon>>(proxy, new BeanModelReader());
ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
ListView<BeanModel> view = new ListView<BeanModel>();
view.setStore(store);

아이고 이렇게 예쁠 수가요. 그렇지만 이렇게 편한 방법을 쓰려면 POJO에 약간을 수정을 가해줘야 합니다. 물론 이점은 GWT 가 아니라 GXT 에서 제공하고 (강요하는) 것입니다.

1) POJO를 건드리지 않고, GXT 앱 프로젝트 위에 썰렁한 BeanModel 클래스를 지정하기

import com.extjs.gxt.ui.client.data.BeanModelMarker;
import com.extjs.gxt.ui.client.data.BeanModelMarker.BEAN;

@BEAN(net.me2day.gwt.client.Icon.class)
public class IconBeanModel implements BeanModelMarker {
}

이렇게 어떤 POJO의 BeanModel 이다.. 라고 마커 클래스를 만들어두면 GWT compiler가 알아서 매핑해줍니다. 또 다른 방법은,

2) POJO를 건드리기

그저 POJO 에 메소드가 하나 없는 BeanModelTag 인터페이스를 하나 달아두면 됩니다.  이 부분에 대해서는 Ext JS Blog의 Java Bean support with Ext GXT 를 참조하시면 됩니다.

프론트엔드 부분은 이정도로 설명을 마치겠습니다.

아, 하나 더. 한창 jQuery를 써서 만들고 싶었는데 GWT 프로젝트를 하게 되서 아쉬움이 컸었는데요, 한을 풀었습니다. gwtquery란 녀석이 있더군요. GWT 자바 소스코드에서 DOM 접근과 조작을 jQuery 처럼 할 수 있게 해줍니다. static으로 $란 이름을 가진 메서드를 제공해서 이 모든 것을 해결합니다. 하하 -_-

VerticalPanel panel = new VerticalPanel() {
protected void onRender( Element parent, int pos )
{
super.onRender(parent, pos);
$(“#profile-picture”).load(new Function() {
public boolean f(Event e)
{
$(“#welcome-message-1”).css(“display”, “block”);
$(“#welcome-message-2”).css(“display”, “block”);
return true;
}
});
}
};

멋집니다. 자알 동작하네요! 이게 다 import static 덕분입니다. 하하.

프론트엔드는 이 정도로 줄이겠습니다. 백엔드는 다음 기회에 ^^

미투 구글리더를 소개합니다.

September 10th, 2009 2 comments

미투 구글리더를 소개합니다.

미투 구글리더는, 구글리더에서 마음에 드는 피드를 공유했을 때 이를 미투데이에 포스팅해주는 매쉬업입니다. 물론 노트와 함께 공유했을 경우 노트 내용이 함께 포스팅 되어 딱딱하지 않은 포스트를 만들어낼 수가 있지요.

미투 구글리더

미투 구글리더

미투데이에 무슨 글을 올려야할지 마땅치 않아 고민하지 않으셨었나요? 그렇다면 구글리더에서 친구들과 함께 보고 싶은 피드 항목을 ‘공유’ 하여 미친들과 함께 볼 수 있습니다.

친구들과 함께 하는 미투데이에.. 딱딱한 피드 제목만 나오는 게 싫다고요? 걱정하지 마세요. 구글리더에서 ‘메모와 함께 공유’를 하시면 메모 내용이 미투데이에 함께 포스팅 되어 딱딱하지 않은 포스트를 발행할 수 있답니다.

그럼 어떻게 쓰는지 함께 보도록 하지요. 일단 미투 구글리더 서비스에 접근합니다.

미투 구글리더는 구글리더에서 공유한 항목을 자동으로 미투데이에 포스트해주는 매쉬업이기 때문에 미투데이 사용자키를 필요로 합니다. 그러므로 인증을 해주셔야 ^^ 쓸 수 있습니다.

아래와 같은 화면이 나오면 ‘인증하기’ 버튼을 눌러주세요.

인증하기 버튼을 누르면, 미투데이로 넘어가서 여러분에게 미투 구글리더 서비스가 신뢰할 수 있는 서비스인지 확인하는 페이지가 아래와 같이 표시됩니다.

미투데이 API 인증

미투데이 API 인증

수락하시고 나면, 아래처럼 미투구글리더 설정 화면이 나옵니다.

미투 구글리더 설정화면

미투 구글리더 설정화면

무엇보다 먼저, 자신의 구글리더 공유 피드 URL를 입력해주셔야 합니다. 위의 스크린샷에 써있는 것은 제 구글리더 공유 피드 주소인데요, 물론 자신의 것을 입력해야겠죠 ^^? 구글리더에 들어가서 공유 설정에 가서.. 상세보기를 눌러 피드주소를 복사해서 붙여주시면 되는데요, 이게 꽤나 귀찮으실 겁니다. 그럴 경우 하단의 “피드 주소를 입력하기 귀찮으시면 눌러주세요” 버튼을 눌러 손쉽게 해결할 수 있는데요, 자신의 구글 아이디와 비밀번호를 입력하면 제 프로그램이 열심히 크롤링하여 피드 주소를 자동으로 채워줍니다. 물론 아이디와 패스워드는 제 서버에 저장해두지 않습니다. 🙂

하단의 미투 아이콘은 미투 구글리더가 포스팅 해줄 때 사용할 아이콘을 의미합니다. 아무거나 ^^ 선택하셔도 되고요.

마지막 필터! 구글리더의 공유 기능을 자주 쓰지 않으셨던 분이라면 아마 쓸모가 없을테지만, 하루에 20개도 넘게 공유를 하시던 분이라면, 공유하는 모든 항목이 자신의 미투데이에 포스팅되는 것이 꽤나 부담스러울 것입니다. 이런 경우 필터를 활성화하여 원하는 피드만 미투데이로 보내게 할 수 있습니다.

공유항목에 노트를 썼을 때만 포스트 – 구글리더에는 ‘공유’ 와 ‘메모와 함께 공유’ 를 할 수 있습니다. 이 필터가 활성화 되어있을 경우 그냥 ‘공유’ 한 것은 미투데이로 보내지지 않고 ‘메모와 함께 공유’ 한 항목만 미투데이에 보내지게 됩니다.

노트 내용에 #me2day를 썼을 때만 포스트 – 위의 필터만으로는 부족하시다면 ^^ 이 필터를 사용하여 거의 완벽히 미투데이로 포스트되는 피드를 걸러낼 수 있습니다. 공유하고자 하는 항목의 노트 내용 맨 앞이나 맨 뒤에 #me2day 라고 쓴 포스트만 미투데이에 포스트해주는 필터입니다. 물론 실제 포스트 내용에는 #me2day 가 빠져서 등록됩니다. 예를 들어 노트 내용에 ‘허허 이게 참 말이 되는 얘기인지.. #me2day’ 라고 쓰셨을 경우 ‘허허 이게 참 말이 되는 얘기인지..’ 만 들어가게 됩니다.

이렇게 설정을 다 하셨으면, 하단의 ‘설정저장’ 버튼을 눌러주셔야 실제로 계정이 활성화가 됩니다. 만약 미투 구글리더가 마음에 안드신다면 ^^ 그 옆 버튼인 ‘연동끊기’를 눌러 미투 구글리더가 미투데이에 어떤 포스트도 보내지 않도록 막아두실 수 있습니다.

그럼 미투 구글리더와 함께 재미난 미투데이 하시길 바랄께요!

여기까지 rath 였습니다.