애플도 버린 1세대 아이패드 탈옥으로 새생명 불어넣기

벌써 3년전인가? 기억도 가물거린다. 여튼 애물단지 1세대 아이패드는 하드웨어가 너무 꾸져서 iOS6로 업그레이드도 안되는 구닥다리다. 이미 애플에서도 버린 자식이다.  64GB 되는 용량이지만 USB로 쓰기엔 너무 무겁다. -_-;; 그러다가 문득 토렌토만 받을수 있다면… 이라는 생각이 들어서 어제부터 씨름을 시작했다. 그리고 결국 해냈다.. ㅋㅋㅋ 자 그럼 지금부터 알아보자!

1. 탈옥하기

일단 탈옥을 해야한다. 완탈은 이미 너무나 쉽게 할수 있으므로 따로 설명안하겠다. 검색하면 나온다.

2. Cydia에서 필요한 소프트웨어 다운받기

이제 기본 소프트웨어를 설치하자. 다음 프로그램을 Cydia에서 다운받자.

  • Aptitude
  • Core Utilities
  • iFile
  • MobileTerminal
  • OpenSSH
  • Vi IMproved 추가로 위 소프트웨어를 깔았다면 MobileTerminal 이나 SSH접속을 통해서 아이패드 root 패스워드를 바꿔본다. 물론 안해도 상관없지만, 터미널 상에서 커맨드 입력을 나중에 해야하기 때문에 터미널에 익숙해질겸 미리 해두는 것이 좋다.

3. 토렌토 설치하기

맥용 소프트웨어 중에 유명한 토렌트 클라이언트가 있다. 바로 Transmission!! 이 녀석이 iOS 버전도 있었다! +_+_+ 바로 iTransmission! 다운로드는 역시 Cyida 에서 다운로드 받을수 있다. 다운로드 받을때는 CLI부터 설치하고 클래식 버전과 iTransmission 2를 차례로 설치한다. iTransmission 3도 있는데, 3는 iOS6용 인지 내 아이패드에선 안되는 건지 여튼 난 그냥 2 까지만 업그레이드 했다. 자 이제 아이패드 바탕화면에는 Terminal과 iFile 그리고 iTransmission 이 설치되어 있을것이다. 만약 아이콘 그냥 백지상태로 있다면 아이패드를 끄고 다시 부팅하면 제대로 된 아이콘으로 보인다.

4. 토렌토 파일 다운로드 하기

토렌토 파일을 다운로드 받으려면 별도의 사파리 플러그인이 필요하다. Cydia에서 Safari Download Plug-In을 설치한다. 그리고 웹서핑 후 토렌토 파일을 다운로드 하면 iTransmission으로 연결할수있을 것이다. 가끔 토렌토 파일이 다운로드 되지 않는 경우가 있을텐데.. 이럴땐 PC에서 다운로드 받아 Transmission으로 연다음에 magnet 주소를 복사해서 iTransmission에 붙여넣으면 된다.

5. ipa 파일 설치하기

NPlayer이나 AVPlayer는 모두 유료 어플이지만 탈옥을 했다면 이런 유료 어플도 손쉽게 ipa를 구해서 설치할수가 있다. 일단 모바일 사파리의 경우 ipa 파일이 다운로드가 되지 않으므로 안드로이드폰이나 PC에서 해당 ipa 파일을 다운로드 받은 다음 아이패드로 옮긴다. 아이패드로 옮기는 방법은 여러가지가 있지만 나는 Dropbox 공유를 통해서 아이패드로 다운로드 받았다. 아이패드로 파일을 옮겼다면 이것을 다시 설치해야한다. 일단 설치하기 쉽도록 터미널의 기본 위치인 /var/mobile 폴더로 옮겨놓자. 옮기는 방법은 iFile에서 옮겨도 되고, 터미널 상에서 mv 명령어를 이용해도 된다. 이제 ipa 파일 설치를 위한 프로그램을 깔아보자. cydia에서 IPA Installer Console 을 설치하자. 설치한 후에는 터미널에서 #> ipainstaller 파일이름.ipa 를 입력하면 설치가 된다.  

6. 별도 cydia 소스 파일

탈옥할 경우 기본으로 포함된 패키지 저장소 소스파일이 있는데 혹시나 없을 경우에는 추가하면 된다.

  • http://apt.thebigboss.org/repofiles/cydia/
  • http://apt.saurik.com/
  • http://repo.insanelyi.com/
  • http://apt.modmyi.com/
  • http://cydia.xsellize.com/
  • http://cydia.zodttd.com/repo/cydia      

생각대로 되는 nodejs, 또 잊어먹기 전에 메모!

지난달부터 재미삼에 패치팡이란 애니팡 아류작을 하나 맹글어보고 있는데, 부득이(?)하게 랭킹서버까지 만들어야했다. 그리고 지난주였나? 페북과 연동해서 친구들과 경쟁구도를 만들기 위해 랭킹서버를 약간 수정했다. 물론 데이터 모델도 달라졌고, API도 약간의 수정이 있었다. 귀차니즘에 수정을 최소화하다보니 많은 기능을 넣지는 않았음에도 불구하고 삽질의 연속이었다. 그때 정리했어야하는데 일단 잊어먹기 전에 생각나는대로 정리해보자.

1. 청크(Chank)데이터 이어붙이기 일단

페이스북 Graph API를 이용해 친구목록을 가져와야했다. 페이스북의 모든 API는 https로 호출한다. (혹시 http로 호출하는 API가 있을찌도 모르겠으나,.. 일단 문서에는 없는듯..) 뭐 https도 암호화와 패킷 검증을 제외하면 프로토콜은 http와 거의 대동소이하다.  여튼 nodejs를 이용해 API 호출후 응답을 받으려면 다음과 같이 ‘data’ 이벤트를 통해 데이터를 수신받는다.

var https = require('https');
var url = 'https://graph.facebook.com/me/friends?fields=id&access_token='+ token;
https.get(url, function(response) {
    response.on('data', function(chunk) {
        console.log('receive.. chunk data...', chunk);
        var friends = JSON.parse(buffer.join(''));
    });
});

HTTP와 HTTPS 객체에 대한 보다 자세한 설명은 nodejs API 문서 를 참고하자. 위와 같이 코드를 작성하고 실행해보면 간간히 JSON.parse 중에 에러가 난다. 아! 왜 자꾸 에러나는거야? 짱내고 있었는데.. 생각해보니 data 이벤트로 받는 녀석은 chunk 단위다! 그럼 당연히 데이터가 짤릴수도 있는거지! 아하~~ 😀 물론 한번에 담겨서 넘어올때도 있지만ㅋㅋㅋ 여튼 콘솔에 값을 출력해보면,.. [Buffer 0x45…..] 버퍼 어쩌구저쩌구가 찍힌다 그래서 버퍼에 담았다가 이어붙이면 되겠다 싶었다. 그런데!!! 어떻게하지? 어떻게 붙이지? Buffer 객체를 만들어야하나? Stream 객체로 해야하나? 서버개발에 익숙치 않으니 Java에서 쓰던 방법들을 동원해서 별에별 방법을 다 써봣다. 너무 Java틱했나? 결론은 다 잘 안됐다. OTL… 도대체 왜 안되는거야? 라고 씩씩대면서 4시간을 날렸다. 그런데 해결책이 아~ 허무해~~! 너무나 단순했다. 그냥 배열에 담았다가 join만 하면 되는거였어!! 정말 javascirpt 다운 해결책!~ ㅜㅜ 아~ 내 아까운 시간~ 그래도 뭐 4시간동안 API문서보고 이거저거 해봤다는거에 위안을 삼으며 다음과 같이 수정!

var https = require('https');
var url = 'https://graph.facebook.com/me/friends?fields=id&access_token='+ token;
https.get(url, function(response) {
    var buffer = [];
    response.on('data', function(chunk) {
        console.log('receive.. chunk data...', chunk);
        buffer.push(chunk);
    });
    response.on('end', function() {
        var friends = JSON.parse(buffer.join(''));
    });
});

위와 같이 수정하면 데이터 짤림 없이 온전한 데이터를 파싱하는데 성공!!

2. Express 모듈에 미들웨어 장착하기

이번에도 다소간의 삽질이 있었지만, 이번엔 지극히 자바스크립트 다운 생각으로 임했더니 매우 쉽게 해결된 문제다. 먼저 nodejs 로 서버를 만들때 가장 많이 쓰는 모듈이 바로 Express 모듈이다. 이젠 거의 socket.io와 더불이 이바닥 표준이 아닌가 싶다. 여튼 GET 방식이든 POST 방식이든 요청 URL에 한글이 들어갈 경우 반드시 인코딩해서 넘겨야하고 서버에선 디코딩 과정이 필요하다.  아니면 서버에서 무조건 URL을 자동 인코딩해서 처리해야한다. 그런데 난 이 모든 것들을 Express가 알아서 해주는줄만 알았다. 그런데 그게 아니었다. ㅜㅜ 너무 맹신했나? 그래서 데이터를 넘길때 서버에서 인코딩하고 다시 응답을 만들때 디코딩하는 생쑈를 했다. 그런데 말이지.. 자꾸 이상한 생각이 든다,.. 이거 너무 귀찮은데,…-_-;;.. 왜 이걸 Express에서 안해주는거지?… API를 뒤졌다.. 역시!!.. 저 밑에 있네.. 바로

Middleware 라는 항목에.. 빙고~!!

app.use(express.bodyParser());

// is equivalent to:
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart());

바디파서 한줄이면 인코딩은 알아서 척척척 해준다. -_-;… 역시 자바스크립트는 생각대로 하면된다. 느무 조아요!! 일단 여기까지 또 생각나면… 이어서..

node를 이용한 초간단 랭킹 서버 만들기

몇일전에 애니팡과 비슷한 팡류 게임을 하나 만들었다. 이름하야 패치팡! ㅋㅋ 패치팡은 자바스크립트만으로 만들었고, 게임을 만드는데 꼬박 3일이 걸렸다. 3일중 이틀은 구조잡고 기본 알고리즘 만드는데 썻고, 나머지 하루는 대충 콜리로  UI만들고 포샵질 하느라 시간을 보냈다. 여튼 만들고 보니 뭔가 허전하다 제대로 쓸려면 내가 얻은 점수를 서버에 저장하고 친구들끼리 경쟁을 붙여야한다. 그래서 또 대충 랭킹 서버를 만들기로 했다.  랭킹 서버는 랭킹 정보를 저장할 DB가 있어야한다. DB는 SQL로 쓰려다가 쿼리 짜기 귀찮아서 그냥 몽고DB로 결정!!

1. 몽고DB 설치하기

일단 서버에 몽고DB 서버를 설치하고 설정해야한다. 설치와 설정은 다음 링크를 참고~!! 참고로 내 서버는 페도라다! 그리고 테스트 개발은 윈도우 환경에서 진행했다!

http://docs.mongodb.org/manual/tutorial/install-mongodb-on-red-hat-centos-or-fedora-linux/ 서버에 DB를 설치했으니 실행하자!

$service mongod start

2. 몽고DB를 읽고 쓰기 위한 node 모듈 설치하기

$npm install mongoose

물론 노드가 미리 설치되어 있어야한다. 뭐 노드는 이미 깔려있으니까.. 패스! 다음으로 RESTfull API로 만들어서 랭킹을 저장할 것이므로.. 간단한 웹 인터페이스 제작을 위해 express 모듈도 일단 설치!!

$npm install express

그리고 요즘엔 이녀석 없으면 코딩할 맛이 안난다. 바로 underscore.js!!! 뭐 안쓸찌도 모르겠찌만.. 일단 설치부터~~  

$npm install underscore

3. 몽고 DB 스키마 만들기

초간단하게 만들 것이므로 스키마도  간단하다. 물론 나중에 소셜을 연동할 것이므로 나중에는 좀더 복잡하겠지만, 지금은 그냥 동작 확인만 하면 되니까 이름과 점수만 기록하자!

var mongoose = require('mongoose');
var db = mongoose.createConnection('mongodb://localhost/test', {
    server : {
        poolSize : 10
    }
});
var RankSchema = new mongoose.Schema({
    point : Number,
    name : String
});
var PatchPangRank = db.model('PatchPangRank', RankSchema);

요렇게 만들어진 PatchPangRank는 RankSchema를 모델로 하는 일종의 Collection 이 된다. 기억해두자! 콜렉션!!  Backbone.js의 콜렉션과 유사하다고 보면 된다! 보다 자세한 몽구스 사용법은

API 문서를 참고하자.

4. RESTful API 서버 만들기

이제 DB는 대충 만들었고, 다음으로 서버를 구축해야한다. 서버는 당근 node를 이용할꺼다. 아까 설치한 express 모듈을 이용해서 간단하게 만들어보자!

var express = require('express');
var app = express();
app.get('*', function(req, res) {

    //일단 들어온 경우
    res.send('Hello!! Get the Fuck OUT!');

});
app.listen(8888);
console.log('starting server~!');

80번 포트가 아닌 8888번 포트인걸 감안하자. 80 포트로 만들면 아주 쉽겠지만,..  내서버의 80포트는 이미 nginx님아 차지하고 있다! 그래서 계획은 이렇다! 어찌됐는 /api/xxxx 형태로 호출되는 API는 프록시를 이용해 8888번 포트로 넘겨버릴 생각이다. 그럼 이제 API를 만들어보자. 대충 이런식으로 호출하면 점수가 기록되게 할 생각이다!

/api/add/score/[이름]/[점수]

그리고, 랭킹을 얻어오는 API는 대충 이렇다!

/api/get/ranks

뭐 대충대충.. 어떻게 만들지를 정했으니..  또 대충 서버에 해당 API를 추가해보자~!!

var express = require('express');
var app = express();

// 이 녀석은 점수를 추가하는 API
app.post('/api/add/score/:name/:point', function(req, res) {  });

// 이 녀석은 랭킹 정보를 가져오는 API
app.get('/api/get/ranks', function(req, res) { });

app.get('*', function(req, res) {
    //일단 들어온 경우
    res.send('Hello!! Get the Fuck OUT!');
});
app.listen(8888);
console.log('starting server~!');

이제 본격적으로 코딩해야할 시간이다~!!

5. 서버 API 만들기 먼저 점수를 넣는 것부터 만들어보자!!

app.post('/api/add/score/:name/:point', function(req, res) {
    var name = req.params.name;
    var point = req.params.point;
    var rank = new PatchPangRank({
        name : name,
        point : point
    });
    rank.save();
    res.send('{result: INSERT OK}');
});

아까 만들어둔 PatchPangRank에다가 점수를 기록하고 save()만 해주면 끝~!! 정말 간단하다~!! 물론 중복데이터는 걸려줘야한다… 그럼 중복데이터도 걸러내볼까? 난 이미 만들었지만.. 설명하기 귀찮타..-_- 힌트를 준다면.. PatchPangRank 객체에서 기존에 같은 이름이 있는지 검색한다. 대충 쓰면 요런식이 되겠다!!

PatchPangRank
    .find({ name : name })
    .exec(function (err, rank){
        if(err){ return handlerError(err); }

        // ...  여기다가 rank가 중복됐는지 확인하면 된다..
});

여기서 주의해야하는건 rank가 콜렉션이다! 그래서 배열로 넘어온다!! 다음으로 랭킹을 가져오는 API도 만들어보자!

app.get('/api/get/ranks', function(req, res) {
    console.log("--------");
    PatchPangRank
    .find()
    .limit(10)
    .sort('-point')
    .select('name point')
    .exec(function(err, rank) {
       if (err)  return handleError(err);

       var data = [];
       _.each(rank, function(v){
           if(!v.name){
               v.remove();
           }

           data.push({
               name : v.name,
               point : v.point
           });
       });

       var body = JSON.stringify(data);
       res.setHeader('Content-Type', 'x-application/json');
       res.setHeader('Content-Length', body.length);
       res.end(body);
   });
});

요건 뭐 너무 쉬워서 설명할 꺼리도 없겠다!!

5. 마지막 프락시 설정하기

아까도 이야기했지만, 내 서버는 엔진엑스가 80포트를 쓰고 있다. 그래서 노드는 뒷딴으로 밀려버린 상태.. 서버 설정에 프락시를 추가해준다.

location /api {
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_pass http://127.0.0.1:8888;
 }

짜잔~~ 이젠 정말 끝~!! 이제 https://miconblog.com/api/get/ranks 로 접근하면 기록된 랭키정보가 나와야한다! 물론 실제 랭킹서버가 이렇게 허술하진 않겠지만… 뭐 어찌됐든 점수를 기록하고 랭킹을 메겨주는건 맞으니까.. 보안 코드는 나중에 또 기회가 되면 얘기하는걸로 하고 여기까지 정리끝~!!