daster/source/daster.d

469 lines
14 KiB
D
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module daster;
import vibe.vibe;
import singlog;
import readconf;
import core.stdc.stdlib : exit, EXIT_SUCCESS, EXIT_FAILURE;
import std.stdio: writefln;
import std.getopt;
import std.file;
import std.path;
import std.algorithm;
import std.array;
import verinfo;
import pgdb;
import structures;
import response;
import requests.numbers;
import requests.sms;
import requests.ussd;
import requests.server;
import requests.authorization;
static ServerInfo serverInfo;
static AuthData serverAuthData;
private void showVersion() {
writefln("daster версия %s, собрано %s", getDasterVersion(), __DATE__);
}
void page404(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo error) {
res.render!("404.dt", req, error);
}
int main(string[] args) {
log.level(log.INFORMATION)
.output(log.SYSLOG)
.color(true);
bool flagVersion;
string flagSettings;
try {
auto opt = getopt(
args,
config.bundling,
config.caseSensitive,
"settings|s",
"<файл> Путь к файлу конфигурации settings.conf",
&flagSettings,
"version|v",
"Текущая версия программы",
&flagVersion
);
if (opt.helpWanted) {
showVersion();
defaultGetoptPrinter(
"Использование: daster [ОПЦИИ]...\n",
opt.options
);
return EXIT_SUCCESS;
}
if (flagVersion) {
showVersion();
return EXIT_SUCCESS;
}
} catch (GetOptException e) {
showVersion();
log.c(e.msg);
log.i("Попробуйте 'daster -h' для дополнительной информации");
log.i("https://git.zhirov.kz/alexander/daster");
return EXIT_FAILURE;
}
if (!flagSettings.length)
flagSettings = "./settings.conf";
if (!flagSettings.exists) {
log.c("Файл конфигурации не найден: " ~ flagSettings);
exit(1);
}
rc.read(flagSettings);
auto webHost = rcWebHost();
serverInfo = ServerInfo(webHost.title);
if (webHost.loglevel != -1) log.level(webHost.loglevel);
if (webHost.logoutput) log.output(webHost.logoutput);
if (webHost.logfile.length) log.file(webHost.logfile);
rcAsteriskDB();
rcAuth();
auto router = new URLRouter;
router.post("/", &postReq);
router.get("/", &getReq);
router.get("*", serveStaticFiles(buildPath(webHost.data, "public")));
router.get("*", serveStaticFiles(buildPath(webHost.data, "images")));
router.get("*", serveStaticFiles(buildPath(webHost.data, "js")));
router.get("*", serveStaticFiles(buildPath(webHost.data, "jq")));
auto memorySessionStore = new MemorySessionStore;
auto settingsHTTP = new HTTPServerSettings;
auto settingsHTTPS = new HTTPServerSettings;
if (webHost.http) {
settingsHTTP.errorPageHandler = toDelegate(&page404);
settingsHTTP.sessionStore = memorySessionStore;
settingsHTTP.port = webHost.http;
settingsHTTP.bindAddresses = ["::1"] ~ webHost.addresses;
}
if (webHost.https) {
settingsHTTPS.errorPageHandler = toDelegate(&page404);
settingsHTTPS.sessionStore = memorySessionStore;
settingsHTTPS.port = webHost.https;
settingsHTTPS.bindAddresses = ["::1"] ~ webHost.addresses;
settingsHTTPS.tlsContext = createTLSContext(TLSContextKind.server);
settingsHTTPS.tlsContext.useCertificateChainFile(webHost.cert);
settingsHTTPS.tlsContext.usePrivateKeyFile(webHost.key);
}
startWebServer(webHost, settingsHTTP, settingsHTTPS, router);
return EXIT_SUCCESS;
}
void startWebServer(WebHost wh, HTTPServerSettings http, HTTPServerSettings https, URLRouter router)
{
if (wh.http && wh.https) {
auto listenerHTTP = listenHTTP(http, router);
auto listenerHTTPS = listenHTTP(https, router);
scope (exit) { listenerHTTP.stopListening(); }
scope (exit) { listenerHTTPS.stopListening(); }
runApplication();
} else if (wh.http) {
auto listenerHTTP = listenHTTP(http, router);
scope (exit) { listenerHTTP.stopListening(); }
runApplication();
} else if (wh.https) {
auto listenerHTTPS = listenHTTP(https, router);
scope (exit) { listenerHTTPS.stopListening(); }
runApplication();
}
}
void getReq(HTTPServerRequest req, HTTPServerResponse res) {
if (req.session) {
auto user = req.session.get!UserData("user");
if (user.login) {
renderMainPage(req, res);
return;
}
}
render!("authorization.dt", serverInfo)(res);
}
void renderMainPage(HTTPServerRequest req, HTTPServerResponse res) {
render!("index.dt", serverInfo)(res);
}
void postReq(HTTPServerRequest req, HTTPServerResponse res) {
if (req.method != HTTPMethod.POST) return;
auto jsr = req.json;
string query = jsr["query"].get!string;
if (query.empty) return;
if (query != "login" && !checkAuth(req)) {
res.send(
true,
"Сессия не существует. Перезагрузите страницу"
);
return;
}
log.d("%s: json request %s".format(req.clientAddress.toAddressString(), jsr.to!string));
switch (query) {
case "login":
login(req, res, serverAuthData);
break;
case "logout":
logout(req, res);
break;
case "listnumbergroups":
getListNumberGroups(req, res);
break;
case "listgroupnumbers":
getListGroupNumbers(req, res);
break;
case "viewnumber":
getViewNumber(req, res);
break;
case "addnumber":
getAddNumber(req, res);
break;
case "writenumber":
sendWriteNumber(req, res);
break;
case "updatenumber":
sendUpdateNumber(req, res);
break;
case "delnumber":
sendDelNumber(req, res);
break;
case "listsmsgroups":
getListSMSGroups(req, res);
break;
case "listgroupsms":
getListGroupSMS(req, res);
break;
case "viewsms":
getViewSMS(req, res);
break;
case "delsms":
sendDelSMS(req, res);
break;
case "listussdgroups":
getListUSSDGroups(req, res);
break;
case "listgroupussd":
getListGroupUSSD(req, res);
break;
case "viewussd":
getViewUSSD(req, res);
break;
case "delussd":
sendDelUSSD(req, res);
break;
case "serverinfo":
getServerInfo(req, res);
break;
case "writeserverinfo":
sendWriteServerInfo(req, res);
break;
default:
res.redirect("/");
}
}
void rcAsteriskDB() {
ConfigSection asteriskDB;
try {
asteriskDB = rc[]["daster-db"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки daster-db");
exit(1);
}
if (asteriskDB["host"].empty) {
log.c("В конфигурационном файле не верны настройки daster-db.host");
exit(1);
}
if (asteriskDB["port"].empty) {
log.c("В конфигурационном файле не верны настройки daster-db.port");
exit(1);
}
if (asteriskDB["dbname"].empty) {
log.c("В конфигурационном файле не верны настройки daster-db.dbname");
exit(1);
}
if (asteriskDB["user"].empty) {
log.c("В конфигурационном файле не верны настройки daster-db.user");
exit(1);
}
try {
pgsql(
"hostaddr=" ~ asteriskDB["host"] ~
" port=" ~ asteriskDB["port"] ~
" dbname=" ~ asteriskDB["dbname"] ~
" user=" ~ asteriskDB["user"] ~
" password=" ~ asteriskDB["password"]
);
} catch (Exception e) {
log.c(e.msg);
exit(1);
}
}
WebHost rcWebHost() {
WebHost wh;
ConfigSection webHost;
try {
webHost = rc[]["web-host"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host");
exit(1);
}
if (webHost["addresses"].empty) {
log.c("В конфигурационном файле не верны настройки web-host.addresses");
exit(1);
}
try {
wh.addresses = webHost["addresses"].to!string.split(',').map!(a => a.strip).array;
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.addresses");
exit(1);
}
if (webHost["http"].empty && webHost["https"].empty) {
log.c("В конфигурационном файле не верны настройки web-host.[http|https]:
должен быть указан хотя бы один протокол");
exit(1);
}
if (!webHost["http"].empty) {
try {
wh.http = webHost["http"].to!ushort;
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.http");
exit(1);
}
}
if (!webHost["https"].empty) {
try {
wh.https = webHost["https"].to!ushort;
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.https");
exit(1);
}
}
if (!webHost["https"].empty) {
if (webHost["cert"].empty || webHost["key"].empty) {
log.c("В конфигурационном файле не верны настройки web-host.[cert|key]:
необходимо указать сертификат и ключ для использования https протокола"
);
exit(1);
}
}
try {
wh.cert = webHost["cert"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.cert");
exit(1);
}
try {
wh.key = webHost["key"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.key");
exit(1);
}
if (!webHost["data"].empty) {
string data;
try {
data = webHost["data"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.data");
exit(1);
}
if (data.exists) {
if (!buildPath(data, "public").exists) {
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: public");
exit(1);
}
if (!buildPath(data, "js").exists) {
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: js");
exit(1);
}
if (!buildPath(data, "images").exists) {
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: images");
exit(1);
}
} else {
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: " ~ data);
exit(1);
}
wh.data = data;
}
if (!webHost["title"].empty) {
try {
wh.title = webHost["title"];
} catch (Exception e) {
log.w("Заголовок не был установлен - web-host.title");
}
}
if (!webHost["loglevel"].empty) {
try {
wh.loglevel = webHost["loglevel"].to!int;
if (wh.loglevel < 0 || wh.loglevel > 6)
throw new Exception("несуществующий уровень");
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.loglevel: " ~ e.msg);
exit(1);
}
}
if (!webHost["logoutput"].empty) {
try {
wh.logoutput = webHost["logoutput"]
.to!string.split(',')
.map!((a) {
auto flag = a.strip.to!int;
if ([1, 2, 4].canFind(flag))
return flag;
log.c("В конфигурационном файле не верны настройки web-host.logoutput");
exit(1);
})
.fold!((a, b) => a | b);
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.logoutput");
exit(1);
}
if (wh.logoutput & 4) {
if (webHost["logfile"].empty) {
log.c("В конфигурационном файле не верны настройки web-host.logfile");
exit(1);
}
try {
wh.logfile = webHost["logfile"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки web-host.logfile");
exit(1);
}
}
}
return wh;
}
void rcAuth() {
ConfigSection auth;
try {
auth = rc[]["auth"];
} catch (Exception e) {
log.c("В конфигурационном файле не верны настройки auth");
exit(1);
}
if (auth["login"].empty)
log.w("Логин не был установлен - auth.login");
else
serverAuthData.login = auth["login"];
if (auth["password"].empty)
log.w("Пароль не был установлен - auth.password");
else
serverAuthData.password = auth["password"];
}