Commit de354bd5 authored by Brendan Long's avatar Brendan Long

Make <protocol> nodes more configurable.

parent c79eacad
...@@ -4,7 +4,12 @@ ...@@ -4,7 +4,12 @@
"uis": [{ "uis": [{
"id": "767cc58a-47d2-4fb3-b27e-f6c0d54f26b6", "id": "767cc58a-47d2-4fb3-b27e-f6c0d54f26b6",
"name": "YouTube", "name": "YouTube",
"url": "https://www.youtube.com/tv", "protocols": [{
"urls": [
"https://www.youtube.com/tv"
],
"shortName": "DLNA-HTML5-1.0"
}],
"icons": [{ "icons": [{
"url": "images/youtube-128px.png", "url": "images/youtube-128px.png",
"width": 128, "width": 128,
...@@ -21,6 +26,11 @@ ...@@ -21,6 +26,11 @@
}, { }, {
"id": "252703FB-A447-4659-B4CD-E15BC57B7B43", "id": "252703FB-A447-4659-B4CD-E15BC57B7B43",
"name": "Sinkhole by Shaun Inman (Game)", "name": "Sinkhole by Shaun Inman (Game)",
"url": "http://shauninman.com/ludumdare/alone/sinkhole/" "protocols": [{
"urls": [
"http://shauninman.com/ludumdare/alone/sinkhole/"
],
"shortName": "DLNA-HTML5-1.0"
}]
}] }]
} }
...@@ -35,10 +35,23 @@ static const OptionEntry[] options = { ...@@ -35,10 +35,23 @@ static const OptionEntry[] options = {
{ null } { null }
}; };
static int main(string[] args) { internal static bool check_required_members(string type, Json.Object obj,
string[] required_members) {
var missing_required = false;
foreach (string member in required_members) {
if (!obj.has_member(member)) {
stderr.printf("Ignoring %s with missing required attribute \"%s\".\n",
type, member);
missing_required = true;
}
}
return !missing_required;
}
internal static int main(string[] args) {
string? root_device_xml; string? root_device_xml;
string? service_directory; string? service_directory;
RemoteUI[] remoteUIs = {}; RUI.RemoteUI[] remoteUIs = {};
try { try {
var opt_context = new OptionContext("UPnP RemoteUIServer"); var opt_context = new OptionContext("UPnP RemoteUIServer");
opt_context.set_help_enabled (true); opt_context.set_help_enabled (true);
...@@ -81,38 +94,57 @@ static int main(string[] args) { ...@@ -81,38 +94,57 @@ static int main(string[] args) {
stderr.printf("Ignoring non-object member of uis array.\n"); stderr.printf("Ignoring non-object member of uis array.\n");
continue; continue;
} }
string[] required_members = {"id", "name", "url"}; string[] required_members = {"id", "name", "protocols"};
var missing_required = false; if (!check_required_members("UI", ui_node, required_members)) {
foreach (string member in required_members) {
if (!ui_node.has_member(member)) {
stderr.printf("Ignoring UI with missing required attribute \"%s\".\n",
member);
missing_required = true;
break;
}
}
if (missing_required) {
continue; continue;
} }
var id = ui_node.get_string_member("id"); RUI.RemoteUI remoteUI = RUI.RemoteUI() {
var name = ui_node.get_string_member("name"); id = ui_node.get_string_member("id"),
var url = ui_node.get_string_member("url"); name = ui_node.get_string_member("name")
string? description = null; };
if (ui_node.has_member("description")) { if (ui_node.has_member("description")) {
description = ui_node.get_string_member("description"); remoteUI.description = ui_node.get_string_member("description");
}
RUI.Protocol[] protocols = {};
Json.Array protocols_node = ui_node.get_array_member("protocols");
for (var j = 0; j < protocols_node.get_length(); ++j) {
Json.Object protocol_node = protocols_node.get_element(j).get_object();
required_members = {"urls", "shortName"};
if (!check_required_members("protocol", protocol_node, required_members)) {
continue;
}
RUI.Protocol protocol = RUI.Protocol() {
shortName = protocol_node.get_string_member("shortName")
};
string[] urls = {};
Json.Array urls_node = protocol_node.get_array_member("urls");
for (var k = 0; k < urls_node.get_length(); ++k) {
urls += urls_node.get_element(k).get_string();
}
if (urls.length == 0) {
stderr.printf("Ignoring invalid protocols attribute with no urls.\n");
continue;
}
protocol.urls = urls;
protocols += protocol;
}
if (protocols.length == 0) {
stderr.printf("Ignoring invalid RemoteUI with 0-length protocol list.\n");
continue;
} }
Icon[]? icons = null; remoteUI.protocols = protocols;
if (ui_node.has_member("icons")) { if (ui_node.has_member("icons")) {
icons = {}; RUI.Icon[] icons = {};
Json.Array icons_node = ui_node.get_array_member("icons"); Json.Array icons_node = ui_node.get_array_member("icons");
for (var j = 0; j < icons_node.get_length(); ++j) { for (var j = 0; j < icons_node.get_length(); ++j) {
Json.Object icon_node = icons_node.get_element(j).get_object(); Json.Object icon_node = icons_node.get_element(j).get_object();
if (!icon_node.has_member("url")) { required_members = {"url"};
stderr.printf("Ignoring icon with missing require attribute \"url\" for UI %s.\n", name); if (!check_required_members("icon", icon_node, required_members)) {
continue; continue;
} }
Icon icon = {}; RUI.Icon icon = RUI.Icon() {
icon.url = icon_node.get_string_member("url"); url = icon_node.get_string_member("url")
};
if (icon_node.has_member("width")) { if (icon_node.has_member("width")) {
var width = icon_node.get_int_member("width"); var width = icon_node.get_int_member("width");
if (width > 0) { if (width > 0) {
...@@ -135,18 +167,20 @@ static int main(string[] args) { ...@@ -135,18 +167,20 @@ static int main(string[] args) {
} }
if (icons.length == 0) { if (icons.length == 0) {
stderr.printf("Ignoring invalid 0-length icons list for UI %s.\n", stderr.printf("Ignoring invalid 0-length icons list for UI %s.\n",
name); remoteUI.name);
icons = null; remoteUI.icons = null;
} else {
remoteUI.icons = icons;
} }
} }
remoteUIs += RemoteUI(id, name, description, url, icons); remoteUIs += remoteUI;
} }
} catch (Error e) { } catch (Error e) {
stderr.printf("Error reading config file %s.\n", config_file); stderr.printf("Error reading config file %s.\n", config_file);
return 3; return 3;
} }
try { try {
RemoteUIServer server = new RemoteUIServer(root_device_xml, RUI.RemoteUIServer server = new RUI.RemoteUIServer(root_device_xml,
service_directory, remoteUIs); service_directory, remoteUIs);
server.start(); server.start();
return 0; return 0;
......
...@@ -23,24 +23,22 @@ ...@@ -23,24 +23,22 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
public struct Icon { public struct RUI.Icon {
uint64? width; uint64? width;
uint64? height; uint64? height;
string url; string url;
} }
public struct RemoteUI { public struct RUI.Protocol {
public RemoteUI(string id, string name, string? description, string url, string[] urls;
Icon[]? icons) { string shortName;
this.id = id; }
this.name = name;
this.description = description; public struct RUI.RemoteUI {
this.url = url;
this.icons = icons;
}
string id; string id;
string name; string name;
string? description; string? description;
string url;
Protocol[] protocols;
Icon[]? icons; Icon[]? icons;
} }
...@@ -27,7 +27,7 @@ errordomain RUIError { ...@@ -27,7 +27,7 @@ errordomain RUIError {
BAD_CONFIG BAD_CONFIG
} }
public class RemoteUIServer { public class RUI.RemoteUIServer {
static const string REMOTE_UI_SERVICE_TYPE = "urn:schemas-upnp-org:service:RemoteUIServer:1"; static const string REMOTE_UI_SERVICE_TYPE = "urn:schemas-upnp-org:service:RemoteUIServer:1";
string root_device_xml; string root_device_xml;
...@@ -92,9 +92,14 @@ public class RemoteUIServer { ...@@ -92,9 +92,14 @@ public class RemoteUIServer {
} }
builder.close_tag("iconList"); builder.close_tag("iconList");
} }
builder.open_tag("protocol", "shortName=\"DLNA-HTML5-1.0\""); foreach (Protocol protocol in ui.protocols) {
builder.append_node("uri", ui.url); builder.open_tag("protocol",
builder.close_tag("protocol"); "shortName=\"%s\"".printf(protocol.shortName));
foreach (string url in protocol.urls) {
builder.append_node("uri", url);
}
builder.close_tag("protocol");
}
builder.close_tag("ui"); builder.close_tag("ui");
} }
builder.close_tag("uilist"); builder.close_tag("uilist");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment