Radiance는 웹 응용 프로그램 환경으로 웹 프레임 워크와 비슷하지만보다 일반적이며 유연합니다. 개인 웹 사이트와 일반적으로 배포 가능한 애플리케이션을 쉽게 그리고 특별한 적응을받지 않고 실질적으로 모든 설정에 사용할 수있는 방식으로 작성할 수 있어야합니다.
Radiance 및 관련 모듈 및 응용 프로그램은 QuickLISP를 통해 별도의 DIST로 배포됩니다. Radiance를 설치하려면 다음을 수행하십시오.
(ql-dist:install-dist "http://dist.shirakumo.org/shirakumo.txt")
(ql:quickload :radiance)
거기에서 QuickLisp의 quickload 통해 Purplish와 같은 모든 종류의 Radiance 모듈을로드하고 사용할 수 있어야합니다.
Radiance와 대부분의 중요한 개념을 소개하는 튜토리얼을 찾을 수 있으며 일반적으로 웹 응용 프로그램을 작성하는 방법을 탐색 할 수 있습니다. 그것은 당신에게 일을하는 방법에 대한 좋은 느낌을주고, 특정 기능이 필요한 경우 어디에서 볼 수 있는지에 대한 포인터를 제공해야합니다. 마지막 부분에서는 프로덕션 서버에서 Radiance 설치의 실제 설정 및 배포로 이동합니다.
가장 기본적인 일은 어떤 종류의 HTML에 서비스를 제공하는 것입니다. 그래서 그것을 향해 노력하고 점차 확장합시다. 시작하기 전에 Radiance를 시작해야합니다.
( ql :quickload :radiance )
( radiance :startup) 이번이 처음으로 Radiance를 설정하면 r-welcome 모듈을 사용하여 메모를받을 수 있습니다. 또한 브라우저에서 열 수있는 링크를 제공하여 약간의 인사말 페이지를 볼 수 있습니다. 지금은 우리가 그와 함께 우리 자신의 작은 페이지를 올려 놓고 싶을 것입니다.
( in-package :rad-user )
(define-page example " /example " ()
( setf (content-type *response* ) " text/plain " )
" Hi! " )LocalHost 방문 : 8080/예제는 이제 "hi"를 보여 주어야합니다. 오히려 지루합니다. 대신 HTML을 뱉어 봅시다. 지금은 CL-WHO가 매우 간단하기 때문에 사용할 것입니다. 먼저 퀵로드 한 다음 다음을 실행하십시오.
(define-page example " /example " ()
( cl-who :with-html-output-to-string (o)
( cl-who :htm
( :html
( :head ( :title " Example Page " ))
( :body ( :header ( :h1 " Couldn't Be Simpler. " ))
( :main ( :p " Trust me on this one. " )))))))나중에 다시 컴파일하고 새로 고침하면 글꼴 스타일이 진행되고 있습니다. 다음으로 CSS 파일을 추가하여 올바르게 스타일링 할 것입니다. 우리는 다른 페이지를 사용하여 CSS에 서비스를 제공 할 수 있지만 장기적으로 일을하는 가장 좋은 방법은 아닙니다.
대신 모듈을 만드는 방법을 살펴 보겠습니다. 이는보다 질서 정연한 방식으로 사물을 구성 할 수 있습니다. 모듈 용 파일을 수동으로 만들 수 있지만 지금은 Radiance가 제공 할 수있는 자동 생성 된 골격으로 정산합니다.
(create-module " example " ) 모듈이있는 경로를 반환해야합니다. ASDF 시스템, 기본 LISP 파일 및 static 및 template 2 개가 포함되어야합니다. 놀랍게도, static 폴더는 정적으로 제공되는 파일이 진행되는 곳이며 템플릿 시스템을 사용하는 경우 template 템플릿 문서를위한 것입니다.
example.lisp 열어 놓고 예제 페이지를 전달해 봅시다.
(define-page example " /example " ()
( cl-who :with-html-output-to-string (o)
( cl-who :htm
( :html
( :head ( :title " Example Page " ))
( :body ( :header ( :h1 " Couldn't Be Simpler. " ))
( :main ( :p " Trust me on this one. " ))))))) 페이지는 이름 기호로 식별됩니다. 우리는 이제 우리 자신의 모듈을 가지고 있기 때문에 우리 자신의 패키지가 있으므로 위의 예제 기호는 이전에 사용한 것과 동일하지 않습니다. 충돌을 피하기 위해 rad-user 패키지의 페이지를 제거하면됩니다.
(remove-page ' rad-user::example) 변경 사항이 적용되도록 지금 변경할 때마다 예제 파일을로드하십시오. 다음으로 간단한 CSS 파일을 만들어서 조금 꾸미고 봅시다. 파일은 example.css static 폴더에 배치됩니다. 자신의 글을 쓰고 싶지 않다면 다음은 샘플 CS입니다.
body {
font-family : sans-serif;
font-size : 12 pt ;
background : # EEE ;
}
header {
text-align : center;
}
main {
width : 800 px ;
margin : 0 auto 0 auto;
background : # FFF ;
padding : 10 px ;
border : 1 px solid # BBB ;
border-radius : 5 px ;
}다음으로 스타일 시트에 실제로 링크하려면 HTML을 수정해야합니다. 스타일 시트에 주소를 얻으려면 Radiance의 라우팅 시스템을 사용해야합니다. 그래도 걱정하지 마십시오. 번거 로움은 많지 않습니다.
(define-page example " /example " ()
( cl-who :with-html-output-to-string (o)
( cl-who :htm
( :html
( :head ( :title " Example Page " )
( :link :rel " stylesheet " :type " text/css "
:href (uri-to-url " /static/example/example.css " :representation :external )))
( :body ( :header ( :h1 " Couldn't Be Simpler. " ))
( :main ( :p " Trust me on this one. " ))))))) 페이지를 새로 고치고 Voilà, 이제 피자도 있습니다. 아마도 uri-to-url 비즈니스 전체에 대한 설명을 원할 것입니다. 전체적으로 설명하는 것은이 섹션을 따르는 섹션에 의해 처리되지만 그 요점은 정적 파일에 대한 링크가 모든 설정에서 올바르게 해결되도록합니다.
Radiance에서 가장 중요한 개념 중 하나는 URI의 개념입니다. URI는 도메인 목록, 선택적 포트 번호 및 경로로 구성된 객체입니다 ( uri 참조). 본질적으로 일반 URI의 제거 버전이므로 스키마, 쿼리 또는 조각 부분이 포함되지 않습니다. 또 다른 중요한 차이점은 domains URI가 위치를 캡처하고 디스패치 매칭을 처리하기 위해 프레임 워크 전체의 여러 지점에서 사용된다는 것입니다.
URI는 변이 가능합니다. URI 수정은 중요한 경로에있는 여러 부분에서 발생해야하므로 성능에 중요합니다. 그러나 일반적인 경우 URI가 일부 선택된 기능 외부에서 수정 될 것으로 예상되지 않습니다. URI의 부분을 예기치 않은 방식으로 수정하면 이상한 행동으로 이어질 수 있습니다.
URI는 고유 한 문자열 표현을 가지고 있으며 문자열로 직렬화되어 전체 URI 객체로 다시 구문 분석 할 수 있습니다. Uris는 Literals로 FASL 파일에 버릴 수 있으므로 매크로에서 방출하는 것이 좋습니다. URI의 구문은 다음과 같습니다.
URI ::= DOMAINS? (':' PORT)? '/' PATH?
DOMAINS ::= DOMAIN ('.' DOMAIN)*
DOMAIN ::= ('a'..'Z' | '0'..'9' | '-')
PORT ::= ('0'..'9'){1, 5}
PATH ::= .*
uri-to-url 사용하여 URI를 콘크리트 URL로 바꿀 수 있습니다. 모든 부품의 반전, 인코딩 및 올바른 형식이 자동으로 처리됩니다.
uri , domains , port , path , matcher , uri-string , make-uri , make-url , ensure-uri , copy-uri , parse-uri , uri< , uri> uri= , uri-matches , merge-uris represent-uri , uri-to-url 참조하십시오.
전송 된 데이터를 캡슐화하기 위해 요청 ( request ) 및 응답 ( response ) 객체에 대한 아이디어가 있습니다. 요청 객체는 요청이 어떤 위치를 나타내는 위치를 나타내는 URI와 Post, Get, Header 및 Cookie 변수와 같은 HTTP 페이로드에 포함 된 모든 데이터를 보유합니다. 응답 객체는 리턴 코드, 헤더, 쿠키 및 실제 신체 데이터를 유지합니다.
요청 처리 중에이 두 객체는 항상 존재하고 *request* 및 *response* 변수에 결합해야합니다. 동적 페이지를 생성하는 데 필요한 매우 중요한 정보를 많이 캡슐화합니다. 또한 요청에는 임의의 데이터를 저장할 수있는 불투명 data 테이블이 포함되어 있습니다. 이것은 요청 실행 중에 도달 할 수있는 시스템의 개별 부분간에 정보를 교환해야 할 때 유용합니다.
요청이 반드시 HTTP 서버에서 나올 필요는 없습니다. 항목을 테스트하기 위해 요청을 직접 구성하고 프로그래밍 방식으로 보낼 수도 있습니다. 어떤 경우이든, 요청을 발송하기위한 기본 인터페이스를 request 이라고합니다. 이것은 귀하를위한 요청 및 응답 개체를 구성하고 URI를 적절하게 처리합니다. 직접 그렇게하고 싶고 실제로 완전한 요청 객체를 보내면 execute-request 사용할 수 있습니다.
요청의 실제 처리는 디스패처, 페이지 및 API 엔드 포인트를 참조하십시오.
*request* , *response* , *default-external-format* , *default-content-type* , request , uri , http-method , body-stream , headers , post-data , get-data , cookies , user-agent , referer , domain , remote , data , 데이터, issue-time , response , return-code data content-type , headers , cookies , DONAL cookie external-format , External name Format, External- value domain , path , expires , http-only , secure , cookie-header , cookie , get-var , post-var , post/get , header , file , redirect , serve-file , request-run-time , *debugger* , handle-condition , render-error-page , execute-request , set-data , request
요청을 발송하기 전에 라우팅 시스템이라는 것을 통과합니다. 'Routes'가 요청을 처리하는 것을 지정하는 다른 프레임 워크와 달리 Radiance A Route ( route )는 URI 번역기의 한 형태입니다. 시스템 의이 부분은 내부 및 외부 인물 인 두 개의 "유니버스"를 생성하고 유지하는 데 책임이 있습니다.
내부 유니버스는 실제 웹 애플리케이션이 살고있는 것 중 하나입니다. 외부 유니버스는 HTTP 서버와 웹 사이트 사용자가 살고있는 것입니다. 한 손, 서버의 잠재적 설정이 어느 시점에서 어떻게 보일지 걱정하지 않고 웹 응용 프로그램을 작성하기 위해서는이 차이가 필요합니다. 응용 프로그램을 실행하려면 어떤 종류의 도메인, 포트, 경로 설정이 필요할 수 있는지 걱정할 필요가 없습니다. 반면에, 웹admin으로서 물건을 깨는 것에 대한 두려움없이 시스템을 정확한 욕구에 맞게 사용자 정의하고 실행할 수 있습니다.
이 모든 것은 노선에 의해 촉진되며, 그 중 매핑과 역전 경로의 두 가지 종류가 있습니다. 매핑 경로는 외부 우주에서 URI를 내부 우주 중 하나로 바꾸는 책임이 있습니다. 일반적으로 여기에는 최상위 도메인을 절단하고 하위 도메인을 매핑하는 것이 포함됩니다. 반전 경로는 반대입니다. 내부 우주에서 외부로갑니다. 제공되는 페이지에서 링크를 만들려면 실제로 외부에서 액세스 할 수있는 리소스를 참조하기 위해 필요합니다. 일반적으로 여기에는 하위 도메인 매핑을 역전시키고 최상위 도메인을 다시 추가하는 것이 포함됩니다.
경로는 임의의 작업을 수행 할 수 있습니다. 가장 기본적인 수준에서, 그들은 단지 어떤 방식으로 URI를 수정하는 기능 일뿐입니다. 이를 통해 관리자로서 귀하의 모든 요구를 수용 할 수있을 정도로 강력 해야하는 매우 유연한 시스템을 만들 수 있습니다. 응용 프로그램 작성자는 페이지에 넣은 모든 링크에서 external-uri 또는 uri-to-url 사용해야합니다.
route , name , direction , 우선 priority , translator , route , remove-route , list-routes , define-route , define-matching-route , define-target-route , define-string-route , internal-uri external-uri 보기
마지막으로 우리는 실제로 요청에 대한 컨텐츠를 생성하는 부분에옵니다. URI 디스패처는 이름, 함수 및 우선 순위를 가지고있는 URI의 서브 클래스입니다. 요청이 도착할 때마다 처리되는 우선 순위로 분류 된 목록에 라이브. 요청의 URI는 각 디스패처와 일치합니다. 그런 다음 일치하는 첫 번째 디스패처의 기능이 실행됩니다.
그리고 그게 다야. 디스패처 기능은 응답 객체에서 필요한 값을 설정하여 페이지 컨텐츠를 전달하는 데 도움이됩니다. 이를 위해 응답 객체의 data 필드를 직접 설정하거나 함수에서 적절한 값을 반환 할 수 있습니다. Radiance는 stream , pathname , string 및 (array (unsigned-byte 8)) 네 가지 유형의 값 만 허용합니다.
URI 디스패처에 명시적인 우선 순위 번호가없는 경우 다른 사람보다 우선 순위가 URI의 특이성에 의해 결정됩니다. 이것이 정확히 어떻게 계산되는지에 대한 설명은 URI 분류 기능 uri> 참조하십시오.
uri-dispatcher , name , dispatch-function , priority , uri-dispatcher , remove-uri-dispatcher , list-uri-dispatchers , uri-dispatcher> , define-uri-dispatcher , dispatch
페이지는 실제 콘텐츠 서빙 기능을 정의하는 데 사용할 수있는 것입니다. 그러나 페이지는 정의 매크로에 추가 기능이있는 Uri-Dispatcher 일뿐입니다. 가장 주목할만한 것은 확장 가능한 옵션이며 아래 설명을 찾을 수 있습니다.
Radiance 자체가 설정 한 기본 페이지가 몇 개 있습니다. 먼저 favicon 및 robots 페이지가 있으며 Radiance의 static/ 디렉토리의 각 파일을 제공합니다. 아마도 해당 페이지를 제공하거나 프로덕션 서버에서 파일을 업데이트하고 싶을 것입니다.
그런 다음 모든 웹 응용 프로그램 및 모듈에 대한 정적 내용을 제공하는 static 페이지가 있습니다. 모든 도메인에서 활성화되어야하며 항상 경로 /static/... 여기서 ... 첫 번째 디렉토리가 모듈의 이름 인 형식이 있어야하고 나머지는 해당 모듈의 static/ 디렉토리의 경로입니다. 이를 통해 항상 공통 경로를 통해 CSS, JS 및 이미지와 같은 정적 파일을 참조 할 수 있습니다.
마지막으로 api 페이지가 있는데,이 페이지는 다음 섹션에서 설명되는 API 엔드 포인트의 발송을 처리하는 데 도움이됩니다. 이 페이지는 모든 도메인의 /api/... 경로를 캡처하여 정적과 유사하게 작동합니다.
page , remove-page , define-page 참조하십시오
Radiance는 REST API 정의에 대한 통합 지원을 제공합니다. 이것은 단순한 기능 일뿐 만 아니라 대부분의 최신 응용 프로그램이 어떤 종류의 API를 제공하기를 원하기 때문에 Radiance는 API 엔드 포인트와 관련된 응용 프로그램을 작성하는 특정 방법을 조언하기 때문입니다.
개념적으로 API 엔드 포인트는 브라우저 요청을 통해 호출 할 수있는 기능입니다. 그런 다음 응답은 요청자가 읽을 수있는 형식으로 직렬화됩니다. 그러나 기억하는 것이 중요합니다. 그러나 API 엔드 포인트는 사용자와 프로그램 모두에서 사용할 수 있어야한다는 것입니다. Radiance는 일반적으로 API를 통해 프로그래밍 방식으로 수행 할 수있는 모든 종류의 동작도 사용자가 어떤 방식으로 수행해야하기 때문에이를 권장합니다. 복제를 피하기 위해 두 가지를 혼란시킬 수 있습니다.
따라서 일반적으로 모든 종류의 데이터 수정 조치는 사용자 또는 응용 프로그램이 요청하는지 여부에 따라 약간 다르게 반응하는 API 엔드 포인트를 통해 제공되어야합니다. 사용자의 경우 일반적으로 적절한 페이지로 다시 리디렉션해야하며 응용 프로그램의 경우 데이터 페이로드를 읽을 수있는 형식으로 제공해야합니다.
이 모든 것의 첫 번째 부분은 API 형식 시스템으로, 데이터를 일부 지정된 형식으로 직렬화하는 데 책임이 있습니다. 기본적으로 S- 표현 기반 형식 만 제공되지만 JSON 출력을 얻는 데 도움이되는 기여는 쉽게로드 될 수 있습니다.
두 번째 부분은 browser 게시물/get 매개 변수의 사양입니다. 해당 매개 변수에 정확한 문자열 "true" 가 포함 된 경우 API 요청은 사용자로부터 오는 것으로 취급되므로 데이터 페이로드가 아닌 리디렉션을 출력해야합니다.
응용 프로그램은 올바르게 통합 된 API를 제공하기 위해 이러한 것들을 사용해야합니다. 이제 실제 엔드 포인트 정의는 이름, 원시 함수, 함수의 인수를 설명하는 람다 목록 및 요청 구문 분석 기능으로 구성됩니다. 일반적으로 귀하의 주장에 대해서는 필수 및 선택적인 인수 만 의미가 있습니다. 결국, HTTP 요청에는 제공 할 수있는 "키워드 인수"만 있으며, 이들은 존재하거나 누락 될 수 있습니다.
API 엔드 포인트의 이름은 도달 할 수있는 위치를 알려주는 식별자 역할을합니다. API 엔드 포인트는 /api/ PATH에서 살고 종말점의 이름이 이어집니다. 따라서 실수로 다른 엔드 포인트를 넘어서는 것을 피하기 위해 모듈 또는 응용 프로그램의 이름으로 엔드 포인트를 접두사를 접두사 할 책임이 있습니다. API 엔드 포인트는 정확히 일치해야하며 경로의 모호함이나 처리를 허용하지 않기 때문에 URI 디스패처와는 다릅니다. 따라서 모든 엔드 포인트에는 고유 한 경로가 있어야하며 즉시 이름으로 사용될 수 있습니다.
원시 기능은 API가 인터페이스를 제공하는 기능입니다. 요청 된 조치를 수행하고 위에서 설명한대로 적절한 데이터를 반환해야합니다. 형식화 된 API 데이터를 반환하려면 api-output 참조하십시오. 브라우저 요청의 경우 리디렉션은 redirect 참조하십시오.
마지막으로, 요청 구문 분석 함수는 요청 객체를 취하고, 기능에 필요한 인수를 추출하고, 가능한 경우 적절한 인수로 해당 함수를 호출해야합니다. 구문 분석 기능은 필요한 인수가 누락 된 경우 api-argument-missing 오류를 나타낼 수 있습니다. 불필요한 주장은 무시되어야합니다.
call-api 사용하여 프로그래밍 방식으로 API 엔드 포인트를 호출하거나 전체 URI 디스패치 메커니즘을 거치지 않고 call-api-request 로 요청 호출을 시뮬레이션 할 수도 있습니다.
페이지와 마찬가지로 API 엔드 포인트 정의는 정의를 더 간단하게 만드는 확장 가능한 옵션도 허용합니다. 옵션에 대한 설명은 다음 섹션을 참조하십시오.
api , *default-api-format* , *serialize-fallback* , api-format , remove-api-format , list-api-formats -api-format, define-api-format , api-output , api-serialize , api-endpoint , remove-api-endpoint , name , handler , argslist, call-reider-papi list-api-endpoints papi api-endpoint , list-api-endpoints, api- argslist , call-api-request request-handler , remove- call-api . define-api
옵션은 확장 가능한 정의 매크로를 제공하는 방법입니다. 이는 프레임 워크가 무언가를 정의하는 일반적인 방법을 제공 할 때 유용하지만 다른 부분은 일반적인 작업을 더 짧게하기 위해이를 확장 할 수 있습니다. 예를 들어, 일반적인 작업은 페이지 또는 API 엔드 포인트를 필요한 액세스 자격 증명을 가진 사람들로 제한하는 것입니다.
이를 용이하게하기 위해 Radiance는 다소 일반적인 옵션 메커니즘을 제공합니다. 옵션은 옵션이 속한 정의 매크로를 지정하는 옵션 유형으로 나뉩니다. Radiance는 상자 밖에서 api 및 page 옵션 유형을 제공합니다.
각 옵션에는 이름에 대한 키워드와 옵션 유형에 따라 여러 인수를 수락 해야하는 Expander 함수가 있습니다. 항상 인수로 제공되는 것은 정의되는 물건의 이름, 정의의 신체 형태 목록 및 옵션 목록의 옵션에 제공된 최종 선택적 값이 전혀 언급 된 경우입니다. 이 확장 기능은 어떤 방식 으로든 정의 매크로의 신체 형태를 변환하는 데 도움이됩니다. 또한 어떤 방식으로 환경을 설정하기 위해 정의 자체 외부에 배치되는 두 번째 형태를 방출 할 수 있습니다.
option , option-type , name , expander , option , remove-option , list-options , define-option , expand-options 참조
모듈의 개념은 방사선에 필수적입니다. 그것은 전체의 "부분"의 표현 역할을합니다. 기술적 인 수준에서 모듈은 특수 메타 데이터가 첨부 된 패키지입니다. modularize 시스템에 의해 제공되며 후크 및 트리거, 인터페이스 및 몇 가지 다른 정보의 추적을 용이하게하는 데 사용됩니다.
이것이 당신에게 의미하는 바는 표준 defpackage 대신 define-module 양식을 사용하여 기본 패키지를 정의해야한다는 것입니다. 구문은 defpackage 와 동일하지만 다음과 같은 추가 옵션이 포함되어 있습니다 :domain 이 모듈이 작동 해야하는 기본 도메인을 지정할 수 있습니다 (있는 경우).
모듈 시스템은 또한 ASDF 시스템을 모듈에 연결할 수있게합니다. 이 작업이 완료되면 ASDF 시스템이 "가상 모듈"이됩니다. 이렇게하려면 시스템 정의에 세 가지 옵션을 추가해야합니다.
:defsystem-depends-on (:radiance)
:class "radiance:virtual-module"
:module-name "MY-MODULE"
이를 통해 Radiance는 ASDF 시스템 정보를 모듈에 식별하고 연결할 수 있습니다. 새로운 모듈에 필요한 시스템 및 모듈 정의를 자동화하려면 create-module 참조하십시오.
virtual-module , virtual-module-name , define-module , define-module-extension , delete-module , module , module-p , module-storage module-storage-remove , Module-Andifier, module-name , 모듈- module-identifier , 모듈-관리자, Module- current-module - module-domain - module-permissions -refore-refore-refore- module-dependencies - module-required-interfaces - module-required-systems , module-pages , module-api-endpoints , describe-module , find-modules-directory , *modules-directory* , create-module
모듈을 서로 통합 할 수 있도록 Radiance가 제공하는 메커니즘 중 하나는 후크입니다. 후크를 사용하면 어떤 종류의 이벤트에 응답하여 임의의 기능을 실행할 수 있습니다. 예를 들어, 포럼 소프트웨어는 새 게시물이 생성 될 때마다 트리거되는 후크를 설정할 수 있습니다. 그런 다음 확장자는 추가 작업을 수행하는 후크의 트리거를 정의 할 수 있습니다.
후크는 임의의 트리거를 정의 할 수 있지만, 트리거를 트리거하는 것은 모든 트리거가 완료 될 때까지 완료되지 않는 차단 작업이므로 트리거가 너무 오래 걸리지 않도록해야합니다. 따라서 장기 실행중인 트리거 작업은 요청 응답을 너무 오랫동안 지연시킬 수 있습니다.
때로는 후크가 스위치처럼 작동해야합니다. 스위치는 나중에 다시 "끄기"할 때까지 오랫동안 "켜기"할 수있는 스위치처럼 작동해야합니다. 해당 기간 동안 새 트리거가 정의되면 자동으로 호출해야합니다. 이것이 define-hook-switch 촉진하는 것입니다. 두 개의 후크를 생성합니다. 첫 번째 것이 트리거되면 나중에 정의 된 트리거는 두 번째 후크가 트리거 될 때까지 자동으로 호출됩니다. 이를 통해 서버가 이미 시작된 후에 만 트리거가 정의 되더라도 server-start 와 같은 후크의 트리거가 제대로 작동 할 수 있습니다.
list-hooks , define-hook , remove-hook , define-trigger , RESM trigger remove-trigger define-hook-switch 참조
모 놀리 식이되지 않고 확장 가능한 백엔드를 허용하기 위해 Radiance에는 인터페이스 시스템이 포함됩니다. 가장 일반적인 의미에서, 인터페이스는 일부 기능, 매크로, 변수 등이 어떻게 작동 해야하는지에 대한 약속을 제공하지만 실제로이를 구현하지는 않습니다. 인터페이스 개요가 작동하는 모든 기능이 작동하는 실제 기능은 구현으로 밀려납니다. 이를 통해 사용자는 인터페이스에 대해 코딩하고 특정 백엔드에 자신을 연결하지 않고 제공되는 기능을 사용할 수 있습니다.
구체적인 예를 들어, 데이터베이스에 대한 인터페이스가 있다고 가정 해 봅시다. 여러 종류의 데이터베이스가 있기 때문에 모두 다른 상호 작용 방법을 제공하지만 여전히 데이터 저장, 데이터 검색 및 데이터 수정과 같은 몇 가지 매우 일반적인 작업을 제공합니다. 따라서 이러한 공통 작업을 제공하는 인터페이스를 만듭니다. 그런 다음 특정 종류의 데이터베이스가 실제 작업을 작동시키기 위해 구현에 달려 있습니다. 응용 프로그램 작성자는 데이터베이스 인터페이스를 사용하여 응용 프로그램이 다양한 데이터베이스와 자동으로 작동하도록 할 수 있습니다.
응용 프로그램 작성자에게 이점을 제공하는 것 외에도 인터페이스가 제공하는 분리는 시스템 관리자가 기존 구현에서 특정 요구 사항을 충족시키지 못하면 상대적으로 쉽게 구현할 수 있음을 의미합니다. 인터페이스의 불투명성 덕분에 구현은 LISP 프로세스에서 실행되는 것에 대한 브리지와 완전히 외부의 무언가에 대한 다리를 제공 할 수 있습니다. 이로 인해 생산 시스템 관리자가 필요한 것을 정확하게 선택할 수 있도록 많은 선택이 열려 있습니다.
실제로 인터페이스는 특별한 종류의 모듈이므로 특별한 종류의 패키지입니다. 정의의 일부로 함수, 변수 등과 같은 다른 바인딩에 대한 일련의 정의가 포함됩니다. 패키지이므로 사용자는 다른 패키지에서 다른 것을 사용할 수있는 것처럼 인터페이스의 구성 요소를 사용할 수 있습니다. 차이가 없습니다. 구현 작가로서 인터페이스가 설명하는 모든 정의를 간단히 재정의합니다.
인터페이스를 사용하는 모듈을 실제로로드하려면 인터페이스의 구현을 미리로드해야합니다. 그렇지 않으면 매크로는 제대로 작동 할 수 없습니다. 따라서 특정 구현을 참조하지 않고 ASDF 시스템 정의의 인터페이스에 따라 허용하기 위해 Radiance는 ASDF 확장을 제공합니다. 이 확장자는 (:interface :foo) :depends-on 목록에 추가 할 수 있습니다. 그런 다음 Radiance는 모듈이로드 될 때 콘크리트 구현으로 인터페이스를 해결합니다.
Radiance는 많은 표준 인터페이스를 제공합니다. 이러한 각 인터페이스에는 Radiance-Contribs가 제공하는 하나 이상의 표준 구현이 있습니다. 인터페이스는 다음과 같습니다.
adminauthbancachedatabaseloggermailprofilerateserversessionuser인터페이스는 아래에 심도있는 설명입니다.
interface , interface-p , implementation , implements , reset-interface , define-interface-extension , find-implementation , load-implementation , define-interface , define-implement-trigger 참조
Radiance는 동일한 기계에서 다른 설정으로 여러 번의 Radiance 인스턴스를 실행할 수 있도록 환경 시스템을 제공합니다. 환경은 기본적으로 Radiance 자체 및로드 된 모든 모듈을위한 구성 및 런타임 파일 세트입니다. Radiance 구성에는 선택된 구현에 대한 인터페이스의 매핑이 포함되므로 인터페이스가 요청되면 선택해야 할 사항을 결정합니다.
사용되는 특정 환경은 startup 호출 될 때 가장 최근에 선택되며 모듈이로드 된 경우 가장 초기에 선택됩니다. 후자의 경우 환경을 선택할 수 있도록 대화식 재시작이 제공됩니다. 그렇지 않으면 Radiance가 인터페이스 매핑을 해결할 수 없으므로 필요합니다.
환경 시스템의 일환으로 Radiance는 응용 프로그램에 사용할 수있는 구성 시스템을 제공합니다. 각 환경마다 설정이 올바르게 다중화되고 설정이 항상 지속되도록합니다. 또한 특수 도구없이 파일을 읽고 수정할 수 있도록 사람이 읽을 수있는 스토리지 형식을 사용합니다.
구성 저장소의 실제 취급 및 사용 검사는 유비쿼터스를 참조하십시오. Radiance는 value 함수 대신 config 기능을 제공합니다.
구성 파일 외에도 환경은 사용자 업로드, 캐시 파일 등과 같은 런타임 데이터 파일에 대한 일관된 스토리지 위치를 제공합니다. environment-module-directory 및 environment-module-pathname 사용 하여이 위치를 검색 할 수 있습니다. 업로드 및 캐시를 저장할 때 모듈은 이러한 경로를 사용하여 관리자에게 일관된 인터페이스를 제공해야합니다.
배포 된 시스템에서는 환경 저장 경로의 위치를 변경하는 것이 바람직 할 수 있으며,이 경우 관리자는 원하는대로 동작을 사용자 정의하기 위해 environment-directory 및 environment-module-directory 에 새로운 방법을 제공하는 것이 좋습니다. 자세한 내용과 기본 조치는 관련 문서 문자열도 참조하십시오.
환경은 또한 관리자를 재정의 할 수 있습니다. 사용 :static 및 : environment-module-directory 의 :template 유형을 사용하면 모듈의 표준 템플릿과 정적 파일을 무시 해야하는 파일을 저장하는 경로가 제공됩니다. 각 디렉토리 내의 경로는 모듈 자체 소스 파일의 경로와 일치해야합니다. 모듈이 실제로 사용하는 정적 및 템플릿 파일은 모듈로드 타임에서 캐시 링하므로 LISP 이미지가 다시 시작되거나 모듈의 소스 파일이 다시로드되지 않으면 변경되지 않습니다.
environment-change , environment , environment-directory , environment-module-directory , environment-module-pathname , check-environment , mconfig-pathname , mconfig-storage , mconfig , defaulted-mconfig , config , defaulted-config , template-file , @template , static-file @static
때때로 시스템은 호환되지 않는 방식으로 뒤로 진화합니다. 이 경우 기존 설정이 새 버전으로 계속 작동하려면 런타임 데이터 마이그레이션이 필요합니다. Radiance는이 프로세스를 자동화하고 원활한 업그레이드를 허용하는 시스템을 제공합니다.
Radiance의 시작 시퀀스 중에 버전 간의 마이그레이션은 자동으로 발생해야합니다. 관리자 또는 저자는 마이그레이션이 발생하기 위해 추가 단계를 수행 할 필요가 없습니다. 그러나 모듈 저자는 모듈에 필요한 데이터 마이그레이션 단계를 수행하기 위해 자연스럽게 코드를 제공해야합니다.
모듈을 마이그레이션 할 수 있으려면 버전 사양이있는 ASDF 시스템에 의해로드되어야합니다. 버전은 표준 점선 숫자 체계를 따라야하며, 옵션 버전 해시가 끝날 수 있습니다. 그런 다음 define-version-migration 사용하여 개별 버전 간의 마이그레이션 단계를 정의 할 수 있습니다. 정의되면 Radiance는 콘크리트 버전을 자동으로 픽업하고 현재 대상 버전에 도달하기 위해 순서대로 필요한 마이그레이션을 수행합니다. 정확한 절차 및 수행 할 수있는 작업에 대한 자세한 내용은 migrate 및 migrate-versions 참조하십시오.
last-known-system-version , migrate-versions , define-version-migration , ready-dependency-for-migration , ensure-dependencies-ready , versions , migrate 참조
마지막으로, Radiance는 표준 시작 및 종료 시퀀스를 제공하여 물건을 올바르게 설정하고 읽을 수 있도록하고 나중에 다시 잘 정리해야합니다. 이 시퀀스의 대부분은 특정 후크가 적절한 순서와 적절한 시간에 호출되도록하는 것입니다.
적절한 인터페이스 기능을 사용하여 수동으로 서버를 시작할 수 있지만, 그렇게하면 응용 프로그램이 제대로 실행될 것으로 예상해서는 안됩니다. 그들 중 다수는 제대로 작동하기 위해 특정 고리가 호출 될 것으로 기대할 것입니다. 그렇기 때문에 항상 무엇을하고 있는지 정확히 알지 못하면 startup 및 shutdown 사용하여 Radiance 인스턴스를 관리해야합니다. 두 기능에 대한 문서는 어떤 후크가 트리거되고 어떤 순서를 정확하게 설명해야합니다. 구현은 상기 기호가 내보내지 않는 한 인터페이스 패키지의 기호에 대한 추가로 지정되지 않은 정의를 제공 할 수 있습니다.
*startup-time* , uptime , server-start , server-ready , server-stop , server-shutdown , startup , startup-done , shutdown , shutdown-done , started-p 참조
이 인터페이스는 Radiance와 함께 배포되며 핵심 패키지의 일부입니다. 그러나 라이브러리는 추가 인터페이스를 제공 할 수 있습니다. 표준 인터페이스의 구현의 경우 다음 인터페이스 정의의 완화 제약 조건이 허용됩니다.
&key 인수를 포함하는 Lambda-Lists는 구현 의존적 키워드 인수를 추가로 확장 할 수 있습니다. &optional 이지만 No &key 또는 &rest 포함하는 Lambda-Lists는 추가 선택 인수에 의해 확장 될 수 있습니다. 필요한 인수 만 포함하는 Lambda-List는 추가 선택 사항 또는 키워드 인수에 의해 확장 될 수 있습니다.
이 인터페이스는 관리 페이지를 제공합니다. 모든 종류의 사용자 구성 가능한 설정 또는 시스템 정보 표시에 사용해야합니다. "투여"라고 불려지더라도 이는 시스템 관리자만을위한 것이 아닙니다. 모든 사용자에게는 페이지를 사용할 수 있어야합니다.
관리 페이지는 분류 된 메뉴와 패널을 표시 할 수 있어야합니다. 패널은 다른 모듈에서 제공되며 admin:define-panel 통해 추가 할 수 있습니다. 민감한 작업에 액세스하는 패널은 :access 을 통해 적절하게 제한되어야합니다. 권한에 대한 설명은 사용자 인터페이스를 참조하십시오.
관리 페이지 또는 특정 패널에 링크하려면 page 자원 유형을 사용하십시오.
admin:list-panels , admin:remove-panel , admin:define-panel , admin:panel
인증 인터페이스는 사용자를 요청에 연결해야합니다. 이러한 이유로 사용자가 시스템에 대해 스스로 인증 할 수있는 방식을 제공해야합니다. 이것이 정확히 어떻게 수행되는지는 구현에 달려 있습니다. 그러나 구현은 인증 프로세스가 시작되는 페이지를 제공해야합니다. You can get a URI to it through the page resource and passing "login" as argument.
You can test for the user currently tied to the request by auth:current . This may also return NIL , in which case the user should be interpreted as being "anonymous" . See the user interface for more information.
See auth:*login-timeout* , auth:page , auth:current , auth:associate
This interface provides for IP-banning. It must prevent any client connecting through a banned IP from seeing the content of the actual page they're requesting. Bans can be lifted manually or automatically after a timeout. The implementation may or may not exert additional effort to track users across IPs.
See ban:jail , ban:list , ban:jail-time , ban:release
The cache interface provides for a generic caching mechanism with a customisable invalidation test. You can explicitly renew the cache by cache:renew . To define a cached block, simply use cache:with-cache , which will cause the cached value of the body to be returned if the test form evaluates to true.
The exact manner by which the cached value is stored is up to the implementation and cache:get or cache:with-cache may coerce the cached value to a string or byte array. The implementation may support any number of types of values to cache, but must in the very least support strings and byte arrays.
The name for a cached value must be a symbol whose name and package name do not contain any of the following characters: <>:"/|?*. The variant for a cached value must be an object that can be discriminated by its printed (as by princ ) representation. The same character constraints as for the name apply.
See cache:get , cache:renew , cache:with-cache
This interface provides you with a data persistence layer, usually called a database. This does not have to be a relational database, but may be one. In order to preserve implementation variance, only basic database operations are supported (no joins, triggers, etc). Data types are also restricted to integers, floats, and strings. Despite these constraints, the database interface is sufficiently useful for most applications.
Note that particular terminology is used to distance from traditional RDBMS terms: a schema is called a "structure". A table is called a "collection". A row is called a "record".
Performing database operations before the database is connected results in undefined behaviour. Thus, you should put your collection creation forms ( db:create ) within a trigger on db:connected . Radiance ensures that the database is connected while Radiance is running, so using the database interface in any page, api, or uri dispatcher definitions is completely fine.
The functions for actually performing data storage are, intuitively enough, called db:insert , db:remove , db:update , db:select , and db:iterate . The behaviour thereof should be pretty much what you'd expect. See the respective docstrings for a close inspection. Also see the docstring of db:create for a lengthy explanation on how to create a collection and what kind of restrictions are imposed.
The database must ensure that once a data manipulation operation has completed, the changes caused by it will be persisted across a restart of Radiance, the lisp image, or the machine, even in the case of an unforeseen crash.
See database:condition , database:connection-failed , database:connection-already-open , database:collection-condition , database:invalid-collection , database:collection-already-exists , database:invalid-field , database:id , database:ensure-id , database:connect , database:disconnect , database:connected-p , database:collections , database:collection-exists-p , database:create , database:structure , database:empty , database:drop , database:iterate , database:select , database:count , database:insert , database:remove , database:update , database:with-transaction , database:query , database:connected , database:disconnected
This interface provides primitive logging functions so that you can log messages about relevant happenings in the system. The actual configuration of what gets logged where and how is up to the implementation and the administrator of the system.
See logger:log , logger:trace , logger:debug , logger:info , logger:warn , logger:error , logger:severe , logger:fatal
With the mail interface you get a very minimal facility to send emails. A variety of components might need email access, in order to reach users outside of the website itself. The configuration of the way the emails are sent --remote server, local sendmail, etc.-- is implementation dependant.
The mail:send hook provided by the interface allows you to react to outgoing emails before they are sent.
See mail:send
The profile interface provides extensions to the user interface that are commonly used in applications that want users to have some kind of presence. As part of this, the interface must provide for a page on which a user's "profile" can be displayed. The profile must show panels of some kind. The panels are provided by other modules and can be added by profile:define-panel .
You can get a URI pointing to the profile page of a user through the page resource type.
The interface also provides access to an "avatar image" to visually identify the user ( profile:avatar ), a customisable name that the user can change ( profile:name ), and field types to what kind of data is contained in a user's field and whether it should be public information or not ( profile:fields profile:add-field profile:remove-field ).
See profile:page , profile:avatar , profile:name , profile:fields , profile:add-field , profile:remove-field , profile:list-panels , profile:remove-panel , profile:define-panel , profile:panel
This interface provides for a rate limitation mechanism to prevent spamming or overly eager access to potentially sensitive or costly resources. This happens in two steps. First, the behaviour of the rate limitation is defined for a particular resource by rate:define-limit . Then the resource is protected through the rate:with-limitation macro. If the access to the block by a certain user is too frequent, the block is not called, and the code in the limit definition is evaluated instead.
Note that rate limitation is per-client, -user, or -session depending on the implementation, but certainly not global.
See rate:define-limit , rate:left , rate:with-limitation
This and the logger interface are the only interfaces Radiance requires an implementation for in order to start. It is responsible for accepting and replying to HTTP requests in some manner. The implementation must accept requests and relay them to the Radiance request function, and then relay the returned response back to the requester.
Note that the actual arguments that specify the listener behaviour are implementation-dependant, as is configuration thereof. However, if applicable, the implementation must provide for a standard listener that is accessible on localhost on the port configured in (mconfig :radiance :port) and is started when radiance:startup is called.
See server:start , server:stop , server:listeners , server:started , server:stopped
The session interface provides for tracking a client over the course of multiple requests. It however cannot guarantee to track clients perfectly, as they may do several things in order to cloak or mask themselves or falsify information. Still, for most users, the session tracking should work fine enough.
The session interface is usually used by other interfaces or lower-lying libraries in order to provide persistence of information such as user authentication.
See session:*default-timeout* , session:session , session:= , session:start , session:get , session:list , session:id , session:field , session:timeout , session:end , session:active-p , session:create
This interface provides for persistent user objects and a permissions system. It does not take care of authentication, identification, tracking, or anything of the sort. It merely provides a user object upon which to build and with which permissions can be managed.
See user:user for a description of permissions and their behaviour.
See user:condition , user:not-found , user:user , user:= , user:list , user:get , user:id , user:username , user:fields , user:field , user:remove-field , user:remove , user:check , user:grant , user:revoke , user:add-default-permissions , user:create , user:remove , user:action , user:ready , user:unready
This is an extension of the database interface. Any module implementing this interface must also implement the database interface. This interface provides some extensions to allow more expressive database operations that are only directly supported by relational database systems.
See relational-database:join , relational-database:sql
*environment-root* has been removed as per issue #28 and fix #29. It has instead been replaced by a more generic mechanism for environment directories, incorporated by the function environment-directory . If you previously customised *environment-root* , please now change environment-directory instead, as described in §1.11.template-file and static-file .user:id identifier for each user object, allowing you to reference users in databases and records more efficiently.:unique on db:select and db:iterate . If you'd like to support the continued development of Radiance, please consider becoming a backer on Patreon: