1 module commandcontroller; 2 import std.stdio; 3 import std.range; 4 import std.algorithm; 5 import std.algorithm.comparison; 6 import std.conv; 7 import std.array; 8 import std.typecons; 9 import std.traits; 10 import std.string; 11 import std.uri; 12 import url; 13 import std.algorithm.iteration; 14 import clients.sourceclient; 15 import clients.opmlclient; 16 import clients.feedsclient; 17 import models; 18 import apierror; 19 20 class CommandController { 21 22 protected SourceClient _sourceClient; 23 protected OpmlClient _opmlClient; 24 protected FeedsClient _feedsClient; 25 26 private static uint defaultSize = 10; 27 28 public this( 29 SourceClient sourceClient, 30 OpmlClient opmlClient, 31 FeedsClient feedsClient 32 ) { 33 _sourceClient = sourceClient; 34 _opmlClient = opmlClient; 35 _feedsClient = feedsClient; 36 } 37 38 public void all() { 39 auto result = _sourceClient.getAllSources(); 40 foreach (source; result) { 41 writeln(to!string(source.id) ~ ": " ~ source.url); 42 } 43 } 44 45 public void latest() { 46 auto page = _sourceClient.latest(); 47 printPage(page, "No entries"); 48 } 49 50 public void favorites() { 51 auto page = _feedsClient.favorites(); 52 printPage(page, "No new entries"); 53 } 54 55 private static void printPage(Page page, string whenEmpty) { 56 auto xs = page.resources; 57 if (page.isEmpty()) { 58 writeln("No new entries"); 59 return; 60 } 61 ulong max = 0; 62 63 foreach (x; xs) { 64 auto len = x.title.walkLength; 65 if (len > max) { 66 max = len; 67 } 68 } 69 70 foreach (x; xs) { 71 auto len = x.title.walkLength; 72 auto diffSize = max - len + defaultSize; 73 auto between = replicate(" ", diffSize); 74 writeln(x.title ~ between ~ x.url); 75 } 76 writeln("Total: " ~ to!string(page.total)); 77 } 78 79 public void download() { 80 _opmlClient.download(); 81 } 82 83 public void add(string url, string name, string interval) { 84 auto tmpInterval = 8; 85 auto tmpName = url.parseURL.host; 86 87 if (uriLength(url) < 0) { 88 writeln(url ~ " is not a valid URL!"); 89 return; 90 } 91 if (!interval.empty) { 92 tmpInterval = conv( interval); 93 if (tmpInterval <= 0) { 94 writeln("Interval must be positive integer"); 95 return; 96 } 97 } 98 if (!name.empty) { 99 tmpName = name; 100 } 101 102 auto newSource = NewSource(url, tmpName, tmpInterval); 103 try { 104 auto result = _sourceClient.addSource(newSource); 105 if (result) { 106 writeln("Source " ~ url ~ " was added"); 107 } else { 108 writeln("Source " ~ url ~ " was not added"); 109 } 110 } catch(Exception ex) { 111 writeln("Can not add new source " ~ url ~ " because: " ~ ex.message); 112 } 113 } 114 115 private static int conv(string str) { 116 try { 117 return to!int(str); 118 } catch (Exception ex) { 119 return -1; 120 } 121 } 122 123 public void overview(string str) { 124 int id = 0; 125 try { 126 id = to!int(str); 127 if (id <= 0) { 128 overviewHelp(str); 129 return; 130 } 131 auto source = _sourceClient.getOne(id); 132 auto overview = _sourceClient.overview(id); 133 auto tmp = max(findMax(source), findMax(overview)); 134 print(source, tmp); 135 print(overview, tmp); 136 137 } catch(ConvException ex) { 138 overviewHelp(str); 139 } catch(ApiError error) { 140 if (error.is404()) { 141 writeln("Source " ~ to!string(id) ~ " not found"); 142 return; 143 } 144 writeln(error.message()); 145 } 146 } 147 148 private ulong findMax(T)(T instance) { 149 ulong max = 0; 150 foreach (member; __traits(allMembers, T)) { 151 auto len = member.walkLength; 152 if (len > max) { 153 max = len; 154 } 155 } 156 return max; 157 } 158 159 private T print(T)(T instance, ulong max) { 160 foreach (member; __traits(allMembers, T)) { 161 auto value = __traits(getMember, instance, member); 162 auto len = to!string(member).walkLength; 163 auto attrs = __traits(getAttributes, __traits(getMember, T, member)); 164 auto field = member.capitalize; 165 foreach(attr; attrs) { 166 static if (is(typeof(attr) == Alias)) { 167 field = attr.name; 168 } 169 } 170 if (!hasUDA!(__traits(getMember, T, member), Ignore)) { 171 print(max, to!string(value), field); 172 } 173 } 174 return instance; 175 } 176 177 private static void print(ulong max, string value, string member) { 178 auto len = member.walkLength; 179 auto diffSize = max - len + defaultSize; 180 auto between = replicate(" ", diffSize); 181 writeln(member ~ between ~ to!string(value)); 182 } 183 184 private static overviewHelp(string str) { 185 writeln("Positive number is required, given: " ~ str); 186 } 187 188 }