hello world 2014. 10. 31. 13:20

telegram-cli 이걸로 뭐하지?


Telegram(https://telegram.org이 국내에서 흥하게 되었는데, 이 텔레그램이 OPEN API 입니다.

telegram-cli 란 linux 용 프로그램입니다. 스크립트나 콘솔명령으로 메세지를 보낼 수 있습니다.

그럼 이걸로 뭘 하나 생각해 보니


1. 심심이 


2. 카톡 미연시


3. 서버 제어 : http://truefeel.tistory.com/224


4. 장애 알림

5. REST 를 이용한 MSG 발송 

등등.. 서버 프로그래머 입장에서 해보고 싶은게 많습니다.


서론은 여기까지.. 텔레그램을 깔아 봅시다.


Linux 에서 늘 하던데로 소스받고,  configure , make 하면 끝~

https://github.com/vysheng/tg 에 잘 설명 되있습니다.


OS 는 CentOS 에 설치 했습니다.


1. 소스받고 압축 풀고

 wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip
 unzip tg-master.zip && cd tg-master

2. 빌드에 필요한 패키지 깔고

 sudo yum install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel

3. 빌드하면 끝 !

 ./configure
 make

이건 CentOS 7 얘기... 현실은

event-old.h: In function 'event_new':
event-old.h:16: error: implicit declaration of function 'malloc'
event-old.h:16: error: incompatible implicit declaration of built-in function 'malloc'
event-old.h: In function 'evtimer_new':
event-old.h:24: error: incompatible implicit declaration of built-in function 'malloc'
event-old.h: In function 'event_free':
event-old.h:33: error: implicit declaration of function 'free'
event-old.h:33: error: incompatible implicit declaration of built-in function 'free'
tgl-timers.c: In function 'tgl_timer_free':
tgl-timers.c:59: error: implicit declaration of function 'event_get_callback_arg'
tgl-timers.c:59: error: initialization makes pointer from integer without a cast
make: *** [objs/tgl-timers.o] Error 1

난 CentOS6 이지...

이럴땐 !! 예전이었다면 아둥바둥 왜 안되는지 알아보고, 이것저것 고쳐보고...했겠지만 

이젠 Docker 를 사용합니다.


Docker - An open platform for distributed applications for developers and sysadmins. 

https://www.docker.com


설치와 사용법은 나중에 자세히 알아보고 docker 로 CentOS 7 환경을 올립니다. 

[root@localhost ~]# docker pull centos 

로 이미지 받아와서 들어가면 CentOS7 환경에서 작업할 수 있습니다.

[root@localhost ~]# docker run -i -t centos:centos7 /bin/bash
bash-4.2# cat /etc/redhat-release
CentOS Linux release 7.0.1406 (Core)
위 예제로 들어가면 image 를 띄운거기 때문에 나오면 데이터가 다 없어집니다.
이미지와 컨테이너의 차이를 느껴보시고,
만약에 docker 안에서 port를 listen 할 일이 있다면 -p 옵션으로 포트도 포워딩 해줘야 합니다. -p 8080:8080 으로 

[root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED ...

cd2b01f5645f centos:centos7 /bin/bash 2 minutes ago ... 9b05fb4f5b8f centos:centos6 /bin/bash 12 minutes ago ... 62368a818401 9b9939481a40 /bin/bash 16 hours ago ... e9d15253d9d7 cc7c33cb9d68 /bin/bash 16 hours ago ...

당황하지 않고 사용한 컨테이너 ID를 찾아서 commit 하면 image 로 생성되어 다음에 작업했던데 부터 사용할 수 있습니다. 자세한 사용법은 나중에?


centos7 환경에선 잘 됩니다.

ar: creating libs/libtgl.a a - ./objs/net.o a - ./objs/mtproto-common.o ....... a - ./objs/updates.o a - ./objs/tgl-timers.o a - ./objs/tools.o gcc ./objs/main.o ./objs/loop.o ./objs/interface.o ./objs/lua-tg.o .........

telegram-cli 를 실행해서 내 번호를 등록합니다. 나중엔 ID만으로도 가입된다고 하니 기다려 봅시다.
bash-4.2# bin/telegram-cli
change_user_group: can't find the user telegramd to switch to
Telegram-cli version 1.1.0, Copyright (C) 2013-2014 Vitaly Valtman
Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show_license' for details.
I: config dir=[//.telegram-cli]
Telephone number (with '+' sign): 
인증번호를 확인해서 넣어주면 사용이 가능합니다.

Telephone number (with '+' sign): +8210******** Code from sms (if you did not receive an SMS and want to be called, type "call"): 36692 >

어떻게 사용하는지 help 를 확인해 보면 주르륵~

help    Prints this help

contact_list    Prints contact list

stats   For debug purpose

history <peer> [limit] [offset] Prints messages with this peer (most recent message lower). Also marks messages as read

dialog_list     List of last conversations

send_photo <peer> <file>        Sends photo to peer

send_video <peer> <file>        Sends video to peer

send_audio <peer> <file>        Sends audio to peer

send_document <peer> <file>     Sends document to peer

send_text <peer> <file> Sends contents of text file as plain text message

chat_info <chat>        Prints info about chat (id, members, admin, etc.)

user_info <user>        Prints info about user (id, last online, phone)

fwd <peer> <msg-id>     Forwards message to peer. Forward to secret chats is forbidden

fwd <peer> <msg-id>     Forwards message media to peer. Forward to secret chats is forbidden. Result slightly differs from fwd

msg <peer> <text>       Sends text message to peer

....

우선 주소를 등록하고 보내 봅니다.

> add_contact +8210******** yongdae kwon

yongdae kwon

> msg yongdae_kwon hello

[02:14]  yongdae kwon <<< hello

잘 되네요 ( 주의 : firstname 과 lastname 사이에 '_' 를 넣으셔야 합니다. )

bash 에서 보내보겠습니다.
bash 에서 실행할때는 몇가지 옵션이 필요합니다. -k 로 인증키를 지정해주고 -W 옵션으로 지연처리?를 해주고..

bash-4.2# echo "msg yongdae_kwon hello" | bin/telegram-cli -k ./tg-server.pub -W

change_user_group: can't find the user telegramd to switch to

Telegram-cli version 1.1.0, Copyright (C) 2013-2014 Vitaly Valtman

Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.

This is free software, and you are welcome to redistribute it

under certain conditions; type `show_license' for details.

I: config dir=[//.telegram-cli]

User Telegram updated photo

User SANGWOOK KWON updated photo

> msg yongdae_kwon hello

[03:22]  yongdae kwon <<< hello

> All done. Exit

잘 보내집니다.


node.js 의 express 와 연결해서 보내봅시다.

javascript 를 추가 하고

var exec = require('child_process').exec; app.get('/msg', function( req, res ) { var _cmd = 'msg ' + req.param('id',null) + ' ' + req.param('msg',null); console.log( _cmd ); exec( "echo '" + _cmd + "' | telegram-cli -k /home/tg-master/tg-server.pub -W " , 

function(err, stdout, stderr) { 

if(err) { 

console.log(err.message); 

} );

res.send('send msg');

});

웹에서 접근하면~

잘 보내지네요.


Lua Script 를 이용하면 ( 참고 : http://truefeel.tistory.com/224 )

function on_msg_receive (msg)

if ( msg.text == 'hello' ) then

send_msg(msg.from.print_name, "world", ok_cb, false)

return

end

end

function ok_cb(extra, success, result)

end

스크립트와 함께 돌리면

bash-4.2# bin/telegram-cli -s ../hello.lua
change_user_group: can't find the user telegramd to switch to
Telegram-cli version 1.1.0, Copyright (C) 2013-2014 Vitaly Valtman
Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show_license' for details.
I: config dir=[//.telegram-cli]
 *** lua: attempt to call a nil value
 *** lua: attempt to call a nil value
 *** lua: attempt to call a nil value
[03:30]  yongdae kwon ««« hello
 *** lua: attempt to call a nil value
[04:07]  yongdae kwon <<< world
hello 라고 새로온 메세지에 wold 라고 보냅니다.
잘되네요...

쉘스크립트에 포함에서 사용해서 모니터링으로 사용해도 좋고,
돈을내고 문자서비스를 이용하는 대신 텔레그램을 사용하는 것도 나쁘진 않을것 같습니다.

하지만 내 전화번호로 인증해야하니 회사에서 사용하기는 그렇고, 나중에 ID 인증이 된다면 그때 다시 생각해 보는걸로...


hello world 2014. 1. 14. 18:56

Google Protocol Buffer 사용해보기 - 개정판

저번에 너무 대충 쓴거 같아서 차근차근 해볼수 있도록 다시 올려봅니다.


우선 소스를 받습니다. ( https://code.google.com/p/protobuf/ )

까보면 대충 폴더가 이렇습니다.


vsproject 폴더에서 protobuf.sln 파일을 찾아서 visual studio 같은걸로 빌드해줍니다.


debug 나 release 든 폴더에 protoc.exe 파일이 생성됩니다. 이걸로 .proto 파일을 .h 와 .cc 로 만들어 주게 됩니다.

 
message Person {
    required string name = 1;
    required int32  id = 2;
    optional string email = 3;
 
    enum PhoneType {
      MOBILE = 0;
      HOME = 1;
      WORK = 2;
    }

    message PhoneNumber { 
        required string number = 1;
        optional PhoneType type = 2 [ default = HOME ];
    }
    repeated PhoneNumber phone = 4;
}


옵션을 잘 골라서 이전에 만든 proto 파일을 잘 역어주면... pb.cc 파일 과 pb.h 파일이 생성 됩니다.

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/test.proto

이라고 tutorial page 에 되어있습니다만 저는 .bat 파일 만들어서 실행하고 있습니다.

del .\output\*.h

del .\output\*.cc

for %%a in (*.proto) do protoc.exe -I=. -I=../../protobuf-2.5.0/src --cpp_out=./output/ %%a

pause

사용할 때는 Directory 와 lib 파일을 설정해야 합니다.

1. Include path : protobug-2.5.0/src


 2. library path : 아까 build한  output 폴더 


 3. library file : libprotobuf.lib



이제 사용할 일만 남았어요


myfile 이라는 파일에 fstream 을 이용해서 저장하고, 다시 파일에서 일거와서 메모리에 가져와서 출력해 보겠습니다.


우선 include 부터 하고

 #include "test.pb.h" 


쓰기.

Person person;                      // proto 에서 저장한 객체를 사용 할 수 있습니다.
person.set_name("John Doe");        // 기본적으로 set_이름, get_이름 을 사용할 수 있습니다.
person.set_id(1234);
person.set_email("123@test.com");

fstream _output( "myfile", ios::out | ios::binary);   
person.SerializeToOstream(&_output);        // myfile 이란 파일에 바로 써버립니다.
_output.close();


읽기.

fstream input( "myfile", ios::in | ios::binary );  // myfile 이란 파일에서 읽습니다.
Person personReadMsg;
PersonReadMsg.ParseFromIstream(&input);
cout << "Name: " << personReadMsg.name() << endl 
       << "Email : " << personReadMsg.email() << endl;


결과 .



간단하게는 이렇게 써볼 수 있습니다.

실제로는 SerializeToString 이라던지 SerializeToArray 함수를 이용해서 소켓 버퍼에 써서 통신하고 있습니다.


한가지 특이한 점?은 동적으로 스키마를 만들 수 있습니다.

DynamicMessageFactory 를 찾아 보시면 됩니다. - 나중에 시간되면 알아보는걸로..


이걸가지고 뭘 하냐면, 클라이언트에서는 proto 파일을 갖고 있지않고, 서버에서 보내준 스키마를 사용합니다.

서버로 부터 받은 스키마를 통해 xml 로 Parsing 해서 가공해서 사용하고 있습니다.


ps : 저번에 쓴글에 오류가 많아서 다시한번 protobuf 에 대해서 써봤습니다. 지난글은 잊어주세요 ㅋㅋㅋ

hello world 2014. 1. 13. 17:16

Google Protocol Buffer 사용해보기

참고 : https://developers.google.com/protocol-buffers/?hl=ko


구조화된 데이터의 직렬화( Serializing )를 도와줌


  • 장점 : 익숙한 포멧으로 사용하기 편하고, 다양한 플랫폼을 지원함
  • 단점 : cpp 의 경우 proto 파일이 변경되면 컴파일 해야하고, 그로인한 .h파일의 변경으로 전체 빌드가 될 가능성이 높음

프로토콜의 정의 ( .proto 파일 )

message Person {
    required string name = 1;
    required int32	id = 2;
    optional string	email = 3;

    enum PhoneType {
	MOBILE = 0;
	HOME = 1;
	WORK = 2;
    } 
    message PhoneNumber { 
        required string number = 1;
        optional PhoneType type = 2 [ default = HOME ];
    }
    repeated PhoneNumber phone = 4
}


Cpp 에서 사용 - 쓰기 


proto 에서 정의한 내용을 class 로 사용할 수 있고, 각 멤버 함수를 사용할 수 있다

멤버함수는 알아서 찾아보시고...

Person person;
person.set_name(“John Doe”);
person.set_id(1234);
person.set_email(“123@redduck.com”)
fstream input(“myfile”, ios::in | ios::binary);
person.SirializeToOstream( );

Cpp 에서 사용 - 읽기 


네트워크에서 읽어온 버퍼를 읽던지, 파일에서 읽던지, outstream 에서 읽던지... 

읽으면 클래스에 값이 채워짐

fstream input(“mysql”, ios::in | ios::binary );
Person person;
person.ParseFromIstream(&input)
cout << “Name: “ << person.name() << endl 
     << “Email : “ << person.email() << endl;


Memory DB 와 사용 예 : 

  1. 프로토 버퍼의 SerializeToString 함수를 사용하여 보내는 패킷자체의 String 을 Key-value DB ( 난 couchbase 사용 ) 에 저장 
    1. key='user_id:record' value='......' 이딴식
  2. 다른 유저의 전적을 확인할때, memory-db에 없으면 oracle 에서 찾아서 데이터를 가공한후 memory-db에 저장
  3. 다른 유저 or 같은 데이터를 요청 할때 memory-db 에서 찾아서 클라이언트에 보내줌
  4. memory-db 에 data를 변경할 필요가 있는 경우 그냥 지워버림 ( 그럼 다시 2번 과정 )
tip : 
  • int (int32, uint32, int64, uin64)의 필드를 repeated 로 선언하는 경우 뒤에 [ packed=true ] 옵션을 를 사용하면 패킷이 더 컴팩트 해진다고 합니다. 무조건 붙이세욧

ps : C#에서는 더럽게 편하다고 상욱이가 그랬음




hello world 2014. 1. 13. 15:17

Release Build에서 변수 깨지지 않고 보는 방법


가끔 릴리즈 빌드에서 디버깅을 해야하는 상황이 있습니다.

대부분의 경우 변수값이 깨져서 나오는데, 컴파일 옵션 하나만 추가하면 디버그 빌드처럼 변수를 확인할 수 있습니다.


Visual C++ 2012 이상에서 가능하고, 정식 지원은 아니랍니다.


* 참고사이트 : http://kblog.popekim.com/2013/11/how-to-debug-optimized-code-in-vc2012.html

* 참고사이트 : http://randomascii.wordpress.com/2013/09/11/debugging-optimized-codenew-in-visual-studio-2012/


* 컴파일옵션


 /d2Zi+


현재 진행중인 프로젝트에 적용해봤습니다. (참고로 VS 2012에서 개발 중입니다.)

* 컴파일옵션 적용



* 옵션 적용 전 Watch창



* 옵션 적용 후 Watch창



같은 라인에서 브레이크포인트를 잡고 테스트했는데, 잘 나오네요.


실행 파일은 건들지 않고(확인해보니 파일 크기도 동일), PDB만 바뀐다고하니, Release 빌드에 컴파일 옵션을 추가해줘도 문제가 없을 것같습니다.


hello world 2014. 1. 13. 13:57

글 작성시 syntax highlighter 적용하기

글쓰기를 할대 소스코드를 이쁘게 쓰기 위해서 html 태그를 사용 할 수 있습니다.

소스코드를 보기 좋게 작성하기 위해서는 html 태그를 키고, 

<pre class="brush: cpp" > .... 소스 ....</pre> 

태그 안에 내용을 작성하면 됨

  1. CPP 의 경우 ( calss='brush: cpp' )
    class HighlighterTest {
     bool test( int val ) { 
       if( val > 0 )
        return true;
       else 
        return false;
     }
    };
    
  2. XML 의 경우 ( calss='brush: xml' )
    
      
        12345