1 /** 2 * Authors: Tomoya Tanjo 3 * Copyright: © 2021 Tomoya Tanjo 4 * License: Apache-2.0 5 */ 6 module salad.fetcher; 7 8 /// 9 auto fetchText(string uri) 10 { 11 if (__ctfe) 12 { 13 import std.format : format; 14 assert(false, format!"%s is not supported at compile time."(__FUNCTION__)); 15 //return import(uri); 16 } 17 else 18 { 19 return Fetcher.instance.fetchText(uri); 20 } 21 } 22 23 /// 24 auto fetchNode(string uri) 25 { 26 import dyaml : Loader; 27 return Loader.fromString(fetchText(uri)).load; 28 } 29 30 /// 31 auto scheme(string uri) @nogc nothrow pure @safe 32 { 33 import std.algorithm : findSplit; 34 if (auto split = uri.findSplit("://")) 35 { 36 return split[0]; 37 } 38 else 39 { 40 return ""; 41 } 42 } 43 44 /// 45 auto pathWithAuthority(string uri) pure @safe 46 { 47 import std.algorithm : findSplit; 48 if (auto sp1 = uri.findSplit("://")) 49 { 50 auto rest = sp1[2]; 51 if (auto sp2 = rest.findSplit("#")) 52 { 53 return sp2[0]; 54 } 55 else 56 { 57 return rest; 58 } 59 } 60 else 61 { 62 throw new Exception("Not valid URI"); 63 } 64 } 65 66 unittest 67 { 68 assert("file:///foo/bar#buzz".pathWithAuthority == "/foo/bar"); 69 assert("file:///foo/bar/buzz".pathWithAuthority == "/foo/bar/buzz"); 70 assert("ssh://user@hostname:/fuga/hoge/piyo".pathWithAuthority == "user@hostname:/fuga/hoge/piyo"); 71 } 72 73 /// 74 auto fragment(string uri) @nogc nothrow pure @safe 75 { 76 import std.algorithm : findSplit; 77 if (auto split = uri.findSplit("#")) 78 { 79 return split[2]; 80 } 81 else 82 { 83 return ""; 84 } 85 } 86 87 /++ 88 A fetcher type that returns a string from absolute URI. 89 +/ 90 alias TextFetcher = string delegate(string) @safe; 91 92 /// 93 class Fetcher 94 { 95 /// 96 static typeof(this) instance() 97 { 98 static Fetcher instance_; 99 100 if (instance_ is null) 101 { 102 instance_ = new Fetcher(); 103 } 104 return instance_; 105 } 106 107 /// 108 auto addSchemeFetcher(string scheme, TextFetcher fetcher) 109 { 110 schemeFetchers[scheme] = fetcher; 111 } 112 113 /// 114 auto fetchText(string uri) 115 { 116 import salad.fetcher.exception : fetcherEnforce; 117 import std.format : format; 118 119 auto scheme = uri.scheme; 120 auto fetcher = *fetcherEnforce(scheme in schemeFetchers, 121 format!"Scheme `%s` is not supported."(scheme)); 122 return fetcher(uri); 123 } 124 private: 125 this() 126 { 127 schemeFetchers["file"] = (uri) { 128 import salad.fetcher.exception : fetcherEnforce; 129 import std.file : exists, readText; 130 import std.format : format; 131 132 auto path = uri.pathWithAuthority; 133 fetcherEnforce(path.exists, format!"File not found: `%s`"(path)); 134 return path.readText; 135 }; 136 // schemeFetchers["http"] = schemeFetchers["https"] = (uri) { 137 // return ""; 138 // }; 139 } 140 TextFetcher[string] schemeFetchers; 141 }