Node.JS와 Express를 이용한 디렉터리 파싱

Similar documents
Windows 8에서 BioStar 1 설치하기

zbrush 4r7 p3 crack macintoshinstmank

2파트-07

SproutCore에 홀딱 반했습니다.

UNIST_교원 홈페이지 관리자_Manual_V1.0

Prototype에서 jQuery로 옮겨타기

Microsoft PowerPoint - chap01-C언어개요.pptx

설계란 무엇인가?

WebGL 레슨 3 - 회전 운동

PowerPoint 프레젠테이션


Microsoft PowerPoint - 04-UDP Programming.ppt

Microsoft PowerPoint - chap10-함수의활용.pptx

Microsoft PowerPoint - ch10 - 이진트리, AVL 트리, 트리 응용 pm0600

Javascript.pages

chap 5: Trees

No Slide Title

Microsoft PowerPoint 세션.ppt

ActFax 4.31 Local Privilege Escalation Exploit

gcloud storage 사용자가이드 1 / 17

LXR 설치 및 사용법.doc

2009년 상반기 사업계획

Tcl의 문법

Mobile Service > IAP > Android SDK [ ] IAP SDK TOAST SDK. IAP SDK. Android Studio IDE Android SDK Version (API Level 10). Name Reference V

- 목차 - - ios 개발환경및유의사항. - 플랫폼 ios Project. - Native Controller와플랫폼화면연동. - 플랫폼 Web(js)-Native 간데이터공유. - 플랫폼확장 WN Interface 함수개발. - Network Manager clas

Week13

Modern Javascript

02장.배열과 클래스

제이쿼리 (JQuery) 정의 자바스크립트함수를쉽게사용하기위해만든자바스크립트라이브러리. 웹페이지를즉석에서변경하는기능에특화된자바스크립트라이브러리. 사용법 $( 제이쿼리객체 ) 혹은 $( 엘리먼트 ) 참고 ) $() 이기호를제이쿼리래퍼라고한다. 즉, 제이쿼리를호출하는기호

C H A P T E R 2

학습목표 함수프로시저, 서브프로시저의의미를안다. 매개변수전달방식을학습한다. 함수를이용한프로그래밍한다. 2

SOFTBASE XFRAME DEVELOPMENT GUIDE SERIES HTML 연동가이드 서울특별시구로구구로 3 동한신 IT 타워 1215 호 Phone Fax Co

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

게시판 스팸 실시간 차단 시스템

본교재는수업용으로제작된게시물입니다. 영리목적으로사용할경우저작권법제 30 조항에의거법적처벌을받을수있습니다. [ 실습 ] 스위치장비초기화 1. NVRAM 에저장되어있는 'startup-config' 파일이있다면, 삭제를실시한다. SWx>enable SWx#erase sta

유니티 변수-함수.key

DBMS & SQL Server Installation Database Laboratory

SIGIL 완벽입문

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

쉽게 풀어쓴 C 프로그래밍

슬라이드 1

Prototype 분석 - Element 오브젝트 메서드

C스토어 사용자 매뉴얼

PowerPoint 프레젠테이션

슬라이드 1

chap 5: Trees

The Pocket Guide to TCP/IP Sockets: C Version

신림프로그래머_클린코드.key

SOFTBASE XFRAME DEVELOPMENT GUIDE SERIES ActiveX 컴포넌트가이드 서울특별시구로구구로 3 동한신 IT 타워 1215 호 Phone Fax

제 1 장 기본 개념

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

1. SNS Topic 생성여기를클릭하여펼치기... Create Topic 실행 Topic Name, Display name 입력후 Create topic * Topic name : 특수문자는 hyphens( - ), underscores( _ ) 만허용한다. Topi

PowerPoint 프레젠테이션

KT AI MAKERS KIT 사용설명서 (Node JS 편).indd

지도상 유의점 m 학생들이 어려워하는 낱말이 있으므로 자세히 설명해주도록 한다. m 버튼을 무리하게 조작하면 고장이 날 위험이 있으므로 수업 시작 부분에서 주의를 준다. m 활동지를 보고 어려워하는 학생에게는 영상자료를 접속하도록 안내한다. 평가 평가 유형 자기 평가

Ext JS À¥¾ÖÇø®ÄÉÀ̼ǰ³¹ß-³¹Àå.PDF

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

PRO1_02E [읽기 전용]

Eclipse 와 Firefox 를이용한 Javascript 개발 발표자 : 문경대 11 년 10 월 26 일수요일

5.스택(강의자료).key

2017 년 6 월한국소프트웨어감정평가학회논문지제 13 권제 1 호 Abstract

금오공대 컴퓨터공학전공 강의자료

Microsoft PowerPoint - web-part03-ch20-XMLHttpRequest기본.pptx

05_tree

위클리 초이스

11장 포인터

목차 BUG 문법에맞지않는질의문수행시, 에러메시지에질의문의일부만보여주는문제를수정합니다... 3 BUG ROUND, TRUNC 함수에서 DATE 포맷 IW 를추가지원합니다... 5 BUG ROLLUP/CUBE 절을포함하는질의는 SUBQUE

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

2_안드로이드UI

쉽게 풀어쓴 C 프로그래밍

chap x: G입력

제 14 장포인터활용 유준범 (JUNBEOM YOO) Ver 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.

03장

디지털포렌식학회 논문양식

U.Tu System Application DW Service AGENDA 1. 개요 4. 솔루션 모음 1.1. 제안의 배경 및 목적 4.1. 고객정의 DW구축에 필요한 메타정보 생성 1.2. 제품 개요 4.2. 사전 변경 관리 1.3. 제품 특장점 4.3. 부품화형

1

<4D F736F F F696E74202D20C1A632C0E520C7C1B7CEB1D7B7A5B0B3B9DFB0FAC1A4>

슬라이드 1

NTD36HD Manual

일반적인 네트워크의 구성은 다음과 같다

B _01_M_Korea.indb

C 프로그래밊 개요

ibmdw_rest_v1.0.ppt

Overall Process

vi 사용법

System Recovery 사용자 매뉴얼

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

Microsoft PowerPoint - Java7.pptx

PowerPoint Presentation

교육2 ? 그림

Lab10

어댑터뷰

PowerPoint 프레젠테이션

iii. Design Tab 을 Click 하여 WindowBuilder 가자동으로생성한 GUI 프로그래밍환경을확인한다.

<4D F736F F F696E74202D2031C1D6C2F72D31C2F7BDC32028B0ADC0C7C0DAB7E D20C7C1B7CEB1D7B7A1B9D6BEF0BEEE20B0FAB8F1BCD2B

Spring Data JPA Many To Many 양방향 관계 예제

TTA Journal No.157_서체변경.indd


이도경, 최덕재 Dokyeong Lee, Deokjai Choi 1. 서론

Transcription:

Created by Firejune at 2011/11/15, Last modified 2016/09/10 Node.JS와 Express를 이용한 디렉터리 파싱 어떠한 데이터라도 받기만 하면 비주얼라이제이션하는 데에는 자신있다고 자부해 왔습니다. 그러나 며칠간 고민에 빠져들게 하는 과제가 하나 생겼습니다. 그것은 바로 '/dir1/dir2/file.name'과 같은 형식으로 반환되는 데이터들에 대한 디렉터리 구조를 표현하는 것이었습니다. 언뜻 보기에는 굉장히 쉬워보였습니다만, 막상 작업에 돌입해 보니 그리 만만한 프로그래밍이 아니구나라는 생각이 들어 그 해결과정을 이곳에 기록합니다. 사실, 예전에도 이와 유사한 고민을 앓았던 적이 있었는데 서버-사이드에서 처리해야 할 문제였으므로 다른 분에게 부탁하고 기억에서 지웠던 일이 고스라니 돌아온 상황이네요.(임대리 난 이렇게 해결했어!) app.get('/files/:container?', function(req, res) { var swift = users[req.session.name], container = req.params.container; if (!swift) return res.redirect('/login'); swift.listobjects(container, function(err, result) { var objects = serialize(json.parse(result.body)); if (req.xhr) res.partial('partial/objects', { container: container, objects: objects ); else res.render('files', {

layout: 'layout/main', view: 'files', container: container, objects:objects ); ); ); 위 코드는 Node.JS와 Express 프레임웤을 이용하여 진행중인 OpenStack Object Storage(이하 Swift)의 웹 클라이언트 프로젝트에서 라우팅 룰의 일부분입니다. 컨테이너 이름을 URL로 받아 Swift에 질의하고 그 결과를 HTML로 응답하는 일을 합니다. 그리고 xhr요청을 구분하여 문서의 일부만 그릴 것인지 문서 전체를 그릴 것인지를 구분하는 조건이 있습니다. 이 때 Swift는 다음과 같은 JSON형식의 데이터를 돌려줍니다.(지면 관계상 이 처리과정과 무관한 hash, bytes, last_modified 속성들은 생략했습니다.) [ {"name": "README.chromium", "content_type": "application/octet-stream", {"name": "buildinf.h", "content_type": "text/x-chdr", {"name": "config", "content_type": "application/directory", {"name": "config/k8", "content_type": "application/directory", {"name": "config/k8/openssl", "content_type": "application/directory", {"name": "config/k8/openssl/opensslconf.h", "content_type": "text/x-chdr", {"name": "config/piii", "content_type": "application/directory", {"name": "config/piii/openssl", "content_type": "application/directory", {"name": "config/piii/openssl/opensslconf-posix.h", "content_type": "text/xchdr", {"name": "config/piii/openssl/opensslconf-win32.h", "content_type": "text/xchdr", {"name": "config/piii/openssl/opensslconf.h", "content_type": "text/x-chdr", {"name": "openssl.gyp", "content_type": "application/octet-stream",

{"name": "patches", "content_type": "application/directory", {"name": "patches/handshake_cutthrough.patch", "content_type": "text/x-diff", {"name": "patches/missing_stddef.patch", "content_type": "text/x-diff", {"name": "patches/next_proto_neg.patch", "content_type": "text/x-diff", {"name": "patches/posix_c_source.patch", "content_type": "text/x-diff", {"name": "patches/snap_start.patch", "content_type": "text/x-diff" ] 데이터(오브젝트)들을 잘 살펴보면 "name"속성에는 일반적으로 파일명이 있지만 경로만 있거나 경로명을 포함한 파일명도 있습니다. 그리고 컨텐츠타입으로 구분할 수 있도록 되어있습니다. 이것은 오브젝트들이 계층구조를 가질수 있게하는 Swift의 Pseudo-Hierarchical Folders/Directories API 입니다. 이렇게 수신된 데이터들은 serialize 함수에 의해 최초로 가공됩니다. function serialize(objects) { var folders = [], files = []; for (var i = 0; i < objects.length; i++) { var object = objects[i], depth = object.name.split('/'); if (object.content_type == 'application/directory' depth.length > 1) { object.pseudo_path = object.name; object.name = depth[depth.length - 1]; for (var j = 0; j < depth.length; j++) { object.parent = depth[j - 1] null; if (!folders[j]) folders[j] = {; if (!folders[j][depth[j]]) folders[j][depth[j]] = object; else files.push(object);

folders = hierarchy(folders); if (!folders.length) folders = []; return folders.concat(files); 오브젝트들의 반복문에서는 크게 파일과 폴더를 구분합니다. 폴더는 슬래시('/')를 구분자로 나누고 폴더의 깊이를 알아내어 배열을 만듭니다. 이 배열의 값으로는 key-value 형식으로 오브젝트를 담아둡니다. 이 때 오브젝트에는 약간의 변화가 발생하는데 부모(상위 디렉터리)는 누구인지, 그리고 name속성은 디스플레이에서 사용될 값으로 교체하고 새로운 pseudo_path 속성에 실제 name값을 백업합니다. 이것으로 1차 가공을 완료했습니다. [ // depth 1 { "config": {name: "config", content_type: "application/directory", pseudo_path: "config", parent: null, "patches": {name: "patches", content_type: "application/directory", pseudo_path: "patches", parent: null, // depth 2 { "k8": {name: "k8", content_type: "application/directory", pseudo_path: "config/k8", parent: "config", "piii": {name: "piii", content_type: "application/directory", pseudo_path: "config/piii", parent: "config", "handshake_cutthrough.patch": {name: "handshake_cutthrough.patch", content_type: "text/x-diff", pseudo_path: "patches/handshake_cutthrough.patch", parent: "patches",

"missing_stddef.patch": {name: "missing_stddef.patch", content_type: "text/x-diff", pseudo_path: "patches/missing_stddef.patch", parent: "patches", "next_proto_neg.patch": {name: "next_proto_neg.patch", content_type: "text/x-diff", pseudo_path: "patches/next_proto_neg.patch", parent: "patches", "posix_c_source.patch": {name: "posix_c_source.patch", content_type: "text/x-diff", pseudo_path: "patches/posix_c_source.patch", parent: "patches", "snap_start.patch": {name: "snap_start.patch", content_type: "text/x-diff", pseudo_path: "patches/snap_start.patch", parent: "patches", // depth 3 { "openssl": {name: "openssl", content_type: "application/directory", pseudo_path: "config/k8/openssl", parent: "k8", // depth 4 { "opensslconf.h": {name: "opensslconf.h", content_type: "text/x-chdr", pseudo_path: "config/k8/openssl/opensslconf.h", parent: "openssl", "opensslconf-posix.h": {name: "opensslconf-posix.h", content_type: "text/x-chdr", pseudo_path: "config/piii/openssl/opensslconf-posix.h", parent: "openssl", "opensslconf-win32.h": {name: "opensslconf-win32.h", content_type: "text/x-chdr", pseudo_path: "config/piii/openssl/opensslconf-win32.h", parent: "openssl" ] 위와 같이 1차적으로 가공을 마친 폴더 데이터를 hierarchy함수에서 2차 가공을 진행합니다. 2차 가공에서는 배열에 속해있는 오브젝트들을 계층구조로 만드는 일을 수행합니다. 배열의 뒤쪽에서부터 순차적으로 처리하며, 부모(parent)가 누구냐라는 근거로 자식들(childs) 배열을

만들어 냅니다. hierarchy함수는 디렉터리의 깊이 단위로 반복해서 자신을 호출하는 재귀함수이며 마지막 처리시점(부모가 더이상 존재하지 않는 시점)에서 완전이 가공된 데이터를 돌려줍니다. function hierarchy(arr, childs) { var item = arr.pop(), parents = {; for (var name in item) { var parent = item[name].parent '_root_'; if (!parents[parent]) parents[parent] = []; if (!item[name].childs && childs) for (var key in childs) if (key == name) item[name].childs = childs[key]; parents[parent].push(item[name]); delete item[name].parent; if (arr.length) parents = hierarchy(arr, parents); return parents['_root_'] parents; hierarchy함수에 의해 2차적으로 가공된 데이터는 다음과 같습니다. 드디어 궁극적으로 원했던 계층형 데이터 컬렉션이 완성되었습니다. serialize함수는 최종 폴더 데이터와 파일 데이터와 병합하여 돌려줍니다. [{ name: "config", content_type: "application/directory", pseudo_path: "config" childs: [{

name: "k8", content_type: "application/directory", pseudo_path: "config/k8" childs: [{ name: "openssl", content_type: "application/directory", pseudo_path: "config/k8/openssl" childs: [{ name: "opensslconf-win32.h", content_type: "text/x-chdr", pseudo_path: "config/piii/openssl/opensslconf-win32.h" name: "opensslconf-posix.h", content_type: "text/x-chdr", pseudo_path: "config/piii/openssl/opensslconf-posix.h" name: "opensslconf.h", content_type: "text/x-chdr", pseudo_path: "config/k8/openssl/opensslconf.h" ] ] name: "piii", content_type: "application/directory", pseudo_path: "config/piii" ] name: "patches", content_type: "application/directory", pseudo_path: "patches", childs: [{ name: "snap_start.patch", content_type: "text/x-diff", pseudo_path: "patches/snap_start.patch" name: "posix_c_source.patch", content_type: "text/x-diff", pseudo_path: "patches/posix_c_source.patch" name: "next_proto_neg.patch",

content_type: "text/x-diff", pseudo_path: "patches/next_proto_neg.patch" name: "missing_stddef.patch", content_type: "text/x-diff", pseudo_path: "patches/missing_stddef.patch" name: "handshake_cutthrough.patch", content_type: "text/x-diff", pseudo_path: "patches/handshake_cutthrough.patch" ] ] 이제 이 데이터를 뷰-파셜에 그냥 컬렉션으로 전달해 주기만 하면 됩니다. 다음은 컨텐츠 영역에 해당하는 내용을 담은 뷰 파일입니다. 참고로 템프릿 엔진으로는 EJS가 사용되고 있습니다. <ul class="section objects" id="objects"> <li class="header"> <span class="name active"><a href="#refresh">file Name <em>asc</em></a></span> <span class="when"><a href="#refresh">modified <em>asc</em></a></span> <span class="size"><a href="#refresh">size <em>asc</em></a></span> </li> <%- partial('partial/object', objects) %> <li class="actions"> <a class="button upload">upload</a> <em class="message">drop files here to upload</em> <a class="button action" href="#refresh">refresh</a> <div class="progress" style="display: none;"> <span id="bar" class="bar" style="width: 0%;"></span> <span id="state" class="state"></span> </div> </li>

</ul> 그리고 컬렉션 단위로 그려질 뷰 파셜입니다. 여기에서 하나의 조문이 있는데 만약에 자식이 있다면 뷰 자신에게 자신을 다시 파셜하라는 명령을 수행합니다. <li class="object"> <p> <span class="name"> <a href="<%= object.content_type == 'application/directory'? '#open' : '/store/' + container + '/' + (object.pseudo_path object.name) %>" target="_blank"><%- object.name %></a> </span> <span class="when"><%- object.when %></span> <span class="size"><%- object.size %></span> </p> <% if (object.childs) { %> <ul class="tree"> <%- partial('partial/object', object.childs) %> </ul> <% %> </li> 이리하여 얻어진 결과물은 다음과 같습니다.

Powered by TCPDF (www.tcpdf.org)