mirror of
https://github.com/YGGverse/Pulsar.git
synced 2025-03-13 05:41:21 +00:00
implement build-in gemini server
This commit is contained in:
parent
d297b16523
commit
7275ecdacd
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
/composer.lock
|
||||
/config.json
|
||||
/data/
|
||||
/crawler.json
|
||||
/server/
|
||||
/vendor/
|
||||
|
34
README.md
34
README.md
@ -7,8 +7,8 @@ Simple RSS feed converter to static Gemtext format, useful for news portals or l
|
||||
## Usage
|
||||
|
||||
1. `git clone https://github.com/YGGverse/Pulsar.git`
|
||||
2. `cp example/config.json config.json` - setup your feeds
|
||||
3. `php src/crawler.php` - create crontab schedule
|
||||
2. `cp example/crawler.json crawler.json` - setup your feed locations
|
||||
3. `php src/crawler.php` - grab feeds manually or create the crontab task
|
||||
|
||||
## Config
|
||||
|
||||
@ -26,4 +26,32 @@ Configuration file supports multiple feed channels with custom settings:
|
||||
* `{title}` - item title
|
||||
* `{description}` - item description
|
||||
|
||||
Resulting files could be generated to the any folder for personal reading on localhost, or shared with others using [gmid](https://github.com/omar-polo/gmid), [twins](https://code.rocket9labs.com/tslocum/twins) or any other [Gemini server](https://github.com/kr1sp1n/awesome-gemini#servers).
|
||||
Resulting files could be generated to the any folder for personal reading on localhost, or shared with others using [gmid](https://github.com/omar-polo/gmid), [twins](https://code.rocket9labs.com/tslocum/twins) or any other [Gemini server](https://github.com/kr1sp1n/awesome-gemini#servers).
|
||||
|
||||
## Server
|
||||
|
||||
Pulsar comes with build-in [Titan-II](https://github.com/YGGverse/titan-II) server implementation.
|
||||
|
||||
It's especially useful for [Yggdrasil](https://github.com/yggdrasil-network/yggdrasil-go) users, who wish to host their feeds using plain IPv6 `0200::/7` addresses as the `CN` record. Build-in server contain this feature implemented from the box.
|
||||
|
||||
### Setup
|
||||
|
||||
* `cd Pulsar` - navigate to the project folder
|
||||
* `composer update` - download server dependencies with Composer
|
||||
* `mkdir server/127.0.0.1` - init server location (you can define any other destination, but `server` one is just git ignored)
|
||||
* `cp example/host.json server/127.0.0.1/host.json` - copy configuration example to the destination folder
|
||||
* `cd server/127.0.0.1` - navigate to server folder created and generate new self-signed certificate
|
||||
|
||||
On example above, certificate could be generated with following command:
|
||||
|
||||
```
|
||||
openssl req -x509 -newkey rsa:4096 -keyout key.rsa -out cert.pem -days 365 -nodes -subj "/CN=127.0.0.1"
|
||||
```
|
||||
|
||||
* _tip: for IPv6 address, just skip square brackets from `CN` value_
|
||||
|
||||
### Launch
|
||||
|
||||
* `php src/server.php server/127.0.0.1` - supported relative or absolute paths for systemd service
|
||||
|
||||
Open `gemini://127.0.0.1` in [Gemini browser](https://github.com/kr1sp1n/awesome-gemini#clients)!
|
@ -15,5 +15,7 @@
|
||||
"name": "YGGverse"
|
||||
}
|
||||
],
|
||||
"require": {}
|
||||
"require": {
|
||||
"yggverse/titan-ii": "^1.0"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
[
|
||||
{
|
||||
"source":"https://www.omglinux.com/feed",
|
||||
"target":"data/omglinux.com/feed.gmi",
|
||||
"target":"server/127.0.0.1/public/omglinux/feed.gmi",
|
||||
"item":
|
||||
{
|
||||
"template":"=> {link} {title}{nl}{nl}{description}",
|
||||
@ -12,7 +12,7 @@
|
||||
},
|
||||
{
|
||||
"source":"https://omgubuntu.co.uk/feed",
|
||||
"target":"data/omgubuntu.co.uk/feed.gmi",
|
||||
"target":"server/127.0.0.1/public/omgubuntu/feed.gmi",
|
||||
"item":
|
||||
{
|
||||
"template":"=> {link} {title}{nl}{nl}{description}",
|
12
example/host.json
Normal file
12
example/host.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"host":"127.0.0.1",
|
||||
"port":1965,
|
||||
"cert":"cert.pem",
|
||||
"key":"key.rsa",
|
||||
"data":
|
||||
{
|
||||
"directory":"public",
|
||||
"index":"index.gmi",
|
||||
"listing":true
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ if (false === sem_acquire($semaphore, true))
|
||||
// Init config
|
||||
$config = json_decode(
|
||||
file_get_contents(
|
||||
__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config.json'
|
||||
__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'crawler.json'
|
||||
)
|
||||
);
|
||||
|
||||
|
249
src/server.php
Normal file
249
src/server.php
Normal file
@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
// Load dependencies
|
||||
require_once __DIR__ .
|
||||
DIRECTORY_SEPARATOR . '..'.
|
||||
DIRECTORY_SEPARATOR . 'vendor' .
|
||||
DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
|
||||
// Init required arguments
|
||||
if (empty($argv[1]))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('Configured hostname required as argument')
|
||||
);
|
||||
}
|
||||
|
||||
// Init server path
|
||||
define(
|
||||
'PULSAR_SERVER_DIRECTORY',
|
||||
str_starts_with($argv[1], DIRECTORY_SEPARATOR) ? $argv[1] :
|
||||
realpath(
|
||||
__DIR__ .
|
||||
DIRECTORY_SEPARATOR . '..' .
|
||||
DIRECTORY_SEPARATOR . $argv[1]
|
||||
) . DIRECTORY_SEPARATOR
|
||||
);
|
||||
|
||||
// Init server config
|
||||
if (!file_exists(PULSAR_SERVER_DIRECTORY . 'host.json'))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('Host not configured')
|
||||
);
|
||||
}
|
||||
|
||||
$config = json_decode(
|
||||
file_get_contents(
|
||||
PULSAR_SERVER_DIRECTORY . 'host.json'
|
||||
)
|
||||
);
|
||||
|
||||
// Init server certificate
|
||||
define(
|
||||
'PULSAR_SERVER_CERT',
|
||||
str_starts_with(
|
||||
$config->cert,
|
||||
DIRECTORY_SEPARATOR
|
||||
) ? $config->cert : PULSAR_SERVER_DIRECTORY . $config->cert
|
||||
);
|
||||
|
||||
if (!file_exists(PULSAR_SERVER_CERT))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('Certificate file not found')
|
||||
);
|
||||
}
|
||||
|
||||
// Init server key
|
||||
define(
|
||||
'PULSAR_SERVER_KEY',
|
||||
str_starts_with(
|
||||
$config->key,
|
||||
DIRECTORY_SEPARATOR
|
||||
) ? $config->key : PULSAR_SERVER_DIRECTORY . $config->key
|
||||
);
|
||||
|
||||
if (!file_exists(PULSAR_SERVER_KEY))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('Key file not found')
|
||||
);
|
||||
}
|
||||
|
||||
// Init data directory
|
||||
define(
|
||||
'PULSAR_SERVER_DATA_DIRECTORY',
|
||||
str_starts_with(
|
||||
$config->data->directory,
|
||||
DIRECTORY_SEPARATOR
|
||||
) ? $config->data->directory : PULSAR_SERVER_DIRECTORY . $config->data->directory
|
||||
);
|
||||
|
||||
if (!is_dir(PULSAR_SERVER_DATA_DIRECTORY))
|
||||
{
|
||||
throw new \Exception(
|
||||
_('Data directory not found')
|
||||
);
|
||||
}
|
||||
|
||||
// Init server
|
||||
$server = new \Yggverse\TitanII\Server();
|
||||
|
||||
$server->setCert(
|
||||
PULSAR_SERVER_CERT
|
||||
);
|
||||
|
||||
$server->setKey(
|
||||
PULSAR_SERVER_KEY
|
||||
);
|
||||
|
||||
$server->setHandler(
|
||||
function (\Yggverse\TitanII\Request $request): \Yggverse\TitanII\Response
|
||||
{
|
||||
global $config;
|
||||
|
||||
$response = new \Yggverse\TitanII\Response;
|
||||
|
||||
// Filter path request
|
||||
$path = trim(
|
||||
preg_replace(
|
||||
[
|
||||
'/\/[\.]+\//',
|
||||
'/\/[\/]+\//',
|
||||
],
|
||||
'/',
|
||||
$request->getPath()
|
||||
)
|
||||
);
|
||||
|
||||
if ($path != $request->getPath() || in_array($path, ['', null, false]))
|
||||
{
|
||||
$response->setCode(
|
||||
30
|
||||
);
|
||||
|
||||
$response->setMeta(
|
||||
sprintf(
|
||||
'gemini://%s%s/%s',
|
||||
$config->host,
|
||||
$config->port == 1965 ? null : ':' . $config->port,
|
||||
trim(
|
||||
(string) $path,
|
||||
'/'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Directory request
|
||||
if (is_dir(PULSAR_SERVER_DATA_DIRECTORY . $path))
|
||||
{
|
||||
// Try index
|
||||
if (file_exists(PULSAR_SERVER_DATA_DIRECTORY . $path . $config->data->index))
|
||||
{
|
||||
$response->setContent(
|
||||
file_get_contents(
|
||||
PULSAR_SERVER_DATA_DIRECTORY . $path . $config->data->index
|
||||
)
|
||||
);
|
||||
|
||||
$response->setCode(
|
||||
20
|
||||
);
|
||||
|
||||
$response->setMeta(
|
||||
'text/gemini; charset=utf-8'
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Build listing
|
||||
if ($config->data->listing)
|
||||
{
|
||||
$response->setCode(
|
||||
20
|
||||
);
|
||||
|
||||
$response->setMeta(
|
||||
'text/gemini; charset=utf-8'
|
||||
);
|
||||
|
||||
$links = [];
|
||||
|
||||
foreach ((array) scandir(PULSAR_SERVER_DATA_DIRECTORY . $path) as $link)
|
||||
{
|
||||
if (!str_starts_with($link, '.'))
|
||||
{
|
||||
if (is_dir(PULSAR_SERVER_DATA_DIRECTORY . $path . $link))
|
||||
{
|
||||
$links[] = sprintf(
|
||||
'=> %s/',
|
||||
$link
|
||||
);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$links[] = sprintf(
|
||||
'=> %s',
|
||||
$link
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response->setContent(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$links
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
// File request
|
||||
if (file_exists(PULSAR_SERVER_DATA_DIRECTORY . $path))
|
||||
{
|
||||
$response->setCode(
|
||||
20
|
||||
);
|
||||
|
||||
$response->setMeta(
|
||||
'text/gemini; charset=utf-8'
|
||||
);
|
||||
|
||||
$response->setContent(
|
||||
file_get_contents(
|
||||
PULSAR_SERVER_DATA_DIRECTORY . $path
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Noting found
|
||||
$response->setCode(
|
||||
51
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
);
|
||||
|
||||
// Start server
|
||||
echo sprintf(
|
||||
_('Server started on %s:%d'),
|
||||
$config->host,
|
||||
$config->port
|
||||
);
|
||||
|
||||
$server->start(
|
||||
$config->host,
|
||||
$config->port
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user