Compare commits
12 Commits
f84c9dcbb4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 45f8072679 | |||
| 984438729e | |||
| 1e8bfc2ac0 | |||
| 1148a65355 | |||
| acb1f63bae | |||
| 6565be735d | |||
| 1de83a858e | |||
| 7d7360fc16 | |||
| 8d6f2df942 | |||
| 34f400b421 | |||
| f98b67292b | |||
| a00d409aba |
24
README.md
24
README.md
@@ -1,15 +1,17 @@
|
|||||||
# urupam
|
# urupam
|
||||||
|
|
||||||
`urupam` is a small URL shortener written in Perl with Mojolicious, using Redis for storage.
|
`urupam` is a lightweight URL shortener built with Perl and Mojolicious, and backed by Redis.
|
||||||
|
|
||||||
## Requirements
|
## Basic requirements
|
||||||
|
|
||||||
- Perl 5.42.0
|
- Perl 5.42.0
|
||||||
- Mojolicious 9.42
|
- Carton (handles perl deps)
|
||||||
|
- Redis
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- [ ] connect to redis
|
- [x] create installation script
|
||||||
|
- [x] connect to redis + setter and getter operations
|
||||||
- [ ] create dummy API endpoints
|
- [ ] create dummy API endpoints
|
||||||
- [ ] decide how to handle short url generation
|
- [ ] decide how to handle short url generation
|
||||||
- [ ] avoid collisions in short urls
|
- [ ] avoid collisions in short urls
|
||||||
@@ -17,7 +19,6 @@
|
|||||||
- [ ] validate URLs and handle errors
|
- [ ] validate URLs and handle errors
|
||||||
- [ ] create a simple and clean UI
|
- [ ] create a simple and clean UI
|
||||||
- [ ] manage/delete short urls
|
- [ ] manage/delete short urls
|
||||||
- [ ] create `Makefile.PL`
|
|
||||||
- [ ] create systemd service
|
- [ ] create systemd service
|
||||||
- [ ] create `Dockerfile`
|
- [ ] create `Dockerfile`
|
||||||
- [ ] create `docker-compose.yml`
|
- [ ] create `docker-compose.yml`
|
||||||
@@ -25,8 +26,6 @@
|
|||||||
|
|
||||||
## How to run
|
## How to run
|
||||||
|
|
||||||
### Dev
|
|
||||||
|
|
||||||
To run the application in development, you'll first need a Redis server. The easiest way is to start a local Redis instance using Docker:
|
To run the application in development, you'll first need a Redis server. The easiest way is to start a local Redis instance using Docker:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -47,18 +46,15 @@ carton exec morbo bin/urupam
|
|||||||
|
|
||||||
Open [http://127.0.0.1:3000](http://127.0.0.1:3000) in your browser.
|
Open [http://127.0.0.1:3000](http://127.0.0.1:3000) in your browser.
|
||||||
|
|
||||||
### Install
|
## Installation
|
||||||
|
|
||||||
Use the provided `Makefile.pl`:
|
Run the installation script:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
perl Makefile.PL
|
scripts/install.sh
|
||||||
make
|
|
||||||
make test
|
|
||||||
sudo make install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Activate/enable the systemd service:
|
Enable and start the systemd service:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo systemctl enable --now urupam
|
sudo systemctl enable --now urupam
|
||||||
|
|||||||
1
cpanfile
1
cpanfile
@@ -1,2 +1,3 @@
|
|||||||
requires 'Mojolicious', '>= 9.0';
|
requires 'Mojolicious', '>= 9.0';
|
||||||
requires 'Moose';
|
requires 'Moose';
|
||||||
|
requires 'Mojo::Redis2';
|
||||||
|
|||||||
@@ -141,6 +141,20 @@ DISTRIBUTIONS
|
|||||||
perl 5.006
|
perl 5.006
|
||||||
strict 0
|
strict 0
|
||||||
warnings 0
|
warnings 0
|
||||||
|
Mojo-Redis2-0.32
|
||||||
|
pathname: D/DB/DBOOK/Mojo-Redis2-0.32.tar.gz
|
||||||
|
provides:
|
||||||
|
Mojo::Redis2 0.32
|
||||||
|
Mojo::Redis2::Backend undef
|
||||||
|
Mojo::Redis2::Bulk undef
|
||||||
|
Mojo::Redis2::Client undef
|
||||||
|
Mojo::Redis2::Cursor undef
|
||||||
|
Mojo::Redis2::Server undef
|
||||||
|
Mojo::Redis2::Transaction 0.01
|
||||||
|
requirements:
|
||||||
|
ExtUtils::MakeMaker 0
|
||||||
|
Mojolicious 7.50
|
||||||
|
Protocol::Redis 1.0
|
||||||
Mojolicious-9.42
|
Mojolicious-9.42
|
||||||
pathname: S/SR/SRI/Mojolicious-9.42.tar.gz
|
pathname: S/SR/SRI/Mojolicious-9.42.tar.gz
|
||||||
provides:
|
provides:
|
||||||
@@ -787,6 +801,16 @@ DISTRIBUTIONS
|
|||||||
Scalar::Util 1.18
|
Scalar::Util 1.18
|
||||||
XSLoader 0.22
|
XSLoader 0.22
|
||||||
parent 0
|
parent 0
|
||||||
|
Protocol-Redis-1.0021
|
||||||
|
pathname: U/UN/UNDEF/Protocol-Redis-1.0021.tar.gz
|
||||||
|
provides:
|
||||||
|
Protocol::Redis 1.0021
|
||||||
|
Protocol::Redis::Test undef
|
||||||
|
requirements:
|
||||||
|
Carp 0
|
||||||
|
ExtUtils::MakeMaker 0
|
||||||
|
Test::More 0.94
|
||||||
|
perl 5.008001
|
||||||
Sub-Exporter-0.991
|
Sub-Exporter-0.991
|
||||||
pathname: R/RJ/RJBS/Sub-Exporter-0.991.tar.gz
|
pathname: R/RJ/RJBS/Sub-Exporter-0.991.tar.gz
|
||||||
provides:
|
provides:
|
||||||
|
|||||||
@@ -1,19 +1,50 @@
|
|||||||
package Urupam::App;
|
package Urupam::App;
|
||||||
|
|
||||||
use Mojo::Base 'Mojolicious';
|
use Mojo::Base 'Mojolicious';
|
||||||
use Moose;
|
use Urupam::DB;
|
||||||
|
|
||||||
sub startup {
|
sub startup {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
$self->helper(
|
||||||
|
db => sub {
|
||||||
|
my $c = shift;
|
||||||
|
$c->stash->{db} ||= Urupam::DB->new;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
my $r = $self->routes;
|
my $r = $self->routes;
|
||||||
$r->get('/')->to(
|
$r->get('/')->to(
|
||||||
cb => sub {
|
cb => sub {
|
||||||
my $c = shift;
|
my $c = shift;
|
||||||
$c->render( text => 'Hello from urupam!' );
|
my $tx = $c->render_later->tx;
|
||||||
|
my $db = $c->db;
|
||||||
|
|
||||||
|
$db->set( 'test_key' => '123soleil' )->then(
|
||||||
|
sub {
|
||||||
|
$c->app->log->info('Value set: test_key => 123soleil');
|
||||||
|
return $db->get('test_key');
|
||||||
|
}
|
||||||
|
)->then(
|
||||||
|
sub {
|
||||||
|
my $value = shift;
|
||||||
|
$c->app->log->info("Value retrieved: $value");
|
||||||
|
$c->render( json => { status => 'ok', value => $value } );
|
||||||
|
undef $tx;
|
||||||
|
}
|
||||||
|
)->catch(
|
||||||
|
sub {
|
||||||
|
my $err = shift;
|
||||||
|
$c->app->log->error("DB error: $err");
|
||||||
|
$c->render(
|
||||||
|
json => { status => 'error', message => "$err" },
|
||||||
|
status => 500
|
||||||
|
);
|
||||||
|
undef $tx;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|||||||
36
lib/Urupam/DB.pm
Normal file
36
lib/Urupam/DB.pm
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package Urupam::DB;
|
||||||
|
|
||||||
|
use Mojo::Base -base;
|
||||||
|
use Mojo::Promise;
|
||||||
|
use Mojo::Redis2;
|
||||||
|
|
||||||
|
has redis => sub {
|
||||||
|
Mojo::Redis2->new( url => $ENV{REDIS_URL} || 'redis://localhost:6379' );
|
||||||
|
};
|
||||||
|
|
||||||
|
sub get {
|
||||||
|
my ( $self, $key ) = @_;
|
||||||
|
my $promise = Mojo::Promise->new;
|
||||||
|
$self->redis->get(
|
||||||
|
$key => sub {
|
||||||
|
my ( $redis, $err, $value ) = @_;
|
||||||
|
$err ? $promise->reject($err) : $promise->resolve($value);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return $promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set {
|
||||||
|
my ( $self, $key, $value ) = @_;
|
||||||
|
my $promise = Mojo::Promise->new;
|
||||||
|
$self->redis->set(
|
||||||
|
$key => $value,
|
||||||
|
sub {
|
||||||
|
my ( $redis, $err, $result ) = @_;
|
||||||
|
$err ? $promise->reject($err) : $promise->resolve($result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return $promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
62
scripts/install.sh
Normal file
62
scripts/install.sh
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# simple helper to deploy urupam
|
||||||
|
|
||||||
|
# fail-fast
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# get root or get out
|
||||||
|
if [[ $(id -u) != 0 ]]; then
|
||||||
|
echo "Please use sudo or run as root."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check carton
|
||||||
|
if ! command -v carton &>/dev/null; then
|
||||||
|
echo "carton not found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check redis
|
||||||
|
if ! ss -ltn | grep -q ":6379"; then
|
||||||
|
echo "Redis isn't running, check README."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create urupam user
|
||||||
|
groupadd urupam
|
||||||
|
useradd -s /bin/bash -g urupam -d /opt/urupam urupam
|
||||||
|
|
||||||
|
# deploy code
|
||||||
|
cp -r bin lib cpan* /opt/urupam
|
||||||
|
chown -R urupam:urupam /opt/urupam
|
||||||
|
|
||||||
|
# install dependencies
|
||||||
|
su - urupam -c "cd /opt/urupam && carton install ."
|
||||||
|
|
||||||
|
# create systemd service
|
||||||
|
cat >>/etc/systemd/system/urupam.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Urupam
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=urupam
|
||||||
|
Group=urupam
|
||||||
|
WorkingDirectory=/opt/urupam
|
||||||
|
ExecStart=carton exec -- bin/urupam
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
# install documentation
|
||||||
|
mkdir -p /usr/share/doc/urupam
|
||||||
|
cp README.md LICENSE /usr/share/doc/urupam
|
||||||
|
|
||||||
|
# enable and start service
|
||||||
|
systemctl enable --now urupam
|
||||||
|
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user