Skip to content

Instantly share code, notes, and snippets.

@maxlapshin
Last active December 19, 2015 03:38
Show Gist options
  • Save maxlapshin/5891500 to your computer and use it in GitHub Desktop.
Save maxlapshin/5891500 to your computer and use it in GitHub Desktop.
Flussonic config grammar
% 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