Clean up
This commit is contained in:
parent
17e85d361c
commit
e147fe3695
7
.gitignore
vendored
7
.gitignore
vendored
@ -124,3 +124,10 @@ coverage
|
|||||||
tempConv
|
tempConv
|
||||||
extracted.json
|
extracted.json
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
|
||||||
|
src/danog/MadelineProto/VoIP.php
|
||||||
|
src/danog/MadelineProto/VoIP/AckHandler.php
|
||||||
|
src/danog/MadelineProto/VoIP/MessageHandler.php
|
||||||
|
src/danog/MadelineProto/OpusStream.php
|
||||||
|
|
||||||
|
ponyScripts
|
||||||
|
356
.phan/config.php
Normal file
356
.phan/config.php
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Phan\Issue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This configuration file was automatically generated by 'phan --init --init-level=3'
|
||||||
|
*
|
||||||
|
* TODOs (added by 'phan --init'):
|
||||||
|
*
|
||||||
|
* - Go through this file and verify that there are no missing/unnecessary files/directories.
|
||||||
|
* (E.g. this only includes direct composer dependencies - You may have to manually add indirect composer dependencies to 'directory_list')
|
||||||
|
* - Look at 'plugins' and add or remove plugins if appropriate (see https://github.com/phan/phan/tree/master/.phan/plugins#plugins)
|
||||||
|
* - Add global suppressions for pre-existing issues to suppress_issue_types (https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base)
|
||||||
|
*
|
||||||
|
* This configuration will be read and overlaid on top of the
|
||||||
|
* default configuration. Command line arguments will be applied
|
||||||
|
* after this file is read.
|
||||||
|
*
|
||||||
|
* @see src/Phan/Config.php
|
||||||
|
* See Config for all configurable options.
|
||||||
|
*
|
||||||
|
* A Note About Paths
|
||||||
|
* ==================
|
||||||
|
*
|
||||||
|
* Files referenced from this file should be defined as
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* Config::projectPath('relative_path/to/file')
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* where the relative path is relative to the root of the
|
||||||
|
* project which is defined as either the working directory
|
||||||
|
* of the phan executable or a path passed in via the CLI
|
||||||
|
* '-d' flag.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
|
||||||
|
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`, `null`.
|
||||||
|
// If this is set to `null`,
|
||||||
|
// then Phan assumes the PHP version which is closest to the minor version
|
||||||
|
// of the php executable used to execute Phan.
|
||||||
|
//
|
||||||
|
// Note that the **only** effect of choosing `'5.6'` is to infer that functions removed in php 7.0 exist.
|
||||||
|
// (See `backward_compatibility_checks` for additional options)
|
||||||
|
// Automatically inferred from composer.json requirement for "php" of ">=7.4.0"
|
||||||
|
'target_php_version' => '7.4',
|
||||||
|
|
||||||
|
// If enabled, missing properties will be created when
|
||||||
|
// they are first seen. If false, we'll report an
|
||||||
|
// error message if there is an attempt to write
|
||||||
|
// to a class property that wasn't explicitly
|
||||||
|
// defined.
|
||||||
|
'allow_missing_properties' => false,
|
||||||
|
|
||||||
|
// If enabled, null can be cast to any type and any
|
||||||
|
// type can be cast to null. Setting this to true
|
||||||
|
// will cut down on false positives.
|
||||||
|
'null_casts_as_any_type' => false,
|
||||||
|
|
||||||
|
// If enabled, allow null to be cast as any array-like type.
|
||||||
|
//
|
||||||
|
// This is an incremental step in migrating away from `null_casts_as_any_type`.
|
||||||
|
// If `null_casts_as_any_type` is true, this has no effect.
|
||||||
|
'null_casts_as_array' => true,
|
||||||
|
|
||||||
|
// If enabled, allow any array-like type to be cast to null.
|
||||||
|
// This is an incremental step in migrating away from `null_casts_as_any_type`.
|
||||||
|
// If `null_casts_as_any_type` is true, this has no effect.
|
||||||
|
'array_casts_as_null' => true,
|
||||||
|
|
||||||
|
// If enabled, scalars (int, float, bool, string, null)
|
||||||
|
// are treated as if they can cast to each other.
|
||||||
|
// This does not affect checks of array keys. See `scalar_array_key_cast`.
|
||||||
|
'scalar_implicit_cast' => false,
|
||||||
|
|
||||||
|
// If enabled, any scalar array keys (int, string)
|
||||||
|
// are treated as if they can cast to each other.
|
||||||
|
// E.g. `array<int,stdClass>` can cast to `array<string,stdClass>` and vice versa.
|
||||||
|
// Normally, a scalar type such as int could only cast to/from int and mixed.
|
||||||
|
'scalar_array_key_cast' => true,
|
||||||
|
|
||||||
|
// If this has entries, scalars (int, float, bool, string, null)
|
||||||
|
// are allowed to perform the casts listed.
|
||||||
|
//
|
||||||
|
// E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]`
|
||||||
|
// allows casting null to a string, but not vice versa.
|
||||||
|
// (subset of `scalar_implicit_cast`)
|
||||||
|
'scalar_implicit_partial' => [],
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in a method invocation's object
|
||||||
|
// is definitely not an object,
|
||||||
|
// or if **any** type in an invoked expression is not a callable.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_method_checking' => false,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type of the object expression for a property access
|
||||||
|
// does not contain that property.
|
||||||
|
'strict_object_checking' => false,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in the argument's union type
|
||||||
|
// cannot be cast to a type in the parameter's expected union type.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_param_checking' => false,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in a property assignment's union type
|
||||||
|
// cannot be cast to a type in the property's declared union type.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_property_checking' => false,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in a returned value's union type
|
||||||
|
// cannot be cast to the declared return type.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_return_checking' => false,
|
||||||
|
|
||||||
|
// If true, seemingly undeclared variables in the global
|
||||||
|
// scope will be ignored.
|
||||||
|
//
|
||||||
|
// This is useful for projects with complicated cross-file
|
||||||
|
// globals that you have no hope of fixing.
|
||||||
|
'ignore_undeclared_variables_in_global_scope' => true,
|
||||||
|
|
||||||
|
// Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for,
|
||||||
|
// but aren't available in the codebase, or from Reflection.
|
||||||
|
// (may lead to false positives if an extension isn't loaded)
|
||||||
|
//
|
||||||
|
// If this is true(default), then Phan will not warn.
|
||||||
|
//
|
||||||
|
// Even when this is false, Phan will still infer return values and check parameters of internal functions
|
||||||
|
// if Phan has the signatures.
|
||||||
|
'ignore_undeclared_functions_with_known_signatures' => true,
|
||||||
|
|
||||||
|
// Backwards Compatibility Checking. This is slow
|
||||||
|
// and expensive, but you should consider running
|
||||||
|
// it before upgrading your version of PHP to a
|
||||||
|
// new version that has backward compatibility
|
||||||
|
// breaks.
|
||||||
|
//
|
||||||
|
// If you are migrating from PHP 5 to PHP 7,
|
||||||
|
// you should also look into using
|
||||||
|
// [php7cc (no longer maintained)](https://github.com/sstalle/php7cc)
|
||||||
|
// and [php7mar](https://github.com/Alexia/php7mar),
|
||||||
|
// which have different backwards compatibility checks.
|
||||||
|
'backward_compatibility_checks' => false,
|
||||||
|
|
||||||
|
// If true, check to make sure the return type declared
|
||||||
|
// in the doc-block (if any) matches the return type
|
||||||
|
// declared in the method signature.
|
||||||
|
'check_docblock_signature_return_type_match' => false,
|
||||||
|
|
||||||
|
// This setting maps case-insensitive strings to union types.
|
||||||
|
//
|
||||||
|
// This is useful if a project uses phpdoc that differs from the phpdoc2 standard.
|
||||||
|
//
|
||||||
|
// If the corresponding value is the empty string,
|
||||||
|
// then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`)
|
||||||
|
//
|
||||||
|
// If the corresponding value is not empty,
|
||||||
|
// then Phan will act as though it saw the corresponding UnionTypes(s)
|
||||||
|
// when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc.
|
||||||
|
//
|
||||||
|
// This matches the **entire string**, not parts of the string.
|
||||||
|
// (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting)
|
||||||
|
//
|
||||||
|
// (These are not aliases, this setting is ignored outside of doc comments).
|
||||||
|
// (Phan does not check if classes with these names exist)
|
||||||
|
//
|
||||||
|
// Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']`
|
||||||
|
'phpdoc_type_mapping' => [],
|
||||||
|
|
||||||
|
// Set to true in order to attempt to detect dead
|
||||||
|
// (unreferenced) code. Keep in mind that the
|
||||||
|
// results will only be a guess given that classes,
|
||||||
|
// properties, constants and methods can be referenced
|
||||||
|
// as variables (like `$class->$property` or
|
||||||
|
// `$class->$method()`) in ways that we're unable
|
||||||
|
// to make sense of.
|
||||||
|
'dead_code_detection' => false,
|
||||||
|
|
||||||
|
// Set to true in order to attempt to detect unused variables.
|
||||||
|
// `dead_code_detection` will also enable unused variable detection.
|
||||||
|
//
|
||||||
|
// This has a few known false positives, e.g. for loops or branches.
|
||||||
|
'unused_variable_detection' => false,
|
||||||
|
|
||||||
|
// Set to true in order to attempt to detect redundant and impossible conditions.
|
||||||
|
//
|
||||||
|
// This has some false positives involving loops,
|
||||||
|
// variables set in branches of loops, and global variables.
|
||||||
|
'redundant_condition_detection' => false,
|
||||||
|
|
||||||
|
// If enabled, Phan will act as though it's certain of real return types of a subset of internal functions,
|
||||||
|
// even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version).
|
||||||
|
//
|
||||||
|
// Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect.
|
||||||
|
// As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x.
|
||||||
|
'assume_real_types_for_internal_functions' => false,
|
||||||
|
|
||||||
|
// If true, this runs a quick version of checks that takes less
|
||||||
|
// time at the cost of not running as thorough
|
||||||
|
// of an analysis. You should consider setting this
|
||||||
|
// to true only when you wish you had more **undiagnosed** issues
|
||||||
|
// to fix in your code base.
|
||||||
|
//
|
||||||
|
// In quick-mode the scanner doesn't rescan a function
|
||||||
|
// or a method's code block every time a call is seen.
|
||||||
|
// This means that the problem here won't be detected:
|
||||||
|
//
|
||||||
|
// ```php
|
||||||
|
// <?php
|
||||||
|
// function test($arg):int {
|
||||||
|
// return $arg;
|
||||||
|
// }
|
||||||
|
// test("abc");
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// This would normally generate:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// test.php:3 PhanTypeMismatchReturn Returning type string but test() is declared to return int
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// The initial scan of the function's code block has no
|
||||||
|
// type information for `$arg`. It isn't until we see
|
||||||
|
// the call and rescan `test()`'s code block that we can
|
||||||
|
// detect that it is actually returning the passed in
|
||||||
|
// `string` instead of an `int` as declared.
|
||||||
|
'quick_mode' => false,
|
||||||
|
|
||||||
|
// Override to hardcode existence and types of (non-builtin) globals in the global scope.
|
||||||
|
// Class names should be prefixed with `\`.
|
||||||
|
//
|
||||||
|
// (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`)
|
||||||
|
'globals_type_map' => [],
|
||||||
|
|
||||||
|
// The minimum severity level to report on. This can be
|
||||||
|
// set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or
|
||||||
|
// `Issue::SEVERITY_CRITICAL`. Setting it to only
|
||||||
|
// critical issues is a good place to start on a big
|
||||||
|
// sloppy mature code base.
|
||||||
|
'minimum_severity' => Issue::SEVERITY_LOW,
|
||||||
|
|
||||||
|
// Add any issue types (such as `'PhanUndeclaredMethod'`)
|
||||||
|
// to this black-list to inhibit them from being reported.
|
||||||
|
'suppress_issue_types' => [],
|
||||||
|
|
||||||
|
// A regular expression to match files to be excluded
|
||||||
|
// from parsing and analysis and will not be read at all.
|
||||||
|
//
|
||||||
|
// This is useful for excluding groups of test or example
|
||||||
|
// directories/files, unanalyzable files, or files that
|
||||||
|
// can't be removed for whatever reason.
|
||||||
|
// (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`)
|
||||||
|
'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@',
|
||||||
|
|
||||||
|
// A list of files that will be excluded from parsing and analysis
|
||||||
|
// and will not be read at all.
|
||||||
|
//
|
||||||
|
// This is useful for excluding hopelessly unanalyzable
|
||||||
|
// files that can't be removed for whatever reason.
|
||||||
|
'exclude_file_list' => [],
|
||||||
|
|
||||||
|
// A directory list that defines files that will be excluded
|
||||||
|
// from static analysis, but whose class and method
|
||||||
|
// information should be included.
|
||||||
|
//
|
||||||
|
// Generally, you'll want to include the directories for
|
||||||
|
// third-party code (such as "vendor/") in this list.
|
||||||
|
//
|
||||||
|
// n.b.: If you'd like to parse but not analyze 3rd
|
||||||
|
// party code, directories containing that code
|
||||||
|
// should be added to the `directory_list` as well as
|
||||||
|
// to `exclude_analysis_directory_list`.
|
||||||
|
'exclude_analysis_directory_list' => [
|
||||||
|
'vendor/',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Enable this to enable checks of require/include statements referring to valid paths.
|
||||||
|
// The settings `include_paths` and `warn_about_relative_include_statement` affect the checks.
|
||||||
|
'enable_include_path_checks' => true,
|
||||||
|
|
||||||
|
// The number of processes to fork off during the analysis
|
||||||
|
// phase.
|
||||||
|
'processes' => 1,
|
||||||
|
|
||||||
|
// List of case-insensitive file extensions supported by Phan.
|
||||||
|
// (e.g. `['php', 'html', 'htm']`)
|
||||||
|
'analyzed_file_extensions' => [
|
||||||
|
'php',
|
||||||
|
],
|
||||||
|
|
||||||
|
// You can put paths to stubs of internal extensions in this config option.
|
||||||
|
// If the corresponding extension is **not** loaded, then Phan will use the stubs instead.
|
||||||
|
// Phan will continue using its detailed type annotations,
|
||||||
|
// but load the constants, classes, functions, and classes (and their Reflection types)
|
||||||
|
// from these stub files (doubling as valid php files).
|
||||||
|
// Use a different extension from php to avoid accidentally loading these.
|
||||||
|
// The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now)
|
||||||
|
//
|
||||||
|
// (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`)
|
||||||
|
'autoload_internal_extension_signatures' => [],
|
||||||
|
|
||||||
|
// A list of plugin files to execute.
|
||||||
|
//
|
||||||
|
// Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`)
|
||||||
|
//
|
||||||
|
// Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins).
|
||||||
|
//
|
||||||
|
// Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`)
|
||||||
|
'plugins' => [
|
||||||
|
'AlwaysReturnPlugin',
|
||||||
|
'PregRegexCheckerPlugin',
|
||||||
|
'UnreachableCodePlugin',
|
||||||
|
],
|
||||||
|
|
||||||
|
// A list of directories that should be parsed for class and
|
||||||
|
// method information. After excluding the directories
|
||||||
|
// defined in `exclude_analysis_directory_list`, the remaining
|
||||||
|
// files will be statically analyzed for errors.
|
||||||
|
//
|
||||||
|
// Thus, both first-party and third-party code being used by
|
||||||
|
// your application should be included in this list.
|
||||||
|
'directory_list' => [
|
||||||
|
'src/danog/MadelineProto',
|
||||||
|
'vendor/amphp/amp/lib',
|
||||||
|
'vendor/amphp/byte-stream/lib',
|
||||||
|
'vendor/amphp/dns/lib',
|
||||||
|
'vendor/amphp/file/src',
|
||||||
|
'vendor/amphp/http-client-cookies/src',
|
||||||
|
'vendor/amphp/http-client/src',
|
||||||
|
'vendor/amphp/http-server/src',
|
||||||
|
'vendor/amphp/http/src',
|
||||||
|
'vendor/amphp/php-cs-fixer-config/src',
|
||||||
|
'vendor/amphp/socket/src',
|
||||||
|
'vendor/amphp/websocket-client/src',
|
||||||
|
'vendor/amphp/websocket/src',
|
||||||
|
'vendor/danog/7to5/src',
|
||||||
|
'vendor/danog/7to70/src',
|
||||||
|
'vendor/danog/dns-over-https/lib',
|
||||||
|
'vendor/danog/ipc/lib',
|
||||||
|
'vendor/danog/magicalserializer/src',
|
||||||
|
'vendor/danog/primemodule/lib',
|
||||||
|
'vendor/danog/tg-file-decoder/src',
|
||||||
|
'vendor/danog/tgseclib/phpseclib',
|
||||||
|
'vendor/erusev/parsedown',
|
||||||
|
'vendor/league/uri/src'
|
||||||
|
],
|
||||||
|
|
||||||
|
// A list of individual files to include in analysis
|
||||||
|
// with a path relative to the root directory of the
|
||||||
|
// project.
|
||||||
|
'file_list' => [],
|
||||||
|
];
|
@ -33,7 +33,8 @@
|
|||||||
"danog/magicalserializer": "^1.0",
|
"danog/magicalserializer": "^1.0",
|
||||||
"league/uri": "^6",
|
"league/uri": "^6",
|
||||||
"danog/ipc": "^0.1",
|
"danog/ipc": "^0.1",
|
||||||
"tivie/htaccess-parser": "^0.2.3"
|
"tivie/htaccess-parser": "^0.2.3",
|
||||||
|
"amphp/log": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"vlucas/phpdotenv": "^3",
|
"vlucas/phpdotenv": "^3",
|
||||||
|
@ -102,7 +102,7 @@ $settings = [
|
|||||||
],
|
],
|
||||||
'serialization' => [
|
'serialization' => [
|
||||||
'serialization_interval' => 30,
|
'serialization_interval' => 30,
|
||||||
],
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$MadelineProto = new API('bot.madeline', $settings);
|
$MadelineProto = new API('bot.madeline', $settings);
|
||||||
|
102
legacy/danog/MadelineProto/Server.php
Normal file
102
legacy/danog/MadelineProto/Server.php
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server module.
|
||||||
|
*
|
||||||
|
* This file is part of MadelineProto.
|
||||||
|
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
* MadelineProto 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 Affero General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||||
|
*
|
||||||
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace danog\MadelineProto;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket server for multi-language API
|
||||||
|
*/
|
||||||
|
class Server
|
||||||
|
{
|
||||||
|
private $settings;
|
||||||
|
private $pids = [];
|
||||||
|
private $mypid;
|
||||||
|
public function __construct($settings)
|
||||||
|
{
|
||||||
|
\set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||||
|
\danog\MadelineProto\Logger::constructor(3);
|
||||||
|
if (!\extension_loaded('sockets')) {
|
||||||
|
throw new Exception(['extension', 'sockets']);
|
||||||
|
}
|
||||||
|
if (!\extension_loaded('pcntl')) {
|
||||||
|
throw new Exception(['extension', 'pcntl']);
|
||||||
|
}
|
||||||
|
$this->settings = $settings;
|
||||||
|
$this->mypid = \getmypid();
|
||||||
|
}
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
\pcntl_signal(SIGTERM, [$this, 'sigHandler']);
|
||||||
|
\pcntl_signal(SIGINT, [$this, 'sigHandler']);
|
||||||
|
\pcntl_signal(SIGCHLD, [$this, 'sigHandler']);
|
||||||
|
$this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
||||||
|
$this->sock->bind($this->settings['address'], $this->settings['port']);
|
||||||
|
$this->sock->listen();
|
||||||
|
$this->sock->setBlocking(true);
|
||||||
|
$timeout = 2;
|
||||||
|
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||||
|
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||||
|
\danog\MadelineProto\Logger::log('Server started! Listening on ' . $this->settings['address'] . ':' . $this->settings['port']);
|
||||||
|
while (true) {
|
||||||
|
\pcntl_signal_dispatch();
|
||||||
|
try {
|
||||||
|
if ($sock = $this->sock->accept()) {
|
||||||
|
$this->handle($sock);
|
||||||
|
}
|
||||||
|
} catch (\danog\MadelineProto\Exception $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function handle($socket)
|
||||||
|
{
|
||||||
|
$pid = \pcntl_fork();
|
||||||
|
if ($pid == -1) {
|
||||||
|
die('could not fork');
|
||||||
|
} elseif ($pid) {
|
||||||
|
return $this->pids[] = $pid;
|
||||||
|
}
|
||||||
|
$handler = new $this->settings['handler']($socket, $this->settings['extra'], null, null, null, null, null);
|
||||||
|
$handler->loop();
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
if ($this->mypid === \getmypid()) {
|
||||||
|
\danog\MadelineProto\Logger::log('Shutting main process ' . $this->mypid . ' down');
|
||||||
|
unset($this->sock);
|
||||||
|
foreach ($this->pids as $pid) {
|
||||||
|
\danog\MadelineProto\Logger::log("Waiting for {$pid}");
|
||||||
|
\pcntl_wait($pid);
|
||||||
|
}
|
||||||
|
\danog\MadelineProto\Logger::log('Done, closing main process');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function sigHandler($sig)
|
||||||
|
{
|
||||||
|
switch ($sig) {
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGINT:
|
||||||
|
exit;
|
||||||
|
case SIGCHLD:
|
||||||
|
\pcntl_waitpid(-1, $status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
psalm.xml
Normal file
18
psalm.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<psalm
|
||||||
|
totallyTyped="false"
|
||||||
|
errorLevel="6"
|
||||||
|
resolveFromConfigFile="true"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="https://getpsalm.org/schema/config"
|
||||||
|
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||||
|
>
|
||||||
|
<projectFiles>
|
||||||
|
<directory name="src" />
|
||||||
|
<ignoreFiles>
|
||||||
|
<directory name="vendor" />
|
||||||
|
<file name="src/danog/MadelineProto/InternalDoc.php" />
|
||||||
|
<file name="src/danog/MadelineProto/TON/InternalDoc.php" />
|
||||||
|
</ignoreFiles>
|
||||||
|
</projectFiles>
|
||||||
|
</psalm>
|
@ -271,7 +271,7 @@ class API extends InternalDoc
|
|||||||
*
|
*
|
||||||
* @return \Generator
|
* @return \Generator
|
||||||
*/
|
*/
|
||||||
private function startAndLoopAsync(string $eventHandler): \Generator
|
public function startAndLoopAsync(string $eventHandler): \Generator
|
||||||
{
|
{
|
||||||
$this->async(true);
|
$this->async(true);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -39,6 +39,7 @@ use Amp\Websocket\Client\Rfc6455Connector;
|
|||||||
use danog\MadelineProto\MTProto\PermAuthKey;
|
use danog\MadelineProto\MTProto\PermAuthKey;
|
||||||
use danog\MadelineProto\MTProto\TempAuthKey;
|
use danog\MadelineProto\MTProto\TempAuthKey;
|
||||||
use danog\MadelineProto\Stream\Common\BufferedRawStream;
|
use danog\MadelineProto\Stream\Common\BufferedRawStream;
|
||||||
|
use danog\MadelineProto\Stream\Common\UdpBufferedStream;
|
||||||
use danog\MadelineProto\Stream\ConnectionContext;
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream;
|
use danog\MadelineProto\Stream\MTProtoTransport\AbridgedStream;
|
||||||
use danog\MadelineProto\Stream\MTProtoTransport\FullStream;
|
use danog\MadelineProto\Stream\MTProtoTransport\FullStream;
|
||||||
@ -212,7 +213,7 @@ class DataCenter
|
|||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
foreach ($this->sockets as $key => $socket) {
|
foreach ($this->sockets as $key => $socket) {
|
||||||
if ($socket instanceof DataCenterConnection && !\strpos($key, '_bk')) {
|
if ($socket instanceof DataCenterConnection && !\strpos($key, '_bk')) {
|
||||||
//$this->API->logger->logger(\sprintf(Lang::$current_lang['dc_con_stop'], $key), \danog\MadelineProto\Logger::VERBOSE);
|
//$this->API->logger->logger(\sprintf(Lang::$current_lang['dc_con_stop'], $key), Logger::VERBOSE);
|
||||||
if ($reconnectAll || isset($changed[$id])) {
|
if ($reconnectAll || isset($changed[$id])) {
|
||||||
$this->API->logger->logger("Disconnecting all before reconnect!");
|
$this->API->logger->logger("Disconnecting all before reconnect!");
|
||||||
$socket->needReconnect(true);
|
$socket->needReconnect(true);
|
||||||
@ -238,6 +239,24 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Set VoIP endpoints.
|
||||||
|
*
|
||||||
|
* @param array $endpoints Endpoints
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setVoIPEndpoints(array $endpoints): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Connect to specified DC.
|
||||||
|
*
|
||||||
|
* @param string $dc_number DC to connect to
|
||||||
|
* @param integer $id Connection ID to re-establish (optional)
|
||||||
|
*
|
||||||
|
* @return \Generator<bool>
|
||||||
|
*/
|
||||||
public function dcConnect(string $dc_number, int $id = -1): \Generator
|
public function dcConnect(string $dc_number, int $id = -1): \Generator
|
||||||
{
|
{
|
||||||
$old = isset($this->sockets[$dc_number]) && ($this->sockets[$dc_number]->shouldReconnect() || $id !== -1 && $this->sockets[$dc_number]->hasConnection($id) && $this->sockets[$dc_number]->getConnection($id)->shouldReconnect());
|
$old = isset($this->sockets[$dc_number]) && ($this->sockets[$dc_number]->shouldReconnect() || $id !== -1 && $this->sockets[$dc_number]->hasConnection($id) && $this->sockets[$dc_number]->getConnection($id)->shouldReconnect());
|
||||||
@ -252,30 +271,36 @@ class DataCenter
|
|||||||
foreach ($ctxs as $ctx) {
|
foreach ($ctxs as $ctx) {
|
||||||
try {
|
try {
|
||||||
if ($old) {
|
if ($old) {
|
||||||
$this->API->logger->logger("Reconnecting to DC {$dc_number} ({$id}) from existing", \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger("Reconnecting to DC {$dc_number} ({$id}) from existing", Logger::WARNING);
|
||||||
$this->sockets[$dc_number]->setExtra($this->API);
|
$this->sockets[$dc_number]->setExtra($this->API);
|
||||||
yield from $this->sockets[$dc_number]->connect($ctx, $id);
|
yield from $this->sockets[$dc_number]->connect($ctx, $id);
|
||||||
} else {
|
} else {
|
||||||
$this->API->logger->logger("Connecting to DC {$dc_number} from scratch", \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger("Connecting to DC {$dc_number} from scratch", Logger::WARNING);
|
||||||
$this->sockets[$dc_number] = new DataCenterConnection();
|
$this->sockets[$dc_number] = new DataCenterConnection();
|
||||||
$this->sockets[$dc_number]->setExtra($this->API);
|
$this->sockets[$dc_number]->setExtra($this->API);
|
||||||
yield from $this->sockets[$dc_number]->connect($ctx);
|
yield from $this->sockets[$dc_number]->connect($ctx);
|
||||||
}
|
}
|
||||||
$this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
|
$this->API->logger->logger('OK!', Logger::WARNING);
|
||||||
return true;
|
return true;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
if (@\constant("MADELINEPROTO_TEST") === 'pony') {
|
if (@\constant("MADELINEPROTO_TEST") === 'pony') {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
$this->API->logger->logger("Connection failed ({$dc_number}): ".$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger("Connection failed ({$dc_number}): ".$e->getMessage(), Logger::ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception("Could not connect to DC {$dc_number}");
|
throw new Exception("Could not connect to DC {$dc_number}");
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param int|string $dc_number
|
* Generate contexts.
|
||||||
|
*
|
||||||
|
* @param integer $dc_number DC ID to generate contexts for
|
||||||
|
* @param string $uri URI
|
||||||
|
* @param ConnectContext $context Connection context
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null)
|
public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null): array
|
||||||
{
|
{
|
||||||
$ctxs = [];
|
$ctxs = [];
|
||||||
$combos = [];
|
$combos = [];
|
||||||
@ -309,6 +334,9 @@ class DataCenter
|
|||||||
case 'https':
|
case 'https':
|
||||||
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]];
|
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [HttpsStream::getName(), []]];
|
||||||
break;
|
break;
|
||||||
|
case 'udp':
|
||||||
|
$default = [[DefaultStream::getName(), []], [UdpBufferedStream::getName(), []]];
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception(Lang::$current_lang['protocol_invalid']);
|
throw new Exception(Lang::$current_lang['protocol_invalid']);
|
||||||
}
|
}
|
||||||
@ -490,7 +518,7 @@ class DataCenter
|
|||||||
}
|
}
|
||||||
if (empty($ctxs)) {
|
if (empty($ctxs)) {
|
||||||
unset($this->sockets[$dc_number]);
|
unset($this->sockets[$dc_number]);
|
||||||
$this->API->logger->logger("No info for DC {$dc_number}", \danog\MadelineProto\Logger::ERROR);
|
$this->API->logger->logger("No info for DC {$dc_number}", Logger::ERROR);
|
||||||
} elseif (@\constant("MADELINEPROTO_TEST") === 'pony') {
|
} elseif (@\constant("MADELINEPROTO_TEST") === 'pony') {
|
||||||
return [$ctxs[0]];
|
return [$ctxs[0]];
|
||||||
}
|
}
|
||||||
|
@ -621,7 +621,7 @@ class Lang
|
|||||||
{
|
{
|
||||||
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) {
|
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) {
|
||||||
\danog\MadelineProto\Lang::$lang['en'][$key] = $value;
|
\danog\MadelineProto\Lang::$lang['en'][$key] = $value;
|
||||||
\file_put_contents(__DIR__.'/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
|
//\file_put_contents(__DIR__.'/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -87,7 +87,7 @@ class ReadLoop extends SignalLoop
|
|||||||
Tools::callForkDefer((function () use ($error, $shared, $connection, $datacenter, $API): \Generator {
|
Tools::callForkDefer((function () use ($error, $shared, $connection, $datacenter, $API): \Generator {
|
||||||
if ($error === -404) {
|
if ($error === -404) {
|
||||||
if ($shared->hasTempAuthKey()) {
|
if ($shared->hasTempAuthKey()) {
|
||||||
$API->logger->logger("WARNING: Resetting auth key in DC {$datacenter}...", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("WARNING: Resetting auth key in DC {$datacenter}...", Logger::WARNING);
|
||||||
$shared->setTempAuthKey(null);
|
$shared->setTempAuthKey(null);
|
||||||
$shared->resetSession();
|
$shared->resetSession();
|
||||||
foreach ($connection->new_outgoing as $message_id) {
|
foreach ($connection->new_outgoing as $message_id) {
|
||||||
@ -99,13 +99,13 @@ class ReadLoop extends SignalLoop
|
|||||||
yield from $connection->reconnect();
|
yield from $connection->reconnect();
|
||||||
}
|
}
|
||||||
} elseif ($error === -1) {
|
} elseif ($error === -1) {
|
||||||
$API->logger->logger("WARNING: Got quick ack from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("WARNING: Got quick ack from DC {$datacenter}", Logger::WARNING);
|
||||||
yield from $connection->reconnect();
|
yield from $connection->reconnect();
|
||||||
} elseif ($error === 0) {
|
} elseif ($error === 0) {
|
||||||
$API->logger->logger("Got NOOP from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("Got NOOP from DC {$datacenter}", Logger::WARNING);
|
||||||
yield from $connection->reconnect();
|
yield from $connection->reconnect();
|
||||||
} elseif ($error === -429) {
|
} elseif ($error === -429) {
|
||||||
$API->logger->logger("Got -429 from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger("Got -429 from DC {$datacenter}", Logger::WARNING);
|
||||||
yield Tools::sleep(1);
|
yield Tools::sleep(1);
|
||||||
yield from $connection->reconnect();
|
yield from $connection->reconnect();
|
||||||
} else {
|
} else {
|
||||||
@ -138,14 +138,14 @@ class ReadLoop extends SignalLoop
|
|||||||
$API->logger->logger($e->getReason());
|
$API->logger->logger($e->getReason());
|
||||||
if (\strpos($e->getReason(), ' ') === 0) {
|
if (\strpos($e->getReason(), ' ') === 0) {
|
||||||
$payload = -\substr($e->getReason(), 7);
|
$payload = -\substr($e->getReason(), 7);
|
||||||
$API->logger->logger("Received {$payload} from DC ".$datacenter, \danog\MadelineProto\Logger::ERROR);
|
$API->logger->logger("Received {$payload} from DC ".$datacenter, Logger::ERROR);
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
if ($payload_length === 4) {
|
if ($payload_length === 4) {
|
||||||
$payload = \danog\MadelineProto\Tools::unpackSignedInt(yield $buffer->bufferRead(4));
|
$payload = \danog\MadelineProto\Tools::unpackSignedInt(yield $buffer->bufferRead(4));
|
||||||
$API->logger->logger("Received {$payload} from DC ".$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger("Received {$payload} from DC ".$datacenter, Logger::ULTRA_VERBOSE);
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
$connection->reading(true);
|
$connection->reading(true);
|
||||||
@ -160,9 +160,9 @@ class ReadLoop extends SignalLoop
|
|||||||
$message_data = yield $buffer->bufferRead($message_length);
|
$message_data = yield $buffer->bufferRead($message_length);
|
||||||
$left = $payload_length - $message_length - 4 - 8 - 8;
|
$left = $payload_length - $message_length - 4 - 8 - 8;
|
||||||
if ($left) {
|
if ($left) {
|
||||||
$API->logger->logger('Padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Padded unencrypted message', Logger::ULTRA_VERBOSE);
|
||||||
if ($left < (-$message_length & 15)) {
|
if ($left < (-$message_length & 15)) {
|
||||||
$API->logger->logger('Protocol padded unencrypted message', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Protocol padded unencrypted message', Logger::ULTRA_VERBOSE);
|
||||||
}
|
}
|
||||||
yield $buffer->bufferRead($left);
|
yield $buffer->bufferRead($left);
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ class ReadLoop extends SignalLoop
|
|||||||
/*
|
/*
|
||||||
$server_salt = substr($decrypted_data, 0, 8);
|
$server_salt = substr($decrypted_data, 0, 8);
|
||||||
if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) {
|
if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) {
|
||||||
$API->logger->logger('WARNING: Server salt mismatch (my server salt '.$shared->getTempAuthKey()->getServerSalt().' is not equal to server server salt '.$server_salt.').', \danog\MadelineProto\Logger::WARNING);
|
$API->logger->logger('WARNING: Server salt mismatch (my server salt '.$shared->getTempAuthKey()->getServerSalt().' is not equal to server server salt '.$server_salt.').', Logger::WARNING);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
$session_id = \substr($decrypted_data, 8, 8);
|
$session_id = \substr($decrypted_data, 8, 8);
|
||||||
@ -213,16 +213,18 @@ class ReadLoop extends SignalLoop
|
|||||||
}
|
}
|
||||||
$connection->incoming_messages[$message_id] = ['seq_no' => $seq_no];
|
$connection->incoming_messages[$message_id] = ['seq_no' => $seq_no];
|
||||||
} else {
|
} else {
|
||||||
$API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR);
|
$API->logger->logger('Got unknown auth_key id', Logger::ERROR);
|
||||||
return -404;
|
return -404;
|
||||||
}
|
}
|
||||||
$deserialized = $API->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]);
|
$deserialized = $API->getTL()->deserialize($message_data, ['type' => '', 'connection' => $connection]);
|
||||||
$API->referenceDatabase->reset();
|
if (isset($API->referenceDatabase)) {
|
||||||
|
$API->referenceDatabase->reset();
|
||||||
|
}
|
||||||
$connection->incoming_messages[$message_id]['content'] = $deserialized;
|
$connection->incoming_messages[$message_id]['content'] = $deserialized;
|
||||||
$connection->incoming_messages[$message_id]['response'] = -1;
|
$connection->incoming_messages[$message_id]['response'] = -1;
|
||||||
$connection->new_incoming[$message_id] = $message_id;
|
$connection->new_incoming[$message_id] = $message_id;
|
||||||
//$connection->last_http_wait = 0;
|
//$connection->last_http_wait = 0;
|
||||||
$API->logger->logger('Received payload from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
$API->logger->logger('Received payload from DC '.$datacenter, Logger::ULTRA_VERBOSE);
|
||||||
} finally {
|
} finally {
|
||||||
$connection->reading(false);
|
$connection->reading(false);
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ trait ResponseHandler
|
|||||||
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
$this->methodRecall('', ['message_id' => $request_id, 'postpone' => true]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'HISTORY_GET_FAILED', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) {
|
if (\in_array($response['error_message'], ['MSGID_DECREASE_RETRY', 'HISTORY_GET_FAILED', 'RPC_CONNECT_FAILED', 'RPC_CALL_FAIL', 'PERSISTENT_TIMESTAMP_OUTDATED', 'RPC_MCGET_FAIL', 'no workers running', 'No workers running'])) {
|
||||||
Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]);
|
Loop::delay(1 * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -19,29 +19,11 @@
|
|||||||
|
|
||||||
namespace danog\MadelineProto\Stream;
|
namespace danog\MadelineProto\Stream;
|
||||||
|
|
||||||
use Amp\Promise;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer interface.
|
* Buffer interface.
|
||||||
*
|
*
|
||||||
* @author Daniil Gentili <daniil@daniil.it>
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
*/
|
*/
|
||||||
interface BufferInterface
|
interface BufferInterface extends ReadBufferInterface, WriteBufferInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Read data asynchronously.
|
|
||||||
*
|
|
||||||
* @param int $length How much data to read
|
|
||||||
*
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function bufferRead(int $length): Promise;
|
|
||||||
/**
|
|
||||||
* Write data asynchronously.
|
|
||||||
*
|
|
||||||
* @param string $data Data to write
|
|
||||||
*
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
public function bufferWrite(string $data): Promise;
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ interface BufferedStreamInterface extends StreamInterface
|
|||||||
*
|
*
|
||||||
* @param int $length Length of payload, as detected by this layer
|
* @param int $length Length of payload, as detected by this layer
|
||||||
*
|
*
|
||||||
* @return Promise
|
* @return Promise<BufferInterface>
|
||||||
*/
|
*/
|
||||||
public function getReadBuffer(&$length): Promise;
|
public function getReadBuffer(&$length): Promise;
|
||||||
/**
|
/**
|
||||||
|
@ -207,6 +207,21 @@ class BufferedRawStream implements BufferedStreamInterface, BufferInterface, Raw
|
|||||||
}
|
}
|
||||||
return $this->write($data);
|
return $this->write($data);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Get remaining data from buffer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function bufferClear(): string
|
||||||
|
{
|
||||||
|
$size = \fstat($this->memory_stream)['size'];
|
||||||
|
$offset = \ftell($this->memory_stream);
|
||||||
|
$buffer_length = $size - $offset;
|
||||||
|
$data = fread($this->memory_stream, $buffer_length);
|
||||||
|
fclose($this->memory_stream);
|
||||||
|
$this->memory_stream = null;
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
|
201
src/danog/MadelineProto/Stream/Common/UdpBufferedStream.php
Normal file
201
src/danog/MadelineProto/Stream/Common/UdpBufferedStream.php
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP stream wrapper.
|
||||||
|
*
|
||||||
|
* This file is part of MadelineProto.
|
||||||
|
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
* MadelineProto 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 Affero General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||||
|
*
|
||||||
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace danog\MadelineProto\Stream\Common;
|
||||||
|
|
||||||
|
use Amp\ByteStream\ClosedException;
|
||||||
|
use Amp\Failure;
|
||||||
|
use Amp\Promise;
|
||||||
|
use Amp\Socket\EncryptableSocket;
|
||||||
|
use Amp\Success;
|
||||||
|
use danog\MadelineProto\Exception;
|
||||||
|
use danog\MadelineProto\Stream\Async\BufferedStream;
|
||||||
|
use danog\MadelineProto\Stream\BufferedStreamInterface;
|
||||||
|
use danog\MadelineProto\Stream\ConnectionContext;
|
||||||
|
use danog\MadelineProto\Stream\RawStreamInterface;
|
||||||
|
use danog\MadelineProto\Stream\ReadBufferInterface;
|
||||||
|
use danog\MadelineProto\Stream\StreamInterface;
|
||||||
|
use danog\MadelineProto\Stream\Transport\DefaultStream;
|
||||||
|
use danog\MadelineProto\Stream\WriteBufferInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP stream wrapper.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
*/
|
||||||
|
class UdpBufferedStream extends DefaultStream implements BufferedStreamInterface
|
||||||
|
{
|
||||||
|
use BufferedStream;
|
||||||
|
private RawStreamInterface $stream;
|
||||||
|
/**
|
||||||
|
* Connect to stream.
|
||||||
|
*
|
||||||
|
* @param ConnectionContext $ctx The connection context
|
||||||
|
*
|
||||||
|
* @return \Generator
|
||||||
|
*/
|
||||||
|
public function connect(ConnectionContext $ctx, string $header = ''): \Generator
|
||||||
|
{
|
||||||
|
$this->stream = (yield from $ctx->getStream($header));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Async close.
|
||||||
|
*
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function disconnect()
|
||||||
|
{
|
||||||
|
return $this->stream->disconnect();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get read buffer asynchronously.
|
||||||
|
*
|
||||||
|
* @param int $length Length of payload, as detected by this layer
|
||||||
|
*
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function getReadBuffer(&$length): Promise
|
||||||
|
{
|
||||||
|
if (!$this->stream) {
|
||||||
|
return new Failure(new ClosedException("MadelineProto stream was disconnected"));
|
||||||
|
}
|
||||||
|
$chunk = yield $this->read();
|
||||||
|
if ($chunk === null) {
|
||||||
|
$this->disconnect();
|
||||||
|
throw new \danog\MadelineProto\NothingInTheSocketException();
|
||||||
|
}
|
||||||
|
$length = \strlen($chunk);
|
||||||
|
return new Success(new class($chunk) implements ReadBufferInterface {
|
||||||
|
/**
|
||||||
|
* Buffer.
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
private $buffer;
|
||||||
|
/**
|
||||||
|
* Constructor function.
|
||||||
|
*
|
||||||
|
* @param string $buf Buffer
|
||||||
|
*/
|
||||||
|
public function __construct(string $buf)
|
||||||
|
{
|
||||||
|
$this->buffer = \fopen('php://memory', 'r+');
|
||||||
|
\fwrite($this->buffer, $buf);
|
||||||
|
\fseek($this->buffer, 0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read data from buffer.
|
||||||
|
*
|
||||||
|
* @param integer $length Length
|
||||||
|
*
|
||||||
|
* @return Promise<string>
|
||||||
|
*/
|
||||||
|
public function bufferRead(int $length): Promise
|
||||||
|
{
|
||||||
|
return new Success(\fread($this->buffer, $length));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Destructor function.
|
||||||
|
*/
|
||||||
|
public function __destruct(): void
|
||||||
|
{
|
||||||
|
\fclose($this->buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get write buffer asynchronously.
|
||||||
|
*
|
||||||
|
* @param int $length Total length of data that is going to be piped in the buffer
|
||||||
|
*
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function getWriteBuffer(int $length, string $append = ''): Promise
|
||||||
|
{
|
||||||
|
return new Success(new class($length, $append, $this) implements WriteBufferInterface {
|
||||||
|
private int $length;
|
||||||
|
private string $append;
|
||||||
|
private int $append_after;
|
||||||
|
private RawStreamInterface $stream;
|
||||||
|
private string $data = '';
|
||||||
|
/**
|
||||||
|
* Constructor function
|
||||||
|
*
|
||||||
|
* @param integer $length
|
||||||
|
* @param string $append
|
||||||
|
* @param RawStreamInterface $rawStreamInterface
|
||||||
|
*/
|
||||||
|
public function __construct(int $length, string $append, RawStreamInterface $rawStreamInterface)
|
||||||
|
{
|
||||||
|
$this->stream = $rawStreamInterface;
|
||||||
|
$this->length = $length;
|
||||||
|
if (\strlen($append)) {
|
||||||
|
$this->append = $append;
|
||||||
|
$this->append_after = $length - \strlen($append);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Async write.
|
||||||
|
*
|
||||||
|
* @param string $data Data to write
|
||||||
|
*
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function bufferWrite(string $data): Promise
|
||||||
|
{
|
||||||
|
$this->data .= $data;
|
||||||
|
if ($this->append_after) {
|
||||||
|
$this->append_after -= \strlen($data);
|
||||||
|
if ($this->append_after === 0) {
|
||||||
|
$this->data .= $this->append;
|
||||||
|
$this->append = '';
|
||||||
|
return $this->stream->write($this->data);
|
||||||
|
} elseif ($this->append_after < 0) {
|
||||||
|
$this->append_after = 0;
|
||||||
|
$this->append = '';
|
||||||
|
throw new Exception('Tried to send too much out of frame data, cannot append');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Success(strlen($data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @return EncryptableSocket
|
||||||
|
*/
|
||||||
|
public function getSocket(): EncryptableSocket
|
||||||
|
{
|
||||||
|
return $this->stream->getSocket();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @return RawStreamInterface
|
||||||
|
*/
|
||||||
|
public function getStream(): RawStreamInterface
|
||||||
|
{
|
||||||
|
return $this->stream;
|
||||||
|
}
|
||||||
|
public static function getName(): string
|
||||||
|
{
|
||||||
|
return __CLASS__;
|
||||||
|
}
|
||||||
|
}
|
@ -411,9 +411,7 @@ class ConnectionContext
|
|||||||
/**
|
/**
|
||||||
* Get a stream from the stream chain.
|
* Get a stream from the stream chain.
|
||||||
*
|
*
|
||||||
* @internal Generator func
|
* @return \Generator<StreamInterface>
|
||||||
*
|
|
||||||
* @return \Generator
|
|
||||||
*/
|
*/
|
||||||
public function getStream(string $buffer = ''): \Generator
|
public function getStream(string $buffer = ''): \Generator
|
||||||
{
|
{
|
||||||
|
39
src/danog/MadelineProto/Stream/ReadBufferInterface.php
Normal file
39
src/danog/MadelineProto/Stream/ReadBufferInterface.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer interface.
|
||||||
|
*
|
||||||
|
* This file is part of MadelineProto.
|
||||||
|
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
* MadelineProto 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 Affero General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||||
|
*
|
||||||
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace danog\MadelineProto\Stream;
|
||||||
|
|
||||||
|
use Amp\Promise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read buffer interface.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
*/
|
||||||
|
interface ReadBufferInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Read data asynchronously.
|
||||||
|
*
|
||||||
|
* @param int $length How much data to read
|
||||||
|
*
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function bufferRead(int $length): Promise;
|
||||||
|
}
|
@ -46,7 +46,7 @@ class DefaultStream implements RawStreamInterface, ProxyStreamInterface
|
|||||||
*
|
*
|
||||||
* @var EncryptableSocket
|
* @var EncryptableSocket
|
||||||
*/
|
*/
|
||||||
private $stream;
|
protected $stream;
|
||||||
/**
|
/**
|
||||||
* Connector.
|
* Connector.
|
||||||
*
|
*
|
||||||
|
39
src/danog/MadelineProto/Stream/WriteBufferInterface.php
Normal file
39
src/danog/MadelineProto/Stream/WriteBufferInterface.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer interface.
|
||||||
|
*
|
||||||
|
* This file is part of MadelineProto.
|
||||||
|
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
* MadelineProto 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 Affero General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
||||||
|
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||||
|
*
|
||||||
|
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace danog\MadelineProto\Stream;
|
||||||
|
|
||||||
|
use Amp\Promise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write buffer interface.
|
||||||
|
*
|
||||||
|
* @author Daniil Gentili <daniil@daniil.it>
|
||||||
|
*/
|
||||||
|
interface WriteBufferInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Write data asynchronously.
|
||||||
|
*
|
||||||
|
* @param string $data Data to write
|
||||||
|
*
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
public function bufferWrite(string $data): Promise;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user