Frontend: Add public channel list and channel log file list
This commit is contained in:
parent
1ffe5fffb4
commit
242cad6291
@ -14,9 +14,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package frontend;
|
||||||
|
|
||||||
use IO::Socket;
|
use IO::Socket;
|
||||||
use File::Spec;
|
use File::Spec;
|
||||||
use Time::Piece;
|
use Time::Piece;
|
||||||
|
use DBI;
|
||||||
|
|
||||||
use lib ".";
|
use lib ".";
|
||||||
use configuration;
|
use configuration;
|
||||||
@ -50,6 +53,59 @@ sub stringToHTTPMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use constant {
|
||||||
|
PPATH_URL => 0,
|
||||||
|
PPATH_GET_KEY => 1,
|
||||||
|
PPATH_GET_VALUE => 2
|
||||||
|
};
|
||||||
|
sub parsePath {
|
||||||
|
my $aPath = $_[0];
|
||||||
|
|
||||||
|
my $pathLength = length($aPath);
|
||||||
|
my $state = PPATH_URL;
|
||||||
|
my $currentString = "";
|
||||||
|
my $currentString2 = "";
|
||||||
|
my %output;
|
||||||
|
foreach my $i (0..$pathLength-1) {
|
||||||
|
my $char = substr($aPath, $i, 1);
|
||||||
|
given($state) {
|
||||||
|
when(PPATH_URL) {
|
||||||
|
if($char eq "?") {
|
||||||
|
$output{"url"} = $currentString;
|
||||||
|
$currentString = "";
|
||||||
|
$state = PPATH_GET_KEY;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$currentString.=$char;
|
||||||
|
if($i==$pathLength-1) {
|
||||||
|
$output{"url"} = $currentString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when(PPATH_GET_KEY) {
|
||||||
|
if($char eq "=") {
|
||||||
|
$state = PPATH_GET_VALUE;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$currentString.=$char;
|
||||||
|
}
|
||||||
|
when(PPATH_GET_VALUE) {
|
||||||
|
if($char eq "&") {
|
||||||
|
$state = PPATH_GET_KEY;
|
||||||
|
$output{"parameters"}{$currentString} = $currentString2;
|
||||||
|
$currentString = "";
|
||||||
|
$currentString2 = "";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$currentString2.=$char;
|
||||||
|
if($i==$pathLength-1) {
|
||||||
|
$output{"parameters"}{$currentString} = $currentString2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return %output;
|
||||||
|
}
|
||||||
|
|
||||||
use constant {
|
use constant {
|
||||||
PHTTP_METHOD => 0,
|
PHTTP_METHOD => 0,
|
||||||
PHTTP_PATH => 1,
|
PHTTP_PATH => 1,
|
||||||
@ -80,7 +136,7 @@ sub parseHTTPRequest {
|
|||||||
}
|
}
|
||||||
when(PHTTP_PATH) {
|
when(PHTTP_PATH) {
|
||||||
if($char eq " ") {
|
if($char eq " ") {
|
||||||
$output{"path"} = $currentString;
|
$output{"path"} = { parsePath($currentString) };
|
||||||
$currentString = "";
|
$currentString = "";
|
||||||
$state = PHTTP_VERSION;
|
$state = PHTTP_VERSION;
|
||||||
next;
|
next;
|
||||||
@ -153,6 +209,18 @@ sub sendNotFound {
|
|||||||
$aClient->send($response);
|
$aClient->send($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub sendBadRequest {
|
||||||
|
my $aClient = $_[0];
|
||||||
|
my $aMessage = $_[1];
|
||||||
|
|
||||||
|
my $content = "<h1>400 Bad Request</h1><h6>irclogger_web</h6>Error: $aMessage";
|
||||||
|
my $response = getBaseResponse(400, "Bad Request");
|
||||||
|
$response.="Content-Type: text/html, charset=utf-8\r\n";
|
||||||
|
$response.="Content-Length: ".length($content)."\r\n\r\n";
|
||||||
|
$response.=$content;
|
||||||
|
$aClient->send($response);
|
||||||
|
}
|
||||||
|
|
||||||
use constant {
|
use constant {
|
||||||
PREPROCESSOR_STATE_TEXT => 0,
|
PREPROCESSOR_STATE_TEXT => 0,
|
||||||
PREPROCESSOR_STATE_VAR => 1,
|
PREPROCESSOR_STATE_VAR => 1,
|
||||||
@ -208,7 +276,7 @@ sub preprocessHTML {
|
|||||||
if($nextChar eq "]") {
|
if($nextChar eq "]") {
|
||||||
$index++;
|
$index++;
|
||||||
if(open(my $file, "<", $currentString)) {
|
if(open(my $file, "<", $currentString)) {
|
||||||
$output.=readFullFile($file);
|
$output.=preprocessHTML(readFullFile($file), $aVariables);
|
||||||
close($file);
|
close($file);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -242,6 +310,7 @@ sub sendTemplate {
|
|||||||
my $response = getBaseResponse(200, "OK");
|
my $response = getBaseResponse(200, "OK");
|
||||||
$response.="Content-Length: $length\r\n\r\n";
|
$response.="Content-Length: $length\r\n\r\n";
|
||||||
$response.=$content;
|
$response.=$content;
|
||||||
|
print("$response\n");
|
||||||
$aClient->send($response);
|
$aClient->send($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,10 +318,54 @@ sub handlePath {
|
|||||||
my $aClient = $_[0];
|
my $aClient = $_[0];
|
||||||
my $aPath = $_[1];
|
my $aPath = $_[1];
|
||||||
my $aRequest = $_[2];
|
my $aRequest = $_[2];
|
||||||
|
my $aConnection = $_[3];
|
||||||
|
|
||||||
given($aPath) {
|
given($aPath) {
|
||||||
when("/") {
|
when("/") {
|
||||||
sendTemplate("templates/index.html", $aClient, {"var"=>"value"});
|
my $query = $aConnection->prepare(qq(select channels.id, channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.public=1;));
|
||||||
|
$query->execute();
|
||||||
|
my $table = "";
|
||||||
|
while(my @row = $query->fetchrow_array()) {
|
||||||
|
my $channelID = $row[0];
|
||||||
|
my $channelName = $row[1];
|
||||||
|
my $serverName = $row[2];
|
||||||
|
|
||||||
|
$table.="<tr><td><a href=\"view_logs?channel=$channelID\">$channelName</a></td><td>$serverName</td></tr>";
|
||||||
|
}
|
||||||
|
sendTemplate("templates/index.html", $aClient, {"publicChannels"=>$table});
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
when("/view_logs") {
|
||||||
|
my $channelID = $aRequest->{"path"}{"parameters"}{"channel"};
|
||||||
|
if(!defined($channelID)) {
|
||||||
|
sendBadRequest($aClient, "view_log requires channel URL parameter");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $query = $aConnection->prepare(qq(select channels.name, servers.name from channels inner join servers on channels.server_id=servers.id where channels.id=?;));
|
||||||
|
$query->execute($channelID);
|
||||||
|
my @row = $query->fetchrow_array();
|
||||||
|
if(scalar(@row)==0) {
|
||||||
|
sendBadRequest($aClient, "Unknown channel with ID $channelID");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
my $channelName = $row[0];
|
||||||
|
my $serverName = $row[1];
|
||||||
|
my $logsPath = "logs/".$serverName."/".$channelName;
|
||||||
|
|
||||||
|
my $result = opendir(my $folder, $logsPath);
|
||||||
|
if(!$result) {
|
||||||
|
sendBadRequest($aClient, "Channel $channelName on $serverName doesn't have any logs");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
my @entries = grep(!/^\.\.?$/, readdir($folder));
|
||||||
|
|
||||||
|
my $table = "";
|
||||||
|
foreach my $entry (@entries) {
|
||||||
|
$table.="<tr><td><a href=\"view_log?channel=$channelID\">$entry</a></td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTemplate("templates/view_logs.html", $aClient, {"channel"=>$channelName, "server"=>$serverName, "logs"=>$table});
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,6 +375,7 @@ sub handlePath {
|
|||||||
sub sendResponse {
|
sub sendResponse {
|
||||||
my $aClient = $_[0];
|
my $aClient = $_[0];
|
||||||
my $aRequest = $_[1];
|
my $aRequest = $_[1];
|
||||||
|
my $aConnection = $_[2];
|
||||||
|
|
||||||
if($aRequest->{"version"} ne "HTTP/1.1") {
|
if($aRequest->{"version"} ne "HTTP/1.1") {
|
||||||
sendNotImplemented($aClient);
|
sendNotImplemented($aClient);
|
||||||
@ -270,11 +384,11 @@ sub sendResponse {
|
|||||||
|
|
||||||
given($aRequest->{"method"}) {
|
given($aRequest->{"method"}) {
|
||||||
when(HTTP_METHOD_GET) {
|
when(HTTP_METHOD_GET) {
|
||||||
my $path = File::Spec->canonpath($aRequest->{"path"});
|
my $path = File::Spec->canonpath($aRequest->{"path"}{"url"});
|
||||||
if($path eq "/index.html" || $path eq "/index.htm") {
|
if($path eq "/index.html" || $path eq "/index.htm") {
|
||||||
$path = "/";
|
$path = "/";
|
||||||
}
|
}
|
||||||
if(handlePath($aClient, $path, $aRequest)) {
|
if(handlePath($aClient, $path, $aRequest, $aConnection)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
my $filePath = "static".$path;
|
my $filePath = "static".$path;
|
||||||
@ -300,6 +414,7 @@ sub sendResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub httpServerWorker {
|
sub httpServerWorker {
|
||||||
|
my $db = DBI->connect("DBI:SQLite:dbname=$configuration::database", "", "", {RaiseError=>1});
|
||||||
my $server = new IO::Socket::INET(LocalHost=>"localhost", LocalPort=>$configuration::httpServerPort, Proto=>"tcp", Listen=>1, Reuse=>1);
|
my $server = new IO::Socket::INET(LocalHost=>"localhost", LocalPort=>$configuration::httpServerPort, Proto=>"tcp", Listen=>1, Reuse=>1);
|
||||||
if(!$server) {
|
if(!$server) {
|
||||||
print("Failed to open HTTP server on port $configuration::httpServerPort\n");
|
print("Failed to open HTTP server on port $configuration::httpServerPort\n");
|
||||||
@ -314,9 +429,9 @@ sub httpServerWorker {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
my %request = parseHTTPRequest($buffer);
|
my %request = parseHTTPRequest($buffer);
|
||||||
sendResponse($client, \%request);
|
sendResponse($client, \%request, $db);
|
||||||
close($client);
|
close($client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httpServerWorker();
|
1;
|
@ -18,7 +18,6 @@ use IO::Socket;
|
|||||||
use List::Util;
|
use List::Util;
|
||||||
use Time::Piece;
|
use Time::Piece;
|
||||||
use File::Path;
|
use File::Path;
|
||||||
use DBI;
|
|
||||||
use threads;
|
use threads;
|
||||||
|
|
||||||
use lib ".";
|
use lib ".";
|
||||||
|
26
main.pl
Normal file
26
main.pl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# irclogger_web
|
||||||
|
# Copyright (C) 2023 mrkubax10 <mrkubax10@onet.pl>
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use lib ".";
|
||||||
|
use frontend;
|
||||||
|
|
||||||
|
use threads;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my $frontendThread = threads->create("frontend::httpServerWorker");
|
||||||
|
$frontendThread->join();
|
@ -1 +1,13 @@
|
|||||||
<h1>{{var}}</h1>
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>irclogger_web</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>Channel list</h2>
|
||||||
|
<table border>
|
||||||
|
<tr><th>Channel</th><th>Network</th></tr>
|
||||||
|
{{publicChannels}}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
12
templates/view_logs.html
Normal file
12
templates/view_logs.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Logs for {{channel}} at {{server}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table border>
|
||||||
|
<tr><th>File</th></tr>
|
||||||
|
{{logs}}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user