Skip to content

Commit

Permalink
Merge pull request #29 from KIMB-technologies/im-export
Browse files Browse the repository at this point in the history
Im- & Export Feature
  • Loading branch information
kimbtech authored Nov 30, 2023
2 parents bbadcaf + 7108562 commit afb25b9
Show file tree
Hide file tree
Showing 15 changed files with 888 additions and 30 deletions.
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ This redirect is possible by manipulating the DNS queries.
- Nobody should host a public DNS resolver resolving wrong IPs. Some type of access control is recommended.

## Setup
See [Setup.md](./Setup.md)!
See [Setup.md](./Setup.md) including hints regarding updates, backups (i.e., Im- & Export), and troubleshooting.
22 changes: 20 additions & 2 deletions Setup.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Setup

Radio-API can be run using Docker (recommend way) [↓](#setup-using-docker).
It is also possible to run Radio-API on a simple webserver with PHP [↓](#manual-setup).
- Radio-API can be run using Docker (recommend way) [↓](#setup-using-docker).
- It is also possible to run Radio-API on a simple webserver with PHP [↓](#manual-setup).
- For backups and migrations see the Im- & Export feature [↓](#im---export).

## Setup using Docker
The entire API is bundled in a [Docker Image](https://hub.docker.com/r/kimbtechnologies/radio_api).
Expand Down Expand Up @@ -73,6 +74,7 @@ The image of [Radio DNS](https://hub.docker.com/r/kimbtechnologies/radio_dns) is
- `CONF_STREAM_JSON` Url to a JSON list of streams or `false` to disable (see [Own Streams](#own-streams)).
- `CONF_LOG_DIR` (optional) Change the folder where log files are written to (defaults to `./data/`).
- `CONF_CACHE_DIR` (optional) Change the folder used by the file based cache (defaults to `./data/cache/`).
- `CONF_IM_EXPORT_TOKEN` (optional) Define a token for use with the Im- & Export web interface *Im- & Export* [↓](#im---export).
- Make sure, that *Radio-API* is available at port `80` for requests with the hostname `*.wifiradiofrontier.com` and `CONF_DOMAIN`.
- Block HTTP access to `./data/` (and `./classes/`) for security reasons (might be omitted in a local network installation).
- Rewrite requests to PHP:
Expand All @@ -90,6 +92,8 @@ The image of [Radio DNS](https://hub.docker.com/r/kimbtechnologies/radio_dns) is
> This is for manual installs, Docker users must make sure to store the redis volume or to run the cron job.
> Then Radio-API can be restarted using a newer version of the Docker Image.
> Generally, the *Im- & Export* [↓](#im---export) interface may be used for backups and restores after updates!
- Run the `./utils/backup-restore.php` script to export all relevant data from the cache.
This will result in two files, which may be stored in `./data` or somewhere else.
- Create a copy of files in the folder `./data` (`./data/cache` can be deleted).
Expand Down Expand Up @@ -136,6 +140,20 @@ location @nofile {
2. `http://radio.example.com/setupapp/iden/asp/BrowseXML/loginXML.asp?gofile=&mac=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&dlang=eng&fver=4&ven=iden00` (returns `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ListOfItems> ... </ListOfItems>`)
3. Get the GUI-Code from the preceding response and try to used it to access the GUI at `http://radio.example.com/gui/`

### Im- & Export
There is an Im- & Export web interface at `./gui/im-export.php`.
To activate and use it, a token must be set in the configuration as `CONF_IM_EXPORT_TOKEN`.
This token needs to have at least 15 chars and must consist only of `[A-Za-z0-9]`.

Using the token a JSON file containing all Radio-API data can be created and downloaded.
This files contains for each radio the list of radio stations, podcasts, stations last listened to via RadioBrowser, and podcast episodes already listened to.
It also contains the list for assigning GUI-Codes to radios and the configuration file used in non-Docker mode.

Such an export JSON file can be imported to Radio-API afterwards.
Thereby, all data can be replaces, appended or only the data for one radio might be overwritten.
(The configuration file used in non-Docker mode will not be imported.)
More information is available at the Im- & Export web interface.

### Nginx Load Balancer
An example file to use *Radio-API* behind a nginx load balancer as reverse proxy.

Expand Down
1 change: 1 addition & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
- CONF_CACHE_EXPIRE=1200
- CONF_REDIS_HOST=redis
- CONF_STREAM_JSON=false #http://192.168.0.10:8081/list.json
- CONF_IM_EXPORT_TOKEN=LP75Djdj195DL8SZnfY3
depends_on:
- redis
redis:
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ services:
# - CONF_REDIS_PASS= # default no auth
- CONF_STREAM_JSON=false # to disable or an url where to fetch list of own streams, e.g., http://stream.example.com/list.json
# -CONF_LOG_DIR= # set a custom directory for log files (defaults to ./data/)
# -CONF_IM_EXPORT_TOKEN= # define a token for use with the im-, export web interface at ./gui/im-export.php
depends_on:
- redis
redis:
Expand Down
12 changes: 11 additions & 1 deletion php/classes/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
!empty($ENV['CONF_CACHE_DIR']) && realpath(substr($ENV['CONF_LOG_DIR'], 0, strrpos($ENV['CONF_LOG_DIR'], '/', -2))) ?
$ENV['CONF_CACHE_DIR'] : __DIR__ . '/../data/cache'
);
define(
'ENV_IM_EXPORT_TOKEN',
!empty($ENV['CONF_IM_EXPORT_TOKEN']) && Helper::checkFilename($ENV['CONF_IM_EXPORT_TOKEN']) && strlen($ENV['CONF_IM_EXPORT_TOKEN']) > 15 ?
$ENV['CONF_IM_EXPORT_TOKEN'] : false
);

// IP on reverse proxy setup
if( !empty($_SERVER['HTTP_X_REAL_IP']) ){
Expand All @@ -69,7 +74,7 @@ class Config {
/**
* The system's version.
*/
const VERSION = 'v2.7.1';
const VERSION = 'v2.7.2-dev';

/**
* The real domain which should be used.
Expand Down Expand Up @@ -101,6 +106,11 @@ class Config {
*/
const CACHE_DIR = ENV_CACHE_DIR;

/**
* Im- & Export via web GUI (at ./gui/im-export.php)
*/
const IM_EXPORT_TOKEN = ENV_IM_EXPORT_TOKEN;

/**
* Store redis cache for ALLOWED_DOMAINS
*/
Expand Down
50 changes: 28 additions & 22 deletions php/classes/Id.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,32 @@ class Id {
//code => gui access
//data => [mac, code]

public static function isIdInteger(int $i) : bool {
return $i > 0 && $i < 10_000;
}

public static function getTableData() : array {
$table = null;
if( is_file( __DIR__ . '/../data/table.json' ) ){ // load table form disk?
$table = json_decode(file_get_contents( __DIR__ . '/../data/table.json' ), true);

if(is_null($table)){ // on json error, move file and create new
rename(__DIR__ . '/../data/table.json', __DIR__ . '/../data/table.error.json');
}
}
if ( is_null($table) ) { // init empty table
$table = array(
'macs' => array(), // mac => id
'ids' => array(), // id => [ mac, code ]
'codes' => array() // code => id
);
// save init table
file_put_contents( __DIR__ . '/../data/table.json', json_encode($table, JSON_PRETTY_PRINT), LOCK_EX);
}

return $table;
}

public function __construct($val, int $type = self::MAC){
// load redis
$redis = new Cache('table.json');
Expand Down Expand Up @@ -77,7 +103,6 @@ public function __construct($val, int $type = self::MAC){
}
}


public function getId() : int {
return $this->id;
}
Expand All @@ -91,23 +116,8 @@ public function getCode() : string {
}

private function loadFileIntoRedis(Cache $redis) : void {
$table = null;
if( is_file( __DIR__ . '/../data/table.json' ) ){ // load table form disk?
$table = json_decode(file_get_contents( __DIR__ . '/../data/table.json' ), true);
$table = self::getTableData();

if(is_null($table)){ // on json error, move file and create new
rename(__DIR__ . '/../data/table.json', __DIR__ . '/../data/table.error.json');
}
}
if ( is_null($table) ) { // init empty table
$table = array(
'macs' => array(), // mac => id
'ids' => array(), // id => [ mac, code ]
'codes' => array() // code => id
);
// save init table
file_put_contents( __DIR__ . '/../data/table.json', json_encode($table, JSON_PRETTY_PRINT), LOCK_EX);
}
// set also in redis
$redis->arraySet('macs', $table['macs']);
$redis->arraySet('ids', $table['ids']);
Expand All @@ -116,11 +126,7 @@ private function loadFileIntoRedis(Cache $redis) : void {

private function generateNewId( string $val, Cache $redis ) : int {
// Load file, as file it the primary storage
$table = json_decode(file_get_contents( __DIR__ . '/../data/table.json' ), true);
if(is_null($table)){ // error in file, fix this!
$this->loadFileIntoRedis($redis);
$table = json_decode(file_get_contents( __DIR__ . '/../data/table.json' ), true);
}
$table = self::getTableData();

// new id
$id = count( $table['ids'] ) + 1;
Expand Down
Loading

0 comments on commit afb25b9

Please sign in to comment.