Last active
December 19, 2015 03:38
-
-
Save maxlapshin/5891500 to your computer and use it in GitHub Desktop.
Flussonic config grammar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% sublime: syntax Erlang | |
config <- config_line* ~; | |
% Here goes all possible top-level things | |
config_line <- listener / loglevel / sessions / max_sessions_option / autogenerate_tokens / include / | |
http_event / central / stream / rewrite / live / file / | |
view_auth / edit_auth; | |
% Listener is for protocols | |
listener <- space? proto:("http" / "rtsp" / "rtmp") space? port:number ";"? space? ` | |
{proto,Proto} = lists:keyfind(proto,1,Node), | |
{binary_to_atom(Proto,latin1), pl(port,Node)} | |
`; | |
loglevel <- space? "loglevel" space? level:string space? ";"? space? ` | |
{loglevel, binary_to_atom(pl(level,Node), latin1)} | |
`; | |
sessions <- space? ("sessions" / "auth") space? url:string space? ";"? space? ` | |
URL = case pl(url,Node) of | |
<<"true">> -> true; | |
<<"false">> -> false; | |
Else -> Else | |
end, | |
{auth, URL, []} | |
`; | |
autogenerate_tokens <- space? "no_auto_token" space? ";"? space? ` | |
{autogenerate_token, false} | |
`; | |
include <- space? "include" space? path:string space? ";"? space? ` | |
{include, binary_to_list(pl(path,Node))} | |
`; | |
http_event <- space? "notify" space? url:string space? ";"? space? ` | |
{http_events, pl(url,Node)} | |
`; | |
central <- space? "central" space? key:string space? url:string space? ";"? space? / | |
space? "central" space? key:string space? ";"? space? ` | |
Key = pl(key, Node), | |
case pl(url, Node) of | |
undefined -> {central, Key}; | |
URL -> {central, Key, [{host,URL}]} | |
end | |
`; | |
% Static stream definitions | |
stream <- short_stream / full_stream; | |
short_stream <- space? "stream" space? name:string space? url:string space? ";"? space? ` | |
{stream, pl(name,Node), [pl(url,Node)], []} | |
`; | |
full_stream <- space? "stream" space? name:string space? "{" space? options:(stream_option*) "}" space? ";"? space? ` | |
apply_stream_options(pl(name,Node), pl(options,Node)) | |
`; | |
stream_option <- auth_option / urls_option / url_option / dvr_option / domains_option / domain_option / udp_option / | |
thumb_option / retry_option / clients_timeout_option / password_option / push_option / publish_enabled_option / | |
max_sessions_option / transcoder_option / rtp_option; | |
file_option <- auth_option / urls_option / url_option / domains_option / domain_option / cache_option / | |
read_queue_option; | |
% Dynamic rewrite | |
rewrite <- long_rewrite / short_rewrite; | |
short_rewrite <- space? "rewrite" space? name:string space? url:string space? ";"? space? ` | |
Name1 = pl(name,Node), | |
{Type,Name, Opts} = case re:run(Name1, "(.*)/\\*", [{capture,all_but_first,binary}]) of | |
{match, [N1]} -> {dynamic, N1,[]}; | |
nomatch -> {stream, Name1, [{static,false}]} | |
end, | |
{Type, Name, [pl(url,Node)], Opts} | |
`; | |
long_rewrite <- space? "rewrite" space? name:string space? "{" space? options:(stream_option*) "}" space? ";"? space? ` | |
#opts{} = Opts = apply_options(pl(options,Node)), | |
Options = make_options(Opts), | |
Name1 = pl(name,Node), | |
{Type,Name,Opts1} = case re:run(Name1, "(.*)/\\*", [{capture,all_but_first,binary}]) of | |
{match, [N1]} -> {dynamic, N1,[]}; | |
nomatch -> {stream, Name1,[{static,false}]} | |
end, | |
{Type, Name, urls(Opts), Opts1++Options} | |
`; | |
% Live | |
live <- full_live / short_live; | |
short_live <- space? "live" space? name:string space? ";"? space? ` | |
{live, pl(name,Node), []} | |
`; | |
full_live <- space? "live" space? name:string space? "{" space? options:(stream_option*) "}" space? ";"? space? ` | |
#opts{} = Opts = apply_options(pl(options,Node)), | |
{live, pl(name,Node), make_options(Opts)} | |
`; | |
% Files streaming | |
file <- full_file / short_file; | |
short_file <- space? "file" space? name:string space? path:string space? ";"? space? ` | |
{file, pl(name,Node), [pl(path,Node)], []} | |
`; | |
full_file <- space? "file" space? name:string space? "{" space? options:(file_option*) "}" space? ";"? space? ` | |
#opts{} = Opts = apply_options(pl(options,Node)), | |
Name = pl(name,Node), | |
{file, Name, urls(Opts), make_options(Opts#opts{prefix = Name})} | |
`; | |
% Auth of admin panel | |
view_auth <- space? "view_auth" space? login:string space? password:string space? ";"? space? ` | |
{view_auth, pl(login,Node), pl(password,Node)} | |
`; | |
edit_auth <- space? "edit_auth" space? login:string space? password:string space? ";"? space? ` | |
{edit_auth, pl(login,Node), pl(password,Node)} | |
`; | |
% Options | |
auth_option <- space? "auth" space? url:string space? ";"? space? ` | |
URL = case pl(url,Node) of | |
<<"true">> -> true; | |
<<"false">> -> false; | |
URL_ -> URL_ | |
end, | |
{auth, URL} | |
`; | |
url_option <- space? ("url" / "path") space? url:string space? ";"? space? ` | |
{url, pl(url,Node)} | |
`; | |
urls_option <- space? ("urls" / "paths") space? urls:((s:string space?)*) ";"? space? ` | |
{urls, [pl(s,N) || N <- pl(urls,Node)]} | |
`; | |
dvr_option <- space? "dvr" space? path:string space? settings:(dvr_setting*) space? ";"? space? ` | |
S = pl(settings,Node), | |
{dvr, pl(path,Node), pl(dvr_limit,S), pl(disk_limit,S)} | |
`; | |
dvr_setting <- disk_limit:percent space? / dvr_limit:dvr_limit space? ` | |
hd(Node) | |
`; | |
dvr_limit <- t:time / n:number ` | |
case Node of | |
{t,Time} -> Time div 60; | |
{n,Time} -> Time | |
end | |
`; | |
domain_option <- space? "domain" space? domain:string space? ";"? space? ` | |
{domain, pl(domain,Node)} | |
`; | |
domains_option <- space? "domains" space? domains:((s:string space?)*) ";"? space? ` | |
{domains, [pl(s,N) || N <- pl(domains,Node)]} | |
`; | |
udp_option <- space? "udp" space? url:string space? mc:"multicast_loop" space? ";"? space? / | |
space? "udp" space? url:string space? space? ";"? space? ` | |
case pl(mc,Node) of | |
undefined -> {udp, pl(url,Node)}; | |
_ -> {udp, pl(url,Node), multicast_loop} | |
end | |
`; | |
thumb_option <- space? "thumbnails" space? ";"? space? ` | |
{thumb, true} | |
`; | |
cache_option <- space? "cache" space? path:string space? time_limit:number space? disk_limit:number space? ";"? space? / | |
space? "cache" space? path:string space? settings:(cache_setting*) ";"? space? ` | |
case pl(time_limit,Node) of | |
undefined -> {cache, pl(path,Node), pl(settings,Node)}; | |
Time -> {cache, pl(path,Node), [{time_limit,Time},{disk_limit,pl(disk_limit,Node)*1024*1024}]} | |
end | |
`; | |
cache_setting <- "misses=" misses:number space? / time_limit:time space? / disk_limit:disk space? ` | |
case lists:keyfind(misses, 1, Node) of | |
{misses,M} -> {misses, M}; | |
false -> hd(Node) | |
end | |
`; | |
retry_option <- space? "retry_limit" space? limit:number space? ";"? space? ` | |
{retry_limit, pl(limit,Node)} | |
`; | |
clients_timeout_option <- space? ("clients_timeout" / "client_timeout") space? timeout:number space? ";"? space? ` | |
{clients_timeout, pl(timeout,Node)} | |
`; | |
password_option <- space? "password" space? password:string space? ";"? space? ` | |
{password, binary_to_list(pl(password,Node))} | |
`; | |
push_option <- space? "push" space? url:string space? ";"? space? ` | |
{push, pl(url,Node)} | |
`; | |
publish_enabled_option <- space? "publish_enabled" space? ";"? space? ` | |
{publish_enabled, true} | |
`; | |
max_sessions_option <- space? "max_sessions" space? count:number space? ";"? space? ` | |
{max_sessions, pl(count,Node)} | |
`; | |
read_queue_option <- space? "read_queue" space? count:number space? ";"? space? ` | |
{read_queue, pl(count,Node)} | |
`; | |
transcoder_option <- space? "transcoder" space? settings:(transcoder_setting*) ";"? space? ` | |
{transcoder, pl(settings, Node)} | |
`; | |
transcoder_setting <- "vb=" video_bitrate:bitrate space? / "ab=" audio_bitrate:bitrate space? / | |
"config=" config:string space? ` | |
lists:nth(2,Node) | |
`; | |
time <- num:number scale:("m" / "h" / "d") ` | |
Number = pl(num,Node), | |
case pl(scale,Node) of | |
<<"m">> -> Number*60; | |
<<"h">> -> Number*3600; | |
<<"d">> -> Number*24*3600 | |
end | |
`; | |
disk <- num:number scale:("K" / "M" / "G") ` | |
Number = pl(num,Node), | |
case pl(scale,Node) of | |
<<"K">> -> Number*1024; | |
<<"M">> -> Number*1024*1024; | |
<<"G">> -> Number*1024*1024*1024 | |
end | |
`; | |
bitrate <- num:number "k" ` | |
pl(num,Node)*1000 | |
`; | |
string <- (nonspace)+ `iolist_to_binary(Node)`; | |
nonspace <- [^ ;\{\}\n\t\r] ~; | |
number <- [0-9]+ `list_to_integer(binary_to_list(iolist_to_binary(Node)))`; | |
percent <- num:number "%" `pl(num,Node)`; | |
space <- (white / comment_to_eol)+ ` | |
space | |
`; | |
white <- [ \t\n\r] ~; | |
comment_to_eol <- !'%{' ('#' / '%') (!"\n" .)* ~; | |
` | |
-record(opts, { | |
prefix, | |
domains = [], | |
auth = true, | |
dvr, | |
dvr_limit, | |
disk_limit, | |
cache, | |
urls = [], | |
push = [], | |
publish_enabled, | |
udp, | |
multicast_loop, | |
thumb, | |
retry_limit, | |
password, | |
max_sessions, | |
read_queue, | |
clients_timeout, | |
transcoder | |
}). | |
apply_stream_options(Name, Options) -> | |
#opts{} = Opts = apply_options(Options), | |
{stream, Name, urls(Opts), make_options(Opts)}. | |
l(_, undefined) -> []; | |
l(Key, Value) -> [{Key,Value}]. | |
make_options(#opts{dvr = DVR, dvr_limit = Time, disk_limit = Disk, domains = Domains, udp = UDP, multicast_loop = MC, | |
thumb = Thumb, auth = Auth, cache = Cache, retry_limit = RetryLimit, clients_timeout = ClientsTimeout, | |
password = Password, push = Push, publish_enabled = PublishEnabled, max_sessions = MaxSessions, | |
read_queue = ReadQueue, prefix = Prefix, transcoder = Transcoder}) -> | |
AuthOptions = | |
case Domains of | |
[] -> []; | |
_ -> [{domains,Domains}] | |
end, | |
case DVR of | |
undefined -> []; | |
_ -> | |
[{dvr,DVR}] ++ case Time of | |
undefined -> []; | |
_ -> [{dvr_limit,Time}] | |
end ++ case Disk of | |
undefined -> []; | |
_ -> [{disk_limit,Disk}] | |
end | |
end ++ | |
case UDP of | |
undefined -> []; | |
_ when MC == true -> [{udp,<<"udp://", UDP/binary>>},{multicast_loop,true}]; | |
_ -> [{udp,<<"udp://", UDP/binary>>}] | |
end ++ l(thumb,Thumb) ++ l(transcoder,Transcoder) ++ case Cache of | |
undefined -> []; | |
{CachePath,CacheOpts} -> [{cache,CachePath,CacheOpts}] | |
end ++ l(retry_limit,RetryLimit) ++ l(clients_timeout,ClientsTimeout) ++ | |
l(password,Password) ++ l(publish_enabled,PublishEnabled) ++ l(max_sessions,MaxSessions) ++ | |
case ReadQueue of | |
undefined -> []; | |
_ -> [{read_queue,ReadQueue,Prefix}] | |
end ++ | |
[{push,P} || P <- Push]++ | |
case Auth of | |
_ when AuthOptions =/= [] -> [{auth,Auth,AuthOptions}]; | |
true -> []; | |
_ -> [{auth, Auth, []}] | |
end. | |
apply_options(Options) -> apply_options(#opts{}, Options). | |
urls(#opts{urls = URLs}) -> URLs. | |
apply_options(#opts{urls = URLs} = O, [{url,URL}|Acc]) -> | |
apply_options(O#opts{urls = URLs ++ [URL]}, Acc); | |
apply_options(#opts{} = O, [{urls,URLs2}|Acc]) -> | |
apply_options(O#opts{urls = URLs2}, Acc); | |
apply_options(#opts{} = O, [{dvr,DVR, Time, Disk}|Acc]) -> | |
apply_options(O#opts{dvr = DVR, dvr_limit = Time, disk_limit = Disk}, Acc); | |
apply_options(#opts{domains = D} = O, [{domain,Domain}|Acc]) -> | |
apply_options(O#opts{domains = D ++ [Domain]}, Acc); | |
apply_options(#opts{} = O, [{domains,Domains}|Acc]) -> | |
apply_options(O#opts{domains = Domains}, Acc); | |
apply_options(#opts{} = O, [{cache,Cache,Opts}|Acc]) -> | |
apply_options(O#opts{cache = {Cache,Opts}}, Acc); | |
apply_options(#opts{} = O, [{udp,<<"udp://", UDP/binary>>}|Acc]) -> | |
apply_options(O#opts{udp = UDP}, Acc); | |
apply_options(#opts{} = O, [{udp,UDP}|Acc]) -> | |
apply_options(O#opts{udp = UDP}, Acc); | |
apply_options(#opts{} = O, [{udp,UDP,multicast_loop}|Acc]) -> | |
apply_options(O#opts{udp = UDP,multicast_loop = true}, Acc); | |
apply_options(#opts{} = O, [{auth,URL}|Acc]) -> | |
apply_options(O#opts{auth = URL}, Acc); | |
apply_options(#opts{} = O, [{thumb,true}|Acc]) -> | |
apply_options(O#opts{thumb = true}, Acc); | |
apply_options(#opts{} = O, [{retry_limit,Limit}|Acc]) -> | |
apply_options(O#opts{retry_limit = Limit}, Acc); | |
apply_options(#opts{} = O, [{clients_timeout,ClientsTimeout}|Acc]) -> | |
apply_options(O#opts{clients_timeout = ClientsTimeout}, Acc); | |
apply_options(#opts{} = O, [{password,Password}|Acc]) -> | |
apply_options(O#opts{password = Password}, Acc); | |
apply_options(#opts{push = Push} = O, [{push,P}|Acc]) -> | |
apply_options(O#opts{push = Push ++ [P]}, Acc); | |
apply_options(#opts{} = O, [{publish_enabled,true}|Acc]) -> | |
apply_options(O#opts{publish_enabled = true}, Acc); | |
apply_options(#opts{} = O, [{max_sessions,S}|Acc]) -> | |
apply_options(O#opts{max_sessions = S}, Acc); | |
apply_options(#opts{} = O, [{read_queue,Q}|Acc]) -> | |
apply_options(O#opts{read_queue = Q}, Acc); | |
apply_options(#opts{} = O, [{transcoder,TC}|Acc]) -> | |
apply_options(O#opts{transcoder = TC}, Acc); | |
apply_options(#opts{} = O, []) -> O. | |
pl(Key, Proplist) -> proplists:get_value(Key, Proplist). | |
` | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment