기본 콘텐츠로 건너뛰기

8월, 2012의 게시물 표시

Meteor 에서 REST 사용

Meteor 에서 file-upload 라던가 REST API 같은 걸 제공하려면
request 를 받아서 처리할 수 있어야하는데 Meteor 에선 지원하지 않아 좀 답답한 면이 있다.

하지만 그래봤자. Node.js 고 connect 프레임워크를 사용하고 있기 때문에
저번에 언급한 적이 있던 __meteor_bootstrap__ 를 이용해보자.

./.meteor/local/build/server/server.js 를 보면 서버쪽 구동부를 볼 수 있는데
run function 쪽을 보면


  __meteor_bootstrap__ = {require: require, startup_hooks: [], app: app};

이런 코드가 있다. 여기서 app은?
그 위쪽에 
  var app = connect.createServer();
어이쿠 connect 네. 게임 끝나셨다.
서버쪽에 아래와 같이 stack array 에 route 를 추가하면 된다.
Meteor.startup ->   app=__meteor_bootstrap__.app   app.stack.unshift     route: "/api",     handle: (req,res)->       res.statusCode = 200       res.write "OK"       res.end()
다행이야 다행이군!

meteor 0.3.9 에서 사용자 인증을 써보자.

예전에 everyAuth 에 대한 글을 쓴적이 있는데
https://github.com/meteor/meteor/wiki/Getting-Started-with-Auth
meteor wiki에 위와 같은 글이 있더라.
발빠르다 meteor. 투자받더니 탄력이 붙었는지 쭉쭉 잘나가는군.
일단 meteor 설치부터 다시하자.
이전에 Quick start 가이드대로

curl https://install.meteor.com | /bin/sh
이렇게 설치했지만.
이번엔 git 에서 auth Branch를 따서 갈 것이므로 수동 설치하자.

git clone git://github.com/meteor/meteor.git cd meteor 수동설치래봤자 적절한 곳에 clone 하고
인스톨 하는게 전부인데.

auth는 다른 branch에 있기 때문에 일단 clone 하고 해당 경로에 진입만한 상태에서
git branch -r 로 리모트 브랜치를 확인해보자

  origin/HEAD -> origin/master
  origin/auth
  origin/auth-email
  origin/auth-test-isolation
  origin/auth-twitter
  origin/avital
  origin/avital-remove
  origin/avital-watch
  origin/david-handlebars
  origin/dev-bundle-bump
  origin/devel
  origin/email
  origin/forms
  origin/jade
  origin/master
  origin/release-0.1
  origin/release-0.1-templates
  origin/spark
  origin/spiderable
  origin/test-isolation
  origin/version-bump
  origin/webgl
  origin/wrappedjs
  origin/{ref}squashed-auth

이렇게 주욱 나올텐데 우리가 필요한 건

  o…

angular.js + node.js + express 로 JSONP 구현을 해보았다.

크로스도메인 문제(다른 사이트의 ajax를 호출할 수 없는 브라우저의 보안정책)를 피하기 위해 JSONP라는 대안이 있는데
angular를 이용해 간단하게 목록을 가져오는 외부 호출을 만들어보자.
http://docs.angularjs.org/api/ng.$http#jsonp
내용을 보고 참조하였다.

index.html
<!DOCTYPE html>
<html ng-app>
<head>
    <title></title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    <script type="text/javascript" src="todo.js"></script>
</head>
<body>
<div>
    <div ng-controller="listController">
        <ul>
            <li ng-repeat="list in lists">
{{list.author}}
            </li>
        </ul>
    </div>
</div>
</body>
</html>

ng-app 을 설정하고 listController 에 lists 객체로부터 author 목록을 가져오게 하자.

todo.js

listController = function($scope,$http) {
    angular.extend($scope,{
        query:function() {
            $http.jsonp('http://jsbin.com/uqamef/1?callback=J…

javascript에서 forEach의 성능 문제

http://jsperf.com/for-vs-foreach/9 를 보고 forEach가 정말 그렇게 느려?
라고 생각이 들어서 node 커맨드라인을 열고 아래와 같이 처 넣고 실행.
어짜피 IE에서도 안되는거 Array를 prototype 확장하여 forEach 를 만들어서 쓰곤 했다.

Array.prototype.forEach=function(callback) {
  for (var i=0,len=this.length; i<len; i++) {
    callback(this[i], i);
  }
}
그래서 이것도 넣어서 같이 돌려봤다.

--------------------------

var i, values = [], sum = 0;
for (i = 0; i < 10000; i++) {
 values[i] = i;
}

function add(val) {
  sum += val;
}

var itercount =2000;

sum=0;
time = +new Date();
for (var _i=itercount; _i>=0; _i--) {
  values.forEach(add);
}
console.log("forEach legacy:"+ (+new Date()-time));

sum=0;
time = +new Date();
for (var _i=itercount; _i>=0; _i--) {
  for (i = 0; i < values.length; i++) {
    add(values[i]);
  }
}
console.log("simple for:"+ (+new Date()-time));

Array.prototype.forEach2=function(callback) {
  for (var i=0,len=this.length; i<len; i++) {
    callback(this[i], i);
  }
}

sum=0;
time = +new Date();
for (var _i=itercount; …

XCode OS X Application : Drag & Drop 후 파일 처리

개인적으로 필요한 유틸이 있어서 appleScript 로 만들까하다가 XCode 4.4 로 OS X Application 을 만들어 본 적이 없어서 Drag & Drop, Pipe, File 처리 같은 걸 해봤다.
xib 에 드래그할 대상인 NSImageView 를 놓고 그 NSImageView 를 Customize 한 NSCImageView 를 만들어서 구현했다. performDragOperation 이벤트에서 
NSPasteboard  *paste = [sender draggingPasteboard]; 로 NSPasteboard 객체에 드래그 한 것들을 가지고 NSFilenamesPboardType 인것들을 타입으로 추출하여 NSData로 받았다.

NSArray *fileArray = [paste propertyListForType:@"NSFilenamesPboardType"]; 파일 목록은 propertyListForType으로 string array 를 받을 수 있다.
http://borkware.com/quickies/one?topic=nstask
shell 실행하고 결과 stdout 을 받는 것 처리하는데 위의 링크를 참조했다.
  NSTask *task = [[NSTaskalloc] init];   [task setLaunchPath:@"<SHELL COMMAND>"];
NSTask 를 setLaunchPath 메서드를 사용하여 콜할 커맨드를 지정하고
  [task setArguments:[NSArrayarrayWithObjects:<@args>, file, nil]];
N개의 argument 를 지정
  NSPipe *pipe=[NSPipepipe];   [task setStandardOutput:pipe];

실행 후 stdout 을 출력할 대상을 pipe 로 돌려놓고
  [task launch];
로 실행.
  NSFileHandle *fileHandle = [pipe fileHandleFor…

express 2.0 에서 3.0으로 바꿀때 주의할 점.

하드 파티션이 날아가서 새로 셋업하고
작업하던 소스를 받아와서 아무생각 없이 npm install 했더니
express 3.0으로 되어있더라.

기존의 소스는

express = require 'express'
gzippo = require 'gzippo'
fs = require 'fs'
http = require 'http'
app = express.createServer()
path = require 'path'

tmpl =
  compile: (source, options)->
    (locals)->
      # 여기에 템플릿 뽁찡
      source

port = process.env.VMC_APP_PORT || 3000
app.configure ->
  app.set 'views', "#{__dirname}/../public"
  app.use app.router
  app.set 'view options', layout: false
  app.set 'view engine', 'html'
  app.register '.html', tmpl
  app.use gzippo.staticGzip "#{__dirname}/../public"

app.get '/', (req,res) ->
  res.render "./html/index.html"

app.listen port, ->
  console.log "Listening on #{port}"

이런 식으로 썼다면



express = require 'express'
fs = require 'fs'
http = require 'http'
app = express()

tmpl = (path, options, fn) -&…

facebook, Google+, Diaspora* 3종 SNS AJAX 메시지 비교

일 관계로 SNS 비슷한 걸 만들고 있는데
데이터 모델을 하기 귀찮은 관계로 남이 한걸 베낄려고 facebook, google+, diaspora 의 XHR을 분석해보고 있다.
1. facebook 역시 예상했던 대로 지저분. entries 라는 객체 밑에 app, group, page, friendlist 등이 마구 혼재 본문 내용은 초기로드시에  <code class="hidden_elem" id="u33ari_19"><!-- <li>.... --> 이런 형태로 뿌리고 MoreStoriesPagelet 을 통해 Document 요청. app, group, page, friendlist 같은 건 본문과는 다르게 처리했는데 뭐 닭짓 아닌가? 하긴 원래 글 한번 쓰면 못바꾸는 구조로 처음에 만들어서 별도로 처리한득.
주기적으로 pull 이라는 heartbeat(클라이언트에서 서버찌르기)을 통해 json을 받아옴.
for (;;); {"t":"heartbeat"} {"t":"heartbeat"} {"t":"continue","seq":2}
결과값은 이런 형태. 전세계 클라이언트로부터 DDOS 공격을 잘도 버티고 있네 ㅎㅎ
2. Google+ 얘들은 성능을 위해 json 데이터 구조를 사용하지 않는다.
그럼 어떻게 하냐고?
)]}'
[[["f.ri","12015082395849449"]
,["ghr",[]
]
,["di",136,,,,,[]
,[]
,,,[]
,[]
,[]
]
,["e",4,,,125]
]]
이런식의 중첩 배열을 사용한다.
마치 C Struct로 만든 전문통신을 보는 느낌인데 데이터를 본다고 알수 있는 구조가 아니다.
물론 주고 받는 쪽에서야 몇번째는 무엇이라고 …

node.js(+express) everyAuth 적용기

node.js 용 package 중 everyAuth 라고 상당히 많은 서비스 API를 지원하는 훌륭한 라이브러리가 있다.
facebook, google, twitter 는 물론이고 github 에서 instagram 까지도 지원한다.
맨땅에 하기엔 사실 사용자 로그인/인증이라는 과정이 간단하지 않다.
설명을 쭉 읽어보니 그냥 커스텀 인증을 한다고 해도 구조가 잘 잡혀있어서 써야겠다고 결심.
express 프로젝트를 만들었다.

일단 facebook 부터 시작해보기로 했다.
먼저 OAuth 인증을 하려면 facebook 으로부터 appId 와 appSecret 두개 한쌍을 페어로 받아와야한다.

https://developers.facebook.com/apps 에서 "새 앱 만들기"를 한다음
App Name을 정해주자. Namespace랑 Web Hosting은 사용하지 않으므로 그대로 내버려둠.

그러고 난 뒤 보안 텍스트 확인하면
앱 > 앱이름 > Basic 으로 이동한다.

보면 앱이름과 App ID, App Secret, 아이콘을 확인할 수 있다.
아이콘은 적당히 수정하면 되고

"기본정보"와 "어떻게 앱을 Facebook과 통합시킬지 선택하세요"
두가지 설정 항목이 있음을 확인하고 "어떻게 앱을 Facebook과 통합시킬지 선택하세요" 에서 Website with Facebook Login 를 체크하면 사이트 URL 을 넣을 수 있다.
리디렉트 할 사이트 URL 을 넣고 변경 내용 저장.

일단 이걸로 facebook 준비는 끝났다.
별도의 facebook 앱 페이지를 만들거나 할 필요는 없다.

server.js 에 대략 구현하기를 (coffeescript)


everyauth = require 'everyauth'


# mock User list
user = {}

# set up for everyAuth
everyauth.facebook
  .appId(config.f…