Individual settings for sessions

This commit is contained in:
Alexander Pankratov 2020-07-01 22:28:54 +03:00
parent be5d7e2749
commit 71c56b053c
8 changed files with 195 additions and 79 deletions

View File

@ -22,13 +22,22 @@ Fast, simple, async php telegram api server:
## Installation
### Docker:
* `git clone https://github.com/xtrime-ru/TelegramApiServer.git TelegramApiServer`
* `cd TelegramApiServer`
* Start container: `docker-compose up`
1. `git clone https://github.com/xtrime-ru/TelegramApiServer.git TelegramApiServer`
1. `cd TelegramApiServer`
1. Start container: `docker-compose up`
Folder will be linked inside container to store all necessary data: sessions, env, db.
### Manual:
1. Requirements:
* ssh / cli
* php 7.4
* composer
* git
* Mysql/MariaDB (optional)
* [MadelindeProto Requirements](https://docs.madelineproto.xyz/docs/REQUIREMENTS.html)
* [Amp Requirements](https://github.com/amphp/amp#requirements)
* XAMPP (for Windows)
1. `git clone https://github.com/xtrime-ru/TelegramApiServer.git TelegramApiServer`
1. `cd TelegramApiServer`
1. `composer install -o --no-dev`
@ -141,7 +150,7 @@ Fast, simple, async php telegram api server:
There are few options to upload and send media files:
- Custom method `sendMedia` supports upload from form:
```
```shell script
curl "http://127.0.0.1:9503/api/sendMedia?data[peer]=xtrime&data[message]=Hello" -g \
-F "file=@/Users/xtrime/Downloads/test.txt"
```
@ -150,7 +159,7 @@ There are few options to upload and send media files:
Method supports `application/x-www-form-urlencoded` and `multipart/form-data`.
2. Send result from `uploadMediaForm` to `messages.sendMedia` or `sendMedia`:
```
```shell script
curl --location --request POST 'http://127.0.0.1:9503/api/sendMedia' \
--header 'Content-Type: application/json' \
--data-raw '{
@ -180,7 +189,7 @@ There are few options to upload and send media files:
### Downloading files
```
```shell script
curl --location --request POST '127.0.0.1:9503/api/downloadToResponse' \
--header 'Content-Type: application/json' \
--data-raw '{
@ -226,17 +235,40 @@ Each session stored in `sessions/{$session}.madeline`. Nested folders supported.
* `--session=users/* --session=bots/*` to use all session files from `sessions/bots` and `sessions/users` folders.
### Different settings for sessions
Use `--env` argument to define the relative path to env file.
* Use `--env` argument to define the relative path to env file.
Example: ```php server.php --env=.env```, ```php server.php --env=sessions/.env.session```
This is helpful to define unique settings for different instances of TelegramApiServer.
You can start multiple instances of TelegramApiServer with different sessions on different ports with their own settings.
* Another way to manage settings - put %sessionName%.settings.json in sessions folder.
Example of `session.settings.json` to add proxy for the one session:
```json
{
"connection_settings": {
"all": {
"proxy": "\\SocksProxy",
"proxy_extra": {
"address": "127.0.0.1",
"port": 1234,
"username": "user",
"password": "pass"
}
}
}
}
```
Methods to work with settings files:
* `http://127.0.0.1:9503/system/saveSessionSettings?session=session&settings[app_info][app_id]=xxx&settings[app_info][app_hash]=xxx`
* `http://127.0.0.1:9503/system/unlinkSessionSettings?session=session`
* Provide settings as second argument when adding session: `http://127.0.0.1:9503/system/addSession?session=users/xtrime&settings[app_info][app_id]=xxx&&settings[app_info][app_hash]=xxx`
These settings will be saved into json file and will apply after the restart.
### Session management
**Examples:**
* Session list: `http://127.0.0.1:9503/system/getSessionList`
* Adding session: `http://127.0.0.1:9503/system/addSession?session=users/xtrime`
* [optional] Adding session with custom settings: `http://127.0.0.1:9503/system/addSession?session=users/xtrime&settings[app_info][app_id]=xxx&&settings[app_info][app_hash]=xxx`
* Removing session (session file will remain): `http://127.0.0.1:9503/system/removeSession?session=users/xtrime`
* Remove session file: `http://127.0.0.1:9503/system/unlinkSessionFile?session=users/xtrime`
Don`t forget to logout and call removeSession first!
@ -285,7 +317,9 @@ PHP websocket client example: [websocket-events.php](https://github.com/xtrime-r
## Contacts
* Telegram: [@xtrime](tg://resolve?domain=xtrime)
* Telegram:
* Author: [@xtrime](tg://resolve?domain=xtrime)
* [MadelineProto and Amp Support Groups](tg://resolve?domain=pwrtelegramgroup)
* Email: alexander(at)i-c-a.su
* Donations:
* BTC: `1BE1nitXgEAxg7A5tgec67ucNryQwusoiP`

View File

@ -11,7 +11,7 @@
"ext-mbstring": "*",
"amphp/http-server": "^2",
"amphp/http-server-router": "^1",
"amphp/websocket-server": "^2",
"amphp/websocket-server": "dev-master",
"amphp/websocket-client": "dev-master",
"vlucas/phpdotenv": "^4",
"danog/madelineproto":"dev-master",

126
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "877345d8ecbc0435bbe435a8c1a4abd6",
"content-hash": "2d1bc14b14e953631c976899556e7a92",
"packages": [
{
"name": "amphp/amp",
@ -151,20 +151,21 @@
},
{
"name": "amphp/cache",
"version": "v1.3.0",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/amphp/cache.git",
"reference": "14d9fa01a2518eda31b10a421660b41a55249736"
"reference": "e7bccc526fc2a555d59e6ee8380eeb39a95c0835"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/cache/zipball/14d9fa01a2518eda31b10a421660b41a55249736",
"reference": "14d9fa01a2518eda31b10a421660b41a55249736",
"url": "https://api.github.com/repos/amphp/cache/zipball/e7bccc526fc2a555d59e6ee8380eeb39a95c0835",
"reference": "e7bccc526fc2a555d59e6ee8380eeb39a95c0835",
"shasum": ""
},
"require": {
"amphp/amp": "^2",
"amphp/serialization": "^1",
"amphp/sync": "^1.2",
"php": ">=7.1"
},
@ -172,10 +173,11 @@
"amphp/file": "<0.2 || >=2"
},
"require-dev": {
"amphp/file": "^1.0",
"amphp/file": "^1",
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1",
"phpunit/phpunit": "^6 | ^7 | ^8"
"amphp/phpunit-util": "^1.1",
"phpunit/phpunit": "^6 | ^7 | ^8 | ^9",
"vimeo/psalm": "^3.11@dev"
},
"type": "library",
"autoload": {
@ -199,20 +201,20 @@
],
"description": "A promise-aware caching API for Amp.",
"homepage": "https://github.com/amphp/cache",
"time": "2019-11-29T18:47:04+00:00"
"time": "2020-04-19T16:10:08+00:00"
},
{
"name": "amphp/dns",
"version": "v1.2.1",
"version": "v1.2.2",
"source": {
"type": "git",
"url": "https://github.com/amphp/dns.git",
"reference": "9d7e57f37d21bfed8ff2e78db52b99d45ce0c215"
"reference": "8cf2ccc4fa5a97f15b0b11087b22d2b544e45ab2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/dns/zipball/9d7e57f37d21bfed8ff2e78db52b99d45ce0c215",
"reference": "9d7e57f37d21bfed8ff2e78db52b99d45ce0c215",
"url": "https://api.github.com/repos/amphp/dns/zipball/8cf2ccc4fa5a97f15b0b11087b22d2b544e45ab2",
"reference": "8cf2ccc4fa5a97f15b0b11087b22d2b544e45ab2",
"shasum": ""
},
"require": {
@ -229,7 +231,7 @@
"require-dev": {
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1",
"phpunit/phpunit": "^6"
"phpunit/phpunit": "^6 || ^7 || ^8 || ^9"
},
"type": "library",
"autoload": {
@ -276,7 +278,7 @@
"dns",
"resolve"
],
"time": "2019-11-28T20:10:22+00:00"
"time": "2020-06-19T20:28:16+00:00"
},
{
"name": "amphp/file",
@ -611,16 +613,16 @@
},
{
"name": "amphp/http-server",
"version": "v2.0.1",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/amphp/http-server.git",
"reference": "9c38d7be6e115ce0ced9f78d2375c28de5871418"
"reference": "30063e245559095ff99a320b88a8a88ff719cc6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/http-server/zipball/9c38d7be6e115ce0ced9f78d2375c28de5871418",
"reference": "9c38d7be6e115ce0ced9f78d2375c28de5871418",
"url": "https://api.github.com/repos/amphp/http-server/zipball/30063e245559095ff99a320b88a8a88ff719cc6e",
"reference": "30063e245559095ff99a320b88a8a88ff719cc6e",
"shasum": ""
},
"require": {
@ -649,6 +651,11 @@
"ext-zlib": "Allows GZip compression of response bodies"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Amp\\Http\\Server\\": "src"
@ -689,7 +696,7 @@
"non-blocking",
"server"
],
"time": "2020-03-10T20:37:39+00:00"
"time": "2020-06-20T14:40:33+00:00"
},
{
"name": "amphp/http-server-form-parser",
@ -1165,16 +1172,16 @@
},
{
"name": "amphp/socket",
"version": "v1.1.1",
"version": "v1.1.3",
"source": {
"type": "git",
"url": "https://github.com/amphp/socket.git",
"reference": "020b65271596f84f4b3127d2eab81ad2790f9fb6"
"reference": "b9064b98742d12f8f438eaf73369bdd7d8446331"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/socket/zipball/020b65271596f84f4b3127d2eab81ad2790f9fb6",
"reference": "020b65271596f84f4b3127d2eab81ad2790f9fb6",
"url": "https://api.github.com/repos/amphp/socket/zipball/b9064b98742d12f8f438eaf73369bdd7d8446331",
"reference": "b9064b98742d12f8f438eaf73369bdd7d8446331",
"shasum": ""
},
"require": {
@ -1189,7 +1196,8 @@
"require-dev": {
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1",
"phpunit/phpunit": "^6"
"phpunit/phpunit": "^6 || ^7 || ^8",
"vimeo/psalm": "^3.9@dev"
},
"type": "library",
"extra": {
@ -1235,7 +1243,7 @@
"tcp",
"tls"
],
"time": "2020-02-27T21:29:37+00:00"
"time": "2020-06-25T18:55:28+00:00"
},
{
"name": "amphp/sql",
@ -1386,16 +1394,16 @@
},
{
"name": "amphp/websocket",
"version": "v1.0.0-rc2",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/amphp/websocket.git",
"reference": "5fbeb1ea821e50af13fc682570f26e71afd23eca"
"reference": "ac4e9c53b35cd19351dc99c788f563f36fec9c6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/websocket/zipball/5fbeb1ea821e50af13fc682570f26e71afd23eca",
"reference": "5fbeb1ea821e50af13fc682570f26e71afd23eca",
"url": "https://api.github.com/repos/amphp/websocket/zipball/ac4e9c53b35cd19351dc99c788f563f36fec9c6e",
"reference": "ac4e9c53b35cd19351dc99c788f563f36fec9c6e",
"shasum": ""
},
"require": {
@ -1408,7 +1416,8 @@
"require-dev": {
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1.1.2",
"phpunit/phpunit": "^8 || ^7"
"phpunit/phpunit": "^8 || ^7",
"vimeo/psalm": "^3.11@dev"
},
"suggest": {
"ext-zlib": "Required for compression"
@ -1450,7 +1459,7 @@
"non-blocking",
"websocket"
],
"time": "2020-04-18T14:05:23+00:00"
"time": "2020-06-25T21:14:23+00:00"
},
{
"name": "amphp/websocket-client",
@ -1458,12 +1467,12 @@
"source": {
"type": "git",
"url": "https://github.com/amphp/websocket-client.git",
"reference": "619e2b550ed907037886f84d0453d27c4e700c21"
"reference": "a867e63773f83e6cb573cd9fede7bfd20a786d98"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/websocket-client/zipball/619e2b550ed907037886f84d0453d27c4e700c21",
"reference": "619e2b550ed907037886f84d0453d27c4e700c21",
"url": "https://api.github.com/repos/amphp/websocket-client/zipball/a867e63773f83e6cb573cd9fede7bfd20a786d98",
"reference": "a867e63773f83e6cb573cd9fede7bfd20a786d98",
"shasum": ""
},
"require": {
@ -1480,9 +1489,10 @@
"amphp/http-server": "^2",
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1.1",
"amphp/websocket-server": "^2-rc3",
"amphp/websocket-server": "dev-master as 2.0-rc4",
"phpunit/phpunit": "^8 || ^7",
"psr/log": "^1"
"psr/log": "^1",
"vimeo/psalm": "^3.11@dev"
},
"type": "library",
"autoload": {
@ -1521,20 +1531,20 @@
"non-blocking",
"websocket"
],
"time": "2020-04-23T18:41:25+00:00"
"time": "2020-06-25T21:45:12+00:00"
},
{
"name": "amphp/websocket-server",
"version": "v2.0.0-rc3",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/amphp/websocket-server.git",
"reference": "353b96b69c44ecfbde98726958f2137530c36f6b"
"reference": "ebccbdb792568039105db749f0e2ec3ac6182cf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/websocket-server/zipball/353b96b69c44ecfbde98726958f2137530c36f6b",
"reference": "353b96b69c44ecfbde98726958f2137530c36f6b",
"url": "https://api.github.com/repos/amphp/websocket-server/zipball/ebccbdb792568039105db749f0e2ec3ac6182cf8",
"reference": "ebccbdb792568039105db749f0e2ec3ac6182cf8",
"shasum": ""
},
"require": {
@ -1554,7 +1564,8 @@
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1.3",
"league/climate": "^3",
"phpunit/phpunit": "^9 || ^8 || ^7"
"phpunit/phpunit": "^9 || ^8 || ^7",
"vimeo/psalm": "^3.11@dev"
},
"suggest": {
"ext-zlib": "Required for compression"
@ -1593,7 +1604,7 @@
"server",
"websocket"
],
"time": "2020-04-22T18:20:00+00:00"
"time": "2020-07-01T16:35:04+00:00"
},
{
"name": "amphp/windows-registry",
@ -2972,16 +2983,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.17.0",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9"
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
"reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
"shasum": ""
},
"require": {
@ -2994,6 +3005,10 @@
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@ -3040,7 +3055,7 @@
"type": "tidelift"
}
],
"time": "2020-05-12T16:14:59+00:00"
"time": "2020-06-06T08:46:27+00:00"
},
{
"name": "tivie/htaccess-parser",
@ -3169,12 +3184,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "499fb201e495ef0064da064f520c845d3638fe24"
"reference": "6d2e5ab854782830911ddd33b7d4649b9f18c10f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/499fb201e495ef0064da064f520c845d3638fe24",
"reference": "499fb201e495ef0064da064f520c845d3638fe24",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/6d2e5ab854782830911ddd33b7d4649b9f18c10f",
"reference": "6d2e5ab854782830911ddd33b7d4649b9f18c10f",
"shasum": ""
},
"conflict": {
@ -3218,8 +3233,8 @@
"doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1",
"dolibarr/dolibarr": "<11.0.4",
"dompdf/dompdf": ">=0.6,<0.6.2",
"drupal/core": ">=7,<7.70|>=8,<8.7.14|>=8.8,<8.8.6",
"drupal/drupal": ">=7,<7.70|>=8,<8.7.14|>=8.8,<8.8.6",
"drupal/core": ">=7,<7.72|>=8,<8.8.8|>=8.9,<8.9.1|>=9,<9.0.1",
"drupal/drupal": ">=7,<7.72|>=8,<8.8.8|>=8.9,<8.9.1|>=9,<9.0.1",
"endroid/qr-code-bundle": "<3.4.2",
"enshrined/svg-sanitize": "<0.13.1",
"erusev/parsedown": "<1.7.2",
@ -3446,12 +3461,13 @@
"type": "tidelift"
}
],
"time": "2020-06-17T06:37:54+00:00"
"time": "2020-06-19T13:23:43+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
"amphp/websocket-server": 20,
"amphp/websocket-client": 20,
"danog/madelineproto": 20,
"roave/security-advisories": 20

View File

@ -61,7 +61,14 @@ class Client
}
$file = Files::getSessionFile($session);
Files::checkOrCreateSessionFolder($file);
$settings = array_replace_recursive((array) Config::getInstance()->get('telegram'), $settings);
if ($settings) {
Files::saveSessionSettings($session, $settings);
}
$settings = array_replace_recursive(
(array) Config::getInstance()->get('telegram'),
Files::getSessionSettings($session),
);
$instance = new MadelineProto\API($file, $settings);
if (self::isSessionLoggedIn($instance)) {
$instance->unsetEventHandler();

View File

@ -219,7 +219,7 @@ abstract class AbstractApiController
return $this->page['response'];
}
if (!is_array($this->page['response'])) {
if (!is_array($this->page['response']) && !is_scalar($this->page['response'])) {
$this->page['response'] = null;
}

View File

@ -5,8 +5,9 @@ namespace TelegramApiServer;
class Files
{
public static string $sessionExtension = '.madeline';
public static string $sessionFolder = 'sessions';
public const SESSION_EXTENSION = '.madeline';
public const SETTINGS_EXTENSION = '.settings.json';
private const SESSION_FOLDER = 'sessions';
public static function checkOrCreateSessionFolder(string $session): void
{
@ -26,7 +27,7 @@ class Files
}
preg_match(
'~' . Files::$sessionFolder . "/(?'sessionName'.*?)" . Files::$sessionExtension . '$~',
'~' . static::SESSION_FOLDER . "/(?'sessionName'.*?)" . static::SESSION_EXTENSION . '$~',
$sessionFile,
$matches
);
@ -37,19 +38,53 @@ class Files
/**
* @param string|null $session
*
* @param string $extension
*
* @return string|null
*/
public static function getSessionFile(?string $session): ?string
public static function getSessionFile(?string $session, string $extension = self::SESSION_EXTENSION): ?string
{
if (!$session) {
return null;
}
$session = trim(trim($session), '/');
$session = Files::$sessionFolder . '/' . $session . Files::$sessionExtension;
$session = static::SESSION_FOLDER . '/' . $session . $extension;
$session = str_replace('//', '/', $session);
return $session;
}
public static function getSessionSettings(string $session): array
{
$settingsFile = static::getSessionFile($session, static::SETTINGS_EXTENSION);
$settings = [];
if (file_exists($settingsFile)) {
$settings = json_decode(
file_get_contents($settingsFile),
true,
10,
JSON_THROW_ON_ERROR
);
}
return $settings;
}
public static function saveSessionSettings(string $session, array $settings = []): void
{
$settingsFile = static::getSessionFile($session, static::SETTINGS_EXTENSION);
file_put_contents(
$settingsFile,
json_encode(
$settings,
JSON_THROW_ON_ERROR |
JSON_INVALID_UTF8_SUBSTITUTE |
JSON_UNESCAPED_SLASHES |
JSON_UNESCAPED_UNICODE |
JSON_PRETTY_PRINT
)
);
}
public static function globRecursive($pattern, $flags = 0): array
{
$files = glob($pattern, $flags) ?: [];

View File

@ -90,12 +90,36 @@ class SystemApiExtensions
public function unlinkSessionFile($session): Promise
{
return call(static function() use($session) {
return call(function() use($session) {
$file = Files::getSessionFile($session);
if (is_file($file)) {
yield \Amp\File\unlink($file);
yield \Amp\File\unlink($file . '.lock');
}
yield from $this->unlinkSessionSettings($session);
return 'ok';
});
}
public function saveSessionSettings(string $session, array $settings = [])
{
Files::saveSessionSettings($session, $settings);
return 'ok';
}
public function unlinkSessionSettings($session): Promise
{
return call(static function() use($session) {
$settings = Files::getSessionFile($session, Files::SETTINGS_EXTENSION);
if (is_file($settings)) {
yield \Amp\File\unlink($settings);
}
return 'ok';
});
}

View File

@ -8,9 +8,9 @@ class SessionsMigration
{
public static function move($rootDir = ROOT_DIR)
{
foreach (glob("$rootDir/*" . Files::$sessionExtension) as $oldFile) {
foreach (glob("$rootDir/*" . Files::SESSION_EXTENSION) as $oldFile) {
preg_match(
'~^' . "{$rootDir}(?'session'.*)" . preg_quote(Files::$sessionExtension, '\\') . '$~',
'~^' . "{$rootDir}(?'session'.*)" . preg_quote(Files::SESSION_EXTENSION, '\\') . '$~',
$oldFile,
$matches
);