init
This commit is contained in:
170
code_depricated/instafeed.1.pl
Executable file
170
code_depricated/instafeed.1.pl
Executable file
@@ -0,0 +1,170 @@
|
|||||||
|
#!usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON::XS qw(encode_json decode_json);
|
||||||
|
use File::Slurp qw(read_file write_file);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
|
||||||
|
my %config = (
|
||||||
|
'uploadPHP' => {
|
||||||
|
'USERNAME' => 'dreamyourmansion',
|
||||||
|
'PASSWORD' => 'H5AZ#dQZ5Ycf',
|
||||||
|
'DEBUG' => 1,
|
||||||
|
'TRUNCATED_DEBUG' => 1,
|
||||||
|
'PROXY_USER' => 'zino%40onlinehome.de',
|
||||||
|
'PROXY_PASSWORD' => 'zinomedial33t',
|
||||||
|
'PROXY_IP' => 'de435.nordvpn.com',
|
||||||
|
'PROXY_PORT' => 80,
|
||||||
|
},
|
||||||
|
'profile' => undef,
|
||||||
|
'imageDir' => './src/images/',
|
||||||
|
'SRCRoot' => './src/',
|
||||||
|
'DBFilepath' => '/home/pi/instafeed/src/db/db.dat',
|
||||||
|
'uploadPHP_CMD' => '/usr/bin/php /home/pi/instafeed/vendor/mgp25/instagram-php/examples/uploadPhoto.php',
|
||||||
|
'uploadPHP_DESCRIPTION_ADD' => "The most beautiful real estates in the world!\n\nBenefit from the flourishing housing market in Germany. Contact us now by DM.\n\nVom Mieter zum Eigentümer! Exklusives Portfolio: Kontaktiere uns jetzt per DM.",
|
||||||
|
'uploadPHP_TAGS' => '#investment #immobilie #mansionhouse #dream #poolhouse #villa #realestate #loft #awesome #lifestyle #motivation #luxury',
|
||||||
|
);
|
||||||
|
|
||||||
|
my (%data, %db, %profiles);
|
||||||
|
my $dbKeysStart = 0;
|
||||||
|
GetOptions ('profile=s' => \$config{'profile'}) or die "Usage: $0 --profile *name*\n";
|
||||||
|
die "Usage: $0 --profile *name*\n" if !$config{'profile'} ;
|
||||||
|
|
||||||
|
# MAIN
|
||||||
|
|
||||||
|
&UndumpFromFile();
|
||||||
|
#print Dumper \%db;
|
||||||
|
&DirectoryListing();
|
||||||
|
# print Dumper \%data;
|
||||||
|
&FindNewDataset();
|
||||||
|
&Summary();
|
||||||
|
|
||||||
|
sub UndumpFromFile {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
if (-e $config{'DBFilepath'}) {
|
||||||
|
my $json = read_file($config{'DBFilepath'}, { binmode => ':raw' });
|
||||||
|
if (!$json) {
|
||||||
|
warn "DB file $config{'DBFilepath'} is empty.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
%db = %{ decode_json $json };
|
||||||
|
$dbKeysStart = scalar(keys(%db));
|
||||||
|
print "INFO: $config{'DBFilepath'} has " . $dbKeysStart . " keys.\n";
|
||||||
|
}
|
||||||
|
elsif (!-e $config{'DBFilepath'}) {
|
||||||
|
warn "INFO: NO DB file found at $config{'DBFilepath'}\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub DirectoryListing {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
opendir(DIR, $config{'imageDir'});
|
||||||
|
my @files = grep(/\.jpg$/,readdir(DIR));
|
||||||
|
closedir(DIR);
|
||||||
|
%data = map { $_ => { 'FILEPATH' => "$config{'imageDir'}$_" } } @files;
|
||||||
|
# @hash{@keys} = undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Summary {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
print "$config{'DBFilepath'} has " . scalar(keys(%db)) . " keys (before $dbKeysStart).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub FindNewDataset {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $key (keys %data) {
|
||||||
|
if (exists $db{$key}) {
|
||||||
|
print "OLD: $key\n";
|
||||||
|
}
|
||||||
|
elsif (!exists $db{$key}) {
|
||||||
|
print "NEW: $key\n";
|
||||||
|
|
||||||
|
my $success = &uploadPHP($data{$key}{'FILEPATH'});
|
||||||
|
if ($success) {
|
||||||
|
print "success is $success\n";
|
||||||
|
&AddToDB($key);
|
||||||
|
&WipeData($key);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i == scalar(keys(%data))) {
|
||||||
|
warn "\nNO NEW FILES AVAILABLE.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uploadPHP {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $filepath = shift;
|
||||||
|
my $success = 1;
|
||||||
|
my $captionText = "$config{'uploadPHP_DESCRIPTION_ADD'}\n\n$config{'uploadPHP_TAGS'}";
|
||||||
|
|
||||||
|
open PHPOUT, "$config{'uploadPHP_CMD'} $filepath \'$captionText\' $config{'uploadPHP'}{'USERNAME'} $config{'uploadPHP'}{'PASSWORD'} $config{'uploadPHP'}{'DEBUG'} $config{'uploadPHP'}{'TRUNCATED_DEBUG'} $config{'uploadPHP'}{'PROXY_USER'} $config{'uploadPHP'}{'PROXY_PASSWORD'} $config{'uploadPHP'}{'PROXY_IP'} $config{'uploadPHP'}{'PROXY_PORT'}|";
|
||||||
|
while (<PHPOUT>) {
|
||||||
|
print $_; # PRINT CURRENT PHP OUPUT LINE
|
||||||
|
if ($_ =~ m/error/) {
|
||||||
|
$success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub WipeData {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
print "Deleting $data{$key}{'FILEPATH'}...";
|
||||||
|
unlink($data{$key}{'FILEPATH'}) or die "Could not delete $data{$key}{'FILEPATH'}!\n";
|
||||||
|
print " Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub AddToDB {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
$data{$key}{'TIMESTAMP_UPLOADED'} = &GetTimestamp('YMDHMS');
|
||||||
|
$db{$key} = $data{$key};
|
||||||
|
my $json = encode_json \%db;
|
||||||
|
write_file($config{'DBFilepath'}, { binmode => ':raw' }, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Delimiter {
|
||||||
|
my $SubName = shift;
|
||||||
|
print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetTimestamp {
|
||||||
|
#&Delimiter((caller(0))[3]);
|
||||||
|
my $switch = shift;
|
||||||
|
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
|
||||||
|
|
||||||
|
my $nice_timestamp;
|
||||||
|
if ($switch eq 'YMDHMS') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d_%02d%02d%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'YMD') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d", $year+1900,$mon+1,$mday);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'year') {
|
||||||
|
$nice_timestamp = $year+1900;
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'month') {
|
||||||
|
$nice_timestamp = $mon+10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Invalid/no switch detected. Use: 'YMDHMS' / 'YMD'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nice_timestamp;
|
||||||
|
}
|
||||||
253
code_depricated/instafeed.pl
Executable file
253
code_depricated/instafeed.pl
Executable file
@@ -0,0 +1,253 @@
|
|||||||
|
#!usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON::XS qw(encode_json decode_json);
|
||||||
|
use File::Slurp qw(read_file write_file);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
my %config = (
|
||||||
|
'profile' => undef,
|
||||||
|
'SRCRoot' => './src/',
|
||||||
|
'uploadPHP_CMD' => '/usr/bin/php ./vendor/mgp25/instagram-php/examples/uploadPhoto.php',
|
||||||
|
'uploadPHP_debug' => 1,
|
||||||
|
'uploadPHP_truncated_debug' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
my %profile = (
|
||||||
|
'dreamyourmansion' => {
|
||||||
|
'DBFilepath' => './src/db/db_dreamyourmansion.dat',
|
||||||
|
'imageDir' => './src/images/dreamyourmansion',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'dreamyourmansion',
|
||||||
|
'password' => 'nBLT!4H3aI@c',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#investment #immobilie #mansionhouse #dream #poolhouse #villa #realestate #loft #awesome #lifestyle #motivation #luxury',
|
||||||
|
'description_add' => "The most beautiful real estates in the world!\n\nBenefit from the flourishing housing market in Germany. Contact us now by DM.\n\nVom Mieter zum Eigentümer! Exklusives Portfolio: Kontaktiere uns jetzt per DM.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'vstbestprices',
|
||||||
|
'password' => 'Vst#1337vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices_testing' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'adobebestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_adobebestprices.dat',
|
||||||
|
'imageDir' => './src/images/adobebestprices/',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#adobe #photoshop #adobeillustrator #vector #illustrator #adobephotoshop #vectorart #graphicdesign #aftereffects #logo #cs6 #lightroom #graphic',
|
||||||
|
'description_add' => 'Photoshop, Lightroom, Illustrator, Dreamviewer, Premiere for WIN & MAC | Installation support is included in all our prices!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
my (%data, %db);
|
||||||
|
my $dbKeysStart = 0;
|
||||||
|
my $profile;
|
||||||
|
|
||||||
|
# MAIN
|
||||||
|
&CheckParameter();
|
||||||
|
&UndumpFromFile();
|
||||||
|
#print Dumper \%db;
|
||||||
|
&DirectoryListing();
|
||||||
|
print Dumper \%data;
|
||||||
|
&FindNewDataset();
|
||||||
|
&Summary();
|
||||||
|
|
||||||
|
sub CheckParameter {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
GetOptions ('profile=s' => \$config{'profile'}) or die "Usage: $0 --profile *name*\n";
|
||||||
|
die "Usage: $0 --profile *name*\n" if !$config{'profile'} ;
|
||||||
|
$profile = $config{'profile'};
|
||||||
|
if (!exists $profile{$profile}) {
|
||||||
|
print "Template for profile '$profile' does not exist. Following templates are available:\n";
|
||||||
|
print "'$_' " for keys(%profile);
|
||||||
|
print "\n";
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub UndumpFromFile {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
if (-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
my $json = read_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' });
|
||||||
|
if (!$json) {
|
||||||
|
warn "DB file $profile{$profile}{'DBFilepath'} is empty.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
%db = %{ decode_json $json };
|
||||||
|
$dbKeysStart = scalar(keys(%db));
|
||||||
|
print "INFO: $profile{$profile}{'DBFilepath'} has " . $dbKeysStart . " keys.\n";
|
||||||
|
}
|
||||||
|
elsif (!-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
print "INFO: NO DB file found at $profile{$profile}{'DBFilepath'}. Creating now... ";
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, '');
|
||||||
|
print "done.\n";
|
||||||
|
die "Please restart.";
|
||||||
|
# &UndumpFromFile();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub DirectoryListing {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
# opendir(DIR, $profile{$profile}{'imageDir'});
|
||||||
|
# my @files = grep(/\.jpg$|\.png$|\.jpeg$|/,readdir(DIR));
|
||||||
|
# closedir(DIR);
|
||||||
|
my @files = glob ( "$profile{$profile}{'imageDir'}/*" );
|
||||||
|
%data = map { $_ => { 'FILEPATH' => "$_" } } @files;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Summary {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
print "$profile{$profile}{'DBFilepath'} has " . scalar(keys(%db)) . " keys (before $dbKeysStart).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub FindNewDataset {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $key (keys %data) {
|
||||||
|
if (exists $db{$key}) {
|
||||||
|
print "OLD: $key\n";
|
||||||
|
}
|
||||||
|
elsif (!exists $db{$key}) {
|
||||||
|
print "NEW: $key\n";
|
||||||
|
|
||||||
|
my $success = &uploadPHP($data{$key}{'FILEPATH'});
|
||||||
|
&AddToDB($key);
|
||||||
|
&WipeData($key);
|
||||||
|
last;
|
||||||
|
# if ($success) {
|
||||||
|
# print "success is $success\n";
|
||||||
|
# &AddToDB($key);
|
||||||
|
# &WipeData($key);
|
||||||
|
# last;
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i == scalar(keys(%data))) {
|
||||||
|
warn "\nNO NEW FILES AVAILABLE.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uploadPHP {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $filepath = shift;
|
||||||
|
|
||||||
|
my $success = 1;
|
||||||
|
my $captionText = "$profile{$profile}{'uploadPHP'}{'description_add'}\n\n$profile{$profile}{'uploadPHP'}{'tags'}";
|
||||||
|
if ($profile{$profile}{'filename_as_title'}) {
|
||||||
|
my $filename = basename($filepath);
|
||||||
|
$filename =~ s/(NO INSTALL)|(SymLink Installer)//g;
|
||||||
|
$filename =~ s/( , )|(\.[^.]+$)//g;
|
||||||
|
$captionText = "$filename\n\n" . $captionText;
|
||||||
|
# print Dumper $captionText;
|
||||||
|
}
|
||||||
|
open PHPOUT, "$config{'uploadPHP_CMD'} \'$filepath\' \'$captionText\' $profile{$profile}{'uploadPHP'}{'username'} $profile{$profile}{'uploadPHP'}{'password'} $config{'uploadPHP_debug'} $config{'uploadPHP_truncated_debug'} $profile{$profile}{'uploadPHP'}{'proxy_user'} $profile{$profile}{'uploadPHP'}{'proxy_password'} $profile{$profile}{'uploadPHP'}{'proxy_ip'} $profile{$profile}{'uploadPHP'}{'proxy_port'}|";
|
||||||
|
while (<PHPOUT>) {
|
||||||
|
print $_; # PRINT CURRENT PHP OUPUT LINE
|
||||||
|
if ($_ =~ m/error/) {
|
||||||
|
$success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub WipeData {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
print "Deleting $data{$key}{'FILEPATH'}...";
|
||||||
|
unlink($data{$key}{'FILEPATH'}) or die "Could not delete $data{$key}{'FILEPATH'}!\n";
|
||||||
|
print " Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub AddToDB {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
$data{$key}{'TIMESTAMP_UPLOADED'} = &GetTimestamp('YMDHMS');
|
||||||
|
$db{$key} = $data{$key};
|
||||||
|
my $json = encode_json \%db;
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' }, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Delimiter {
|
||||||
|
my $SubName = shift;
|
||||||
|
print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetTimestamp {
|
||||||
|
#&Delimiter((caller(0))[3]);
|
||||||
|
my $switch = shift;
|
||||||
|
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
|
||||||
|
|
||||||
|
my $nice_timestamp;
|
||||||
|
if ($switch eq 'YMDHMS') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d_%02d%02d%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'YMD') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d", $year+1900,$mon+1,$mday);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'year') {
|
||||||
|
$nice_timestamp = $year+1900;
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'month') {
|
||||||
|
$nice_timestamp = $mon+10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Invalid/no switch detected. Use: 'YMDHMS' / 'YMD'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nice_timestamp;
|
||||||
|
}
|
||||||
5
composer.json
Executable file
5
composer.json
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"mgp25/instagram-php": "^7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
1294
composer.lock
generated
Executable file
1294
composer.lock
generated
Executable file
File diff suppressed because it is too large
Load Diff
261
instafeed.pl
Executable file
261
instafeed.pl
Executable file
@@ -0,0 +1,261 @@
|
|||||||
|
#!usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON::XS qw(encode_json decode_json);
|
||||||
|
use File::Slurp qw(read_file write_file);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
use File::Basename;
|
||||||
|
use HTTP::Cookies;
|
||||||
|
use Cwd qw(cwd);
|
||||||
|
|
||||||
|
my %config = (
|
||||||
|
'profile' => undef,
|
||||||
|
'SRCRoot' => './src/',
|
||||||
|
'uploadPHP_CMD' => '/usr/bin/php ./vendor/mgp25/instagram-php/examples/uploadPhoto.php',
|
||||||
|
'uploadPHP_debug' => 1,
|
||||||
|
'uploadPHP_truncated_debug' => 1,
|
||||||
|
'uploadPHP_autoload' => cwd . '/src/mpg25-instagram-api/vendor/autoload.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
my %profile = (
|
||||||
|
'dreamyourmansion' => {
|
||||||
|
'DBFilepath' => './src/db/db_dreamyourmansion.dat',
|
||||||
|
'imageDir' => './src/images/dreamyourmansion',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'dreamyourmansion',
|
||||||
|
'password' => 'nBLT!4H3aI@c',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de786.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#investment #immobilie #mansionhouse #dream #poolhouse #villa #realestate #loft #awesome #lifestyle #motivation #luxury',
|
||||||
|
'description_add' => "The most beautiful real estates in the world!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'vstbestprices',
|
||||||
|
'password' => 'Vst#1337vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices_testing' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'adobebestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_adobebestprices.dat',
|
||||||
|
'imageDir' => './src/images/adobebestprices/',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#adobe #photoshop #adobeillustrator #vector #illustrator #adobephotoshop #vectorart #graphicdesign #aftereffects #logo #cs6 #lightroom #graphic',
|
||||||
|
'description_add' => 'Photoshop, Lightroom, Illustrator, Dreamviewer, Premiere for WIN & MAC | Installation support is included in all our prices!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
my (%data, %db);
|
||||||
|
my $dbKeysStart = 0;
|
||||||
|
my $profile;
|
||||||
|
|
||||||
|
# MAIN
|
||||||
|
&CheckParameter();
|
||||||
|
&UndumpFromFile();
|
||||||
|
#print Dumper \%db;
|
||||||
|
&DirectoryListing();
|
||||||
|
print Dumper \%data;
|
||||||
|
&FindNewDataset();
|
||||||
|
&Summary();
|
||||||
|
|
||||||
|
sub CheckParameter {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
GetOptions ('profile=s' => \$config{'profile'}) or die &PrintUsage();
|
||||||
|
die &PrintUsage() if !$config{'profile'};
|
||||||
|
$profile = $config{'profile'};
|
||||||
|
if (!exists $profile{$profile}) {
|
||||||
|
print "Profile '$profile' does not exist.\n";
|
||||||
|
&PrintUsage();
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub PrintUsage {
|
||||||
|
print "Usage: $0 --profile *name*\n";
|
||||||
|
print "Following profiles are available:\n";
|
||||||
|
print "* '$_'\n" for keys(%profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub UndumpFromFile {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
if (-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
my $json = read_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' });
|
||||||
|
if (!$json) {
|
||||||
|
warn "DB file $profile{$profile}{'DBFilepath'} is empty.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
%db = %{ decode_json $json };
|
||||||
|
$dbKeysStart = scalar(keys(%db));
|
||||||
|
print "INFO: $profile{$profile}{'DBFilepath'} has " . $dbKeysStart . " keys.\n";
|
||||||
|
}
|
||||||
|
elsif (!-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
print "INFO: NO DB file found at $profile{$profile}{'DBFilepath'}. Creating now... ";
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, '');
|
||||||
|
print "done.\n";
|
||||||
|
die "Please restart.";
|
||||||
|
# &UndumpFromFile();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub DirectoryListing {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
# opendir(DIR, $profile{$profile}{'imageDir'});
|
||||||
|
# my @files = grep(/\.jpg$|\.png$|\.jpeg$|/,readdir(DIR));
|
||||||
|
# closedir(DIR);
|
||||||
|
my @files = glob ( "$profile{$profile}{'imageDir'}/*" );
|
||||||
|
%data = map { $_ => { 'FILEPATH' => "$_" } } @files;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Summary {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
print "$profile{$profile}{'DBFilepath'} has " . scalar(keys(%db)) . " keys (before $dbKeysStart).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub FindNewDataset {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $key (keys %data) {
|
||||||
|
if (exists $db{$key}) {
|
||||||
|
print "OLD: $key\n";
|
||||||
|
}
|
||||||
|
elsif (!exists $db{$key}) {
|
||||||
|
print "NEW: $key\n";
|
||||||
|
|
||||||
|
my $success = &uploadPHP($data{$key}{'FILEPATH'});
|
||||||
|
&AddToDB($key);
|
||||||
|
&WipeData($key);
|
||||||
|
last;
|
||||||
|
# if ($success) {
|
||||||
|
# print "success is $success\n";
|
||||||
|
# &AddToDB($key);
|
||||||
|
# &WipeData($key);
|
||||||
|
# last;
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i == scalar(keys(%data))) {
|
||||||
|
warn "\nNO NEW FILES AVAILABLE.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uploadPHP {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $filepath = shift;
|
||||||
|
|
||||||
|
my $success = 1;
|
||||||
|
my $captionText = "$profile{$profile}{'uploadPHP'}{'description_add'}\n\n$profile{$profile}{'uploadPHP'}{'tags'}";
|
||||||
|
if ($profile{$profile}{'filename_as_title'}) {
|
||||||
|
my $filename = basename($filepath);
|
||||||
|
$filename =~ s/(NO INSTALL)|(SymLink Installer)//g;
|
||||||
|
$filename =~ s/( , )|(\.[^.]+$)//g;
|
||||||
|
$captionText = "$filename\n\n" . $captionText;
|
||||||
|
# print Dumper $captionText;
|
||||||
|
}
|
||||||
|
open PHPOUT, "$config{'uploadPHP_CMD'} \'$filepath\' \'$captionText\' $profile{$profile}{'uploadPHP'}{'username'} $profile{$profile}{'uploadPHP'}{'password'} $config{'uploadPHP_debug'} $config{'uploadPHP_truncated_debug'} $profile{$profile}{'uploadPHP'}{'proxy_user'} $profile{$profile}{'uploadPHP'}{'proxy_password'} $profile{$profile}{'uploadPHP'}{'proxy_ip'} $profile{$profile}{'uploadPHP'}{'proxy_port'} \'$config{'uploadPHP_autoload'}\'|";
|
||||||
|
while (<PHPOUT>) {
|
||||||
|
print $_; # PRINT CURRENT PHP OUPUT LINE
|
||||||
|
if ($_ =~ m/error/) {
|
||||||
|
$success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub WipeData {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
print "Deleting $data{$key}{'FILEPATH'}...";
|
||||||
|
unlink($data{$key}{'FILEPATH'}) or die "Could not delete $data{$key}{'FILEPATH'}!\n";
|
||||||
|
print " Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub AddToDB {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
$data{$key}{'TIMESTAMP_UPLOADED'} = &GetTimestamp('YMDHMS');
|
||||||
|
$db{$key} = $data{$key};
|
||||||
|
my $json = encode_json \%db;
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' }, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Delimiter {
|
||||||
|
my $SubName = shift;
|
||||||
|
print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetTimestamp {
|
||||||
|
#&Delimiter((caller(0))[3]);
|
||||||
|
my $switch = shift;
|
||||||
|
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
|
||||||
|
|
||||||
|
my $nice_timestamp;
|
||||||
|
if ($switch eq 'YMDHMS') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d_%02d%02d%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'YMD') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d", $year+1900,$mon+1,$mday);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'year') {
|
||||||
|
$nice_timestamp = $year+1900;
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'month') {
|
||||||
|
$nice_timestamp = $mon+10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Invalid/no switch detected. Use: 'YMDHMS' / 'YMD'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nice_timestamp;
|
||||||
|
}
|
||||||
170
instafeed/code_depricated/instafeed.1.pl
Executable file
170
instafeed/code_depricated/instafeed.1.pl
Executable file
@@ -0,0 +1,170 @@
|
|||||||
|
#!usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON::XS qw(encode_json decode_json);
|
||||||
|
use File::Slurp qw(read_file write_file);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
|
||||||
|
my %config = (
|
||||||
|
'uploadPHP' => {
|
||||||
|
'USERNAME' => 'dreamyourmansion',
|
||||||
|
'PASSWORD' => 'H5AZ#dQZ5Ycf',
|
||||||
|
'DEBUG' => 1,
|
||||||
|
'TRUNCATED_DEBUG' => 1,
|
||||||
|
'PROXY_USER' => 'zino%40onlinehome.de',
|
||||||
|
'PROXY_PASSWORD' => 'zinomedial33t',
|
||||||
|
'PROXY_IP' => 'de435.nordvpn.com',
|
||||||
|
'PROXY_PORT' => 80,
|
||||||
|
},
|
||||||
|
'profile' => undef,
|
||||||
|
'imageDir' => './src/images/',
|
||||||
|
'SRCRoot' => './src/',
|
||||||
|
'DBFilepath' => '/home/pi/instafeed/src/db/db.dat',
|
||||||
|
'uploadPHP_CMD' => '/usr/bin/php /home/pi/instafeed/vendor/mgp25/instagram-php/examples/uploadPhoto.php',
|
||||||
|
'uploadPHP_DESCRIPTION_ADD' => "The most beautiful real estates in the world!\n\nBenefit from the flourishing housing market in Germany. Contact us now by DM.\n\nVom Mieter zum Eigentümer! Exklusives Portfolio: Kontaktiere uns jetzt per DM.",
|
||||||
|
'uploadPHP_TAGS' => '#investment #immobilie #mansionhouse #dream #poolhouse #villa #realestate #loft #awesome #lifestyle #motivation #luxury',
|
||||||
|
);
|
||||||
|
|
||||||
|
my (%data, %db, %profiles);
|
||||||
|
my $dbKeysStart = 0;
|
||||||
|
GetOptions ('profile=s' => \$config{'profile'}) or die "Usage: $0 --profile *name*\n";
|
||||||
|
die "Usage: $0 --profile *name*\n" if !$config{'profile'} ;
|
||||||
|
|
||||||
|
# MAIN
|
||||||
|
|
||||||
|
&UndumpFromFile();
|
||||||
|
#print Dumper \%db;
|
||||||
|
&DirectoryListing();
|
||||||
|
# print Dumper \%data;
|
||||||
|
&FindNewDataset();
|
||||||
|
&Summary();
|
||||||
|
|
||||||
|
sub UndumpFromFile {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
if (-e $config{'DBFilepath'}) {
|
||||||
|
my $json = read_file($config{'DBFilepath'}, { binmode => ':raw' });
|
||||||
|
if (!$json) {
|
||||||
|
warn "DB file $config{'DBFilepath'} is empty.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
%db = %{ decode_json $json };
|
||||||
|
$dbKeysStart = scalar(keys(%db));
|
||||||
|
print "INFO: $config{'DBFilepath'} has " . $dbKeysStart . " keys.\n";
|
||||||
|
}
|
||||||
|
elsif (!-e $config{'DBFilepath'}) {
|
||||||
|
warn "INFO: NO DB file found at $config{'DBFilepath'}\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub DirectoryListing {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
opendir(DIR, $config{'imageDir'});
|
||||||
|
my @files = grep(/\.jpg$/,readdir(DIR));
|
||||||
|
closedir(DIR);
|
||||||
|
%data = map { $_ => { 'FILEPATH' => "$config{'imageDir'}$_" } } @files;
|
||||||
|
# @hash{@keys} = undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Summary {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
print "$config{'DBFilepath'} has " . scalar(keys(%db)) . " keys (before $dbKeysStart).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub FindNewDataset {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $key (keys %data) {
|
||||||
|
if (exists $db{$key}) {
|
||||||
|
print "OLD: $key\n";
|
||||||
|
}
|
||||||
|
elsif (!exists $db{$key}) {
|
||||||
|
print "NEW: $key\n";
|
||||||
|
|
||||||
|
my $success = &uploadPHP($data{$key}{'FILEPATH'});
|
||||||
|
if ($success) {
|
||||||
|
print "success is $success\n";
|
||||||
|
&AddToDB($key);
|
||||||
|
&WipeData($key);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i == scalar(keys(%data))) {
|
||||||
|
warn "\nNO NEW FILES AVAILABLE.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uploadPHP {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $filepath = shift;
|
||||||
|
my $success = 1;
|
||||||
|
my $captionText = "$config{'uploadPHP_DESCRIPTION_ADD'}\n\n$config{'uploadPHP_TAGS'}";
|
||||||
|
|
||||||
|
open PHPOUT, "$config{'uploadPHP_CMD'} $filepath \'$captionText\' $config{'uploadPHP'}{'USERNAME'} $config{'uploadPHP'}{'PASSWORD'} $config{'uploadPHP'}{'DEBUG'} $config{'uploadPHP'}{'TRUNCATED_DEBUG'} $config{'uploadPHP'}{'PROXY_USER'} $config{'uploadPHP'}{'PROXY_PASSWORD'} $config{'uploadPHP'}{'PROXY_IP'} $config{'uploadPHP'}{'PROXY_PORT'}|";
|
||||||
|
while (<PHPOUT>) {
|
||||||
|
print $_; # PRINT CURRENT PHP OUPUT LINE
|
||||||
|
if ($_ =~ m/error/) {
|
||||||
|
$success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub WipeData {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
print "Deleting $data{$key}{'FILEPATH'}...";
|
||||||
|
unlink($data{$key}{'FILEPATH'}) or die "Could not delete $data{$key}{'FILEPATH'}!\n";
|
||||||
|
print " Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub AddToDB {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
$data{$key}{'TIMESTAMP_UPLOADED'} = &GetTimestamp('YMDHMS');
|
||||||
|
$db{$key} = $data{$key};
|
||||||
|
my $json = encode_json \%db;
|
||||||
|
write_file($config{'DBFilepath'}, { binmode => ':raw' }, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Delimiter {
|
||||||
|
my $SubName = shift;
|
||||||
|
print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetTimestamp {
|
||||||
|
#&Delimiter((caller(0))[3]);
|
||||||
|
my $switch = shift;
|
||||||
|
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
|
||||||
|
|
||||||
|
my $nice_timestamp;
|
||||||
|
if ($switch eq 'YMDHMS') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d_%02d%02d%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'YMD') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d", $year+1900,$mon+1,$mday);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'year') {
|
||||||
|
$nice_timestamp = $year+1900;
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'month') {
|
||||||
|
$nice_timestamp = $mon+10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Invalid/no switch detected. Use: 'YMDHMS' / 'YMD'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nice_timestamp;
|
||||||
|
}
|
||||||
253
instafeed/code_depricated/instafeed.pl
Executable file
253
instafeed/code_depricated/instafeed.pl
Executable file
@@ -0,0 +1,253 @@
|
|||||||
|
#!usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON::XS qw(encode_json decode_json);
|
||||||
|
use File::Slurp qw(read_file write_file);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
my %config = (
|
||||||
|
'profile' => undef,
|
||||||
|
'SRCRoot' => './src/',
|
||||||
|
'uploadPHP_CMD' => '/usr/bin/php ./vendor/mgp25/instagram-php/examples/uploadPhoto.php',
|
||||||
|
'uploadPHP_debug' => 1,
|
||||||
|
'uploadPHP_truncated_debug' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
my %profile = (
|
||||||
|
'dreamyourmansion' => {
|
||||||
|
'DBFilepath' => './src/db/db_dreamyourmansion.dat',
|
||||||
|
'imageDir' => './src/images/dreamyourmansion',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'dreamyourmansion',
|
||||||
|
'password' => 'nBLT!4H3aI@c',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#investment #immobilie #mansionhouse #dream #poolhouse #villa #realestate #loft #awesome #lifestyle #motivation #luxury',
|
||||||
|
'description_add' => "The most beautiful real estates in the world!\n\nBenefit from the flourishing housing market in Germany. Contact us now by DM.\n\nVom Mieter zum Eigentümer! Exklusives Portfolio: Kontaktiere uns jetzt per DM.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'vstbestprices',
|
||||||
|
'password' => 'Vst#1337vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices_testing' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'adobebestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_adobebestprices.dat',
|
||||||
|
'imageDir' => './src/images/adobebestprices/',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#adobe #photoshop #adobeillustrator #vector #illustrator #adobephotoshop #vectorart #graphicdesign #aftereffects #logo #cs6 #lightroom #graphic',
|
||||||
|
'description_add' => 'Photoshop, Lightroom, Illustrator, Dreamviewer, Premiere for WIN & MAC | Installation support is included in all our prices!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
my (%data, %db);
|
||||||
|
my $dbKeysStart = 0;
|
||||||
|
my $profile;
|
||||||
|
|
||||||
|
# MAIN
|
||||||
|
&CheckParameter();
|
||||||
|
&UndumpFromFile();
|
||||||
|
#print Dumper \%db;
|
||||||
|
&DirectoryListing();
|
||||||
|
print Dumper \%data;
|
||||||
|
&FindNewDataset();
|
||||||
|
&Summary();
|
||||||
|
|
||||||
|
sub CheckParameter {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
GetOptions ('profile=s' => \$config{'profile'}) or die "Usage: $0 --profile *name*\n";
|
||||||
|
die "Usage: $0 --profile *name*\n" if !$config{'profile'} ;
|
||||||
|
$profile = $config{'profile'};
|
||||||
|
if (!exists $profile{$profile}) {
|
||||||
|
print "Template for profile '$profile' does not exist. Following templates are available:\n";
|
||||||
|
print "'$_' " for keys(%profile);
|
||||||
|
print "\n";
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub UndumpFromFile {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
if (-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
my $json = read_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' });
|
||||||
|
if (!$json) {
|
||||||
|
warn "DB file $profile{$profile}{'DBFilepath'} is empty.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
%db = %{ decode_json $json };
|
||||||
|
$dbKeysStart = scalar(keys(%db));
|
||||||
|
print "INFO: $profile{$profile}{'DBFilepath'} has " . $dbKeysStart . " keys.\n";
|
||||||
|
}
|
||||||
|
elsif (!-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
print "INFO: NO DB file found at $profile{$profile}{'DBFilepath'}. Creating now... ";
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, '');
|
||||||
|
print "done.\n";
|
||||||
|
die "Please restart.";
|
||||||
|
# &UndumpFromFile();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub DirectoryListing {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
# opendir(DIR, $profile{$profile}{'imageDir'});
|
||||||
|
# my @files = grep(/\.jpg$|\.png$|\.jpeg$|/,readdir(DIR));
|
||||||
|
# closedir(DIR);
|
||||||
|
my @files = glob ( "$profile{$profile}{'imageDir'}/*" );
|
||||||
|
%data = map { $_ => { 'FILEPATH' => "$_" } } @files;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Summary {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
print "$profile{$profile}{'DBFilepath'} has " . scalar(keys(%db)) . " keys (before $dbKeysStart).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub FindNewDataset {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $key (keys %data) {
|
||||||
|
if (exists $db{$key}) {
|
||||||
|
print "OLD: $key\n";
|
||||||
|
}
|
||||||
|
elsif (!exists $db{$key}) {
|
||||||
|
print "NEW: $key\n";
|
||||||
|
|
||||||
|
my $success = &uploadPHP($data{$key}{'FILEPATH'});
|
||||||
|
&AddToDB($key);
|
||||||
|
&WipeData($key);
|
||||||
|
last;
|
||||||
|
# if ($success) {
|
||||||
|
# print "success is $success\n";
|
||||||
|
# &AddToDB($key);
|
||||||
|
# &WipeData($key);
|
||||||
|
# last;
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i == scalar(keys(%data))) {
|
||||||
|
warn "\nNO NEW FILES AVAILABLE.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uploadPHP {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $filepath = shift;
|
||||||
|
|
||||||
|
my $success = 1;
|
||||||
|
my $captionText = "$profile{$profile}{'uploadPHP'}{'description_add'}\n\n$profile{$profile}{'uploadPHP'}{'tags'}";
|
||||||
|
if ($profile{$profile}{'filename_as_title'}) {
|
||||||
|
my $filename = basename($filepath);
|
||||||
|
$filename =~ s/(NO INSTALL)|(SymLink Installer)//g;
|
||||||
|
$filename =~ s/( , )|(\.[^.]+$)//g;
|
||||||
|
$captionText = "$filename\n\n" . $captionText;
|
||||||
|
# print Dumper $captionText;
|
||||||
|
}
|
||||||
|
open PHPOUT, "$config{'uploadPHP_CMD'} \'$filepath\' \'$captionText\' $profile{$profile}{'uploadPHP'}{'username'} $profile{$profile}{'uploadPHP'}{'password'} $config{'uploadPHP_debug'} $config{'uploadPHP_truncated_debug'} $profile{$profile}{'uploadPHP'}{'proxy_user'} $profile{$profile}{'uploadPHP'}{'proxy_password'} $profile{$profile}{'uploadPHP'}{'proxy_ip'} $profile{$profile}{'uploadPHP'}{'proxy_port'}|";
|
||||||
|
while (<PHPOUT>) {
|
||||||
|
print $_; # PRINT CURRENT PHP OUPUT LINE
|
||||||
|
if ($_ =~ m/error/) {
|
||||||
|
$success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub WipeData {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
print "Deleting $data{$key}{'FILEPATH'}...";
|
||||||
|
unlink($data{$key}{'FILEPATH'}) or die "Could not delete $data{$key}{'FILEPATH'}!\n";
|
||||||
|
print " Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub AddToDB {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
$data{$key}{'TIMESTAMP_UPLOADED'} = &GetTimestamp('YMDHMS');
|
||||||
|
$db{$key} = $data{$key};
|
||||||
|
my $json = encode_json \%db;
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' }, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Delimiter {
|
||||||
|
my $SubName = shift;
|
||||||
|
print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetTimestamp {
|
||||||
|
#&Delimiter((caller(0))[3]);
|
||||||
|
my $switch = shift;
|
||||||
|
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
|
||||||
|
|
||||||
|
my $nice_timestamp;
|
||||||
|
if ($switch eq 'YMDHMS') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d_%02d%02d%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'YMD') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d", $year+1900,$mon+1,$mday);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'year') {
|
||||||
|
$nice_timestamp = $year+1900;
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'month') {
|
||||||
|
$nice_timestamp = $mon+10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Invalid/no switch detected. Use: 'YMDHMS' / 'YMD'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nice_timestamp;
|
||||||
|
}
|
||||||
5
instafeed/composer.json
Executable file
5
instafeed/composer.json
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"mgp25/instagram-php": "^7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
1294
instafeed/composer.lock
generated
Executable file
1294
instafeed/composer.lock
generated
Executable file
File diff suppressed because it is too large
Load Diff
0
instafeed/foo
Executable file
0
instafeed/foo
Executable file
261
instafeed/instafeed.pl
Executable file
261
instafeed/instafeed.pl
Executable file
@@ -0,0 +1,261 @@
|
|||||||
|
#!usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
use JSON::XS qw(encode_json decode_json);
|
||||||
|
use File::Slurp qw(read_file write_file);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
use File::Basename;
|
||||||
|
use HTTP::Cookies;
|
||||||
|
use Cwd qw(cwd);
|
||||||
|
|
||||||
|
my %config = (
|
||||||
|
'profile' => undef,
|
||||||
|
'SRCRoot' => './src/',
|
||||||
|
'uploadPHP_CMD' => '/usr/bin/php ./vendor/mgp25/instagram-php/examples/uploadPhoto.php',
|
||||||
|
'uploadPHP_debug' => 1,
|
||||||
|
'uploadPHP_truncated_debug' => 1,
|
||||||
|
'uploadPHP_autoload' => cwd . '/src/mpg25-instagram-api/vendor/autoload.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
my %profile = (
|
||||||
|
'dreamyourmansion' => {
|
||||||
|
'DBFilepath' => './src/db/db_dreamyourmansion.dat',
|
||||||
|
'imageDir' => './src/images/dreamyourmansion',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'dreamyourmansion',
|
||||||
|
'password' => 'nBLT!4H3aI@c',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de786.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#investment #immobilie #mansionhouse #dream #poolhouse #villa #realestate #loft #awesome #lifestyle #motivation #luxury',
|
||||||
|
'description_add' => "The most beautiful real estates in the world!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'vstbestprices',
|
||||||
|
'password' => 'Vst#1337vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'vstbestprices_testing' => {
|
||||||
|
'DBFilepath' => './src/db/db_vstbestprices.dat',
|
||||||
|
'imageDir' => './src/images/vstbestprices',
|
||||||
|
'filename_as_title' => 1,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#Beats #FLStudio20 #Producer #Ableton #Beatmaker #Studio #ProTools #Music #DAW #LogicPro #FruityLoops #VST #VSTplugins #NativeInstruments #MIDI #Drums #AutoTune #Spectrasonics #Omnisphere #AutoTune #Plugins #Keyscape #Trilian #Logic',
|
||||||
|
'description_add' => 'INSTALLATION SUPPORT is included in all prices so you can relax and focus on producing!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'adobebestprices' => {
|
||||||
|
'DBFilepath' => './src/db/db_adobebestprices.dat',
|
||||||
|
'imageDir' => './src/images/adobebestprices/',
|
||||||
|
'filename_as_title' => 0,
|
||||||
|
'uploadPHP' => {
|
||||||
|
'username' => 'adobebestprices',
|
||||||
|
'password' => 'vst#1337',
|
||||||
|
'truncated_debug' => 1,
|
||||||
|
'proxy_user' => 'zino%40onlinehome.de',
|
||||||
|
'proxy_password' => 'zinomedial33t',
|
||||||
|
'proxy_ip' => 'de435.nordvpn.com',
|
||||||
|
'proxy_port' => 80,
|
||||||
|
'tags' => '#adobe #photoshop #adobeillustrator #vector #illustrator #adobephotoshop #vectorart #graphicdesign #aftereffects #logo #cs6 #lightroom #graphic',
|
||||||
|
'description_add' => 'Photoshop, Lightroom, Illustrator, Dreamviewer, Premiere for WIN & MAC | Installation support is included in all our prices!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
my (%data, %db);
|
||||||
|
my $dbKeysStart = 0;
|
||||||
|
my $profile;
|
||||||
|
|
||||||
|
# MAIN
|
||||||
|
&CheckParameter();
|
||||||
|
&UndumpFromFile();
|
||||||
|
#print Dumper \%db;
|
||||||
|
&DirectoryListing();
|
||||||
|
print Dumper \%data;
|
||||||
|
&FindNewDataset();
|
||||||
|
&Summary();
|
||||||
|
|
||||||
|
sub CheckParameter {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
GetOptions ('profile=s' => \$config{'profile'}) or die &PrintUsage();
|
||||||
|
die &PrintUsage() if !$config{'profile'};
|
||||||
|
$profile = $config{'profile'};
|
||||||
|
if (!exists $profile{$profile}) {
|
||||||
|
print "Profile '$profile' does not exist.\n";
|
||||||
|
&PrintUsage();
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub PrintUsage {
|
||||||
|
print "Usage: $0 --profile *name*\n";
|
||||||
|
print "Following profiles are available:\n";
|
||||||
|
print "* '$_'\n" for keys(%profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub UndumpFromFile {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
if (-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
my $json = read_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' });
|
||||||
|
if (!$json) {
|
||||||
|
warn "DB file $profile{$profile}{'DBFilepath'} is empty.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
%db = %{ decode_json $json };
|
||||||
|
$dbKeysStart = scalar(keys(%db));
|
||||||
|
print "INFO: $profile{$profile}{'DBFilepath'} has " . $dbKeysStart . " keys.\n";
|
||||||
|
}
|
||||||
|
elsif (!-e $profile{$profile}{'DBFilepath'}) {
|
||||||
|
print "INFO: NO DB file found at $profile{$profile}{'DBFilepath'}. Creating now... ";
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, '');
|
||||||
|
print "done.\n";
|
||||||
|
die "Please restart.";
|
||||||
|
# &UndumpFromFile();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub DirectoryListing {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
# opendir(DIR, $profile{$profile}{'imageDir'});
|
||||||
|
# my @files = grep(/\.jpg$|\.png$|\.jpeg$|/,readdir(DIR));
|
||||||
|
# closedir(DIR);
|
||||||
|
my @files = glob ( "$profile{$profile}{'imageDir'}/*" );
|
||||||
|
%data = map { $_ => { 'FILEPATH' => "$_" } } @files;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Summary {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
print "$profile{$profile}{'DBFilepath'} has " . scalar(keys(%db)) . " keys (before $dbKeysStart).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub FindNewDataset {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for my $key (keys %data) {
|
||||||
|
if (exists $db{$key}) {
|
||||||
|
print "OLD: $key\n";
|
||||||
|
}
|
||||||
|
elsif (!exists $db{$key}) {
|
||||||
|
print "NEW: $key\n";
|
||||||
|
|
||||||
|
my $success = &uploadPHP($data{$key}{'FILEPATH'});
|
||||||
|
&AddToDB($key);
|
||||||
|
&WipeData($key);
|
||||||
|
last;
|
||||||
|
# if ($success) {
|
||||||
|
# print "success is $success\n";
|
||||||
|
# &AddToDB($key);
|
||||||
|
# &WipeData($key);
|
||||||
|
# last;
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i == scalar(keys(%data))) {
|
||||||
|
warn "\nNO NEW FILES AVAILABLE.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uploadPHP {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $filepath = shift;
|
||||||
|
|
||||||
|
my $success = 1;
|
||||||
|
my $captionText = "$profile{$profile}{'uploadPHP'}{'description_add'}\n\n$profile{$profile}{'uploadPHP'}{'tags'}";
|
||||||
|
if ($profile{$profile}{'filename_as_title'}) {
|
||||||
|
my $filename = basename($filepath);
|
||||||
|
$filename =~ s/(NO INSTALL)|(SymLink Installer)//g;
|
||||||
|
$filename =~ s/( , )|(\.[^.]+$)//g;
|
||||||
|
$captionText = "$filename\n\n" . $captionText;
|
||||||
|
# print Dumper $captionText;
|
||||||
|
}
|
||||||
|
open PHPOUT, "$config{'uploadPHP_CMD'} \'$filepath\' \'$captionText\' $profile{$profile}{'uploadPHP'}{'username'} $profile{$profile}{'uploadPHP'}{'password'} $config{'uploadPHP_debug'} $config{'uploadPHP_truncated_debug'} $profile{$profile}{'uploadPHP'}{'proxy_user'} $profile{$profile}{'uploadPHP'}{'proxy_password'} $profile{$profile}{'uploadPHP'}{'proxy_ip'} $profile{$profile}{'uploadPHP'}{'proxy_port'} \'$config{'uploadPHP_autoload'}\'|";
|
||||||
|
while (<PHPOUT>) {
|
||||||
|
print $_; # PRINT CURRENT PHP OUPUT LINE
|
||||||
|
if ($_ =~ m/error/) {
|
||||||
|
$success = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub WipeData {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
print "Deleting $data{$key}{'FILEPATH'}...";
|
||||||
|
unlink($data{$key}{'FILEPATH'}) or die "Could not delete $data{$key}{'FILEPATH'}!\n";
|
||||||
|
print " Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub AddToDB {
|
||||||
|
&Delimiter((caller(0))[3]);
|
||||||
|
my $key = shift;
|
||||||
|
|
||||||
|
$data{$key}{'TIMESTAMP_UPLOADED'} = &GetTimestamp('YMDHMS');
|
||||||
|
$db{$key} = $data{$key};
|
||||||
|
my $json = encode_json \%db;
|
||||||
|
write_file($profile{$profile}{'DBFilepath'}, { binmode => ':raw' }, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Delimiter {
|
||||||
|
my $SubName = shift;
|
||||||
|
print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub GetTimestamp {
|
||||||
|
#&Delimiter((caller(0))[3]);
|
||||||
|
my $switch = shift;
|
||||||
|
|
||||||
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
|
||||||
|
|
||||||
|
my $nice_timestamp;
|
||||||
|
if ($switch eq 'YMDHMS') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d_%02d%02d%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'YMD') {
|
||||||
|
$nice_timestamp = sprintf ( "%04d%02d%02d", $year+1900,$mon+1,$mday);
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'year') {
|
||||||
|
$nice_timestamp = $year+1900;
|
||||||
|
}
|
||||||
|
elsif ($switch eq 'month') {
|
||||||
|
$nice_timestamp = $mon+10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "Invalid/no switch detected. Use: 'YMDHMS' / 'YMD'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nice_timestamp;
|
||||||
|
}
|
||||||
23
instafeed/log/dreamyourmansion.log
Executable file
23
instafeed/log/dreamyourmansion.log
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::CheckParameter
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::UndumpFromFile
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
INFO: ./src/db/db_dreamyourmansion.dat has 191 keys.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::DirectoryListing
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
$VAR1 = {};
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::FindNewDataset
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::Summary
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
./src/db/db_dreamyourmansion.dat has 191 keys (before 191).
|
||||||
23
instafeed/log/vstbestprices.log
Executable file
23
instafeed/log/vstbestprices.log
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::CheckParameter
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::UndumpFromFile
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
INFO: ./src/db/db_vstbestprices.dat has 115 keys.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::DirectoryListing
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
$VAR1 = {};
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::FindNewDataset
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
SUB main::Summary
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
./src/db/db_vstbestprices.dat has 115 keys (before 115).
|
||||||
1
instafeed/src/db/db_dreamyourmansion.dat
Executable file
1
instafeed/src/db/db_dreamyourmansion.dat
Executable file
File diff suppressed because one or more lines are too long
1
instafeed/src/db/db_vstbestprices.dat
Executable file
1
instafeed/src/db/db_vstbestprices.dat
Executable file
File diff suppressed because one or more lines are too long
BIN
instafeed/src/images/dreamyourmansion/7VPFyhB_j8Y.jpg
Executable file
BIN
instafeed/src/images/dreamyourmansion/7VPFyhB_j8Y.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 265 KiB |
BIN
instafeed/src/images/dreamyourmansion/RKdLlTyjm5g.jpg
Executable file
BIN
instafeed/src/images/dreamyourmansion/RKdLlTyjm5g.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
BIN
instafeed/src/images/dreamyourmansion/UV81E0oXXWQ.jpg
Executable file
BIN
instafeed/src/images/dreamyourmansion/UV81E0oXXWQ.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
7
instafeed/vendor/autoload.php
vendored
Executable file
7
instafeed/vendor/autoload.php
vendored
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit331ae81537359437b02a96bc74f11b80::getLoader();
|
||||||
738
instafeed/vendor/bin/lazydoctor
vendored
Executable file
738
instafeed/vendor/bin/lazydoctor
vendored
Executable file
@@ -0,0 +1,738 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright 2017 The LazyJsonMapper Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Lazy Doctor.
|
||||||
|
*
|
||||||
|
* This tool automatically builds up-to-date class documentation for all classes
|
||||||
|
* that derive from LazyJsonMapper, and documents their virtual properties and
|
||||||
|
* functions by adding "@property" and "@method" declarations to their class
|
||||||
|
* PHPdoc blocks. That documentation is necessary for things like code analysis
|
||||||
|
* tools and IDE autocomplete for all of your virtual properties/functions!
|
||||||
|
*
|
||||||
|
* LazyDoctor also performs class diagnostics: It compiles the class property
|
||||||
|
* maps of _all_ of your LazyJsonMapper-based classes, which means that you can
|
||||||
|
* be 100% sure that all of your maps are valid if this tool runs successfully.
|
||||||
|
*
|
||||||
|
* To see all available options, type "./vendor/bin/lazydoctor --help".
|
||||||
|
*
|
||||||
|
* To begin, simply point the "--composer" option at the "composer.json" file
|
||||||
|
* for your project. Just be aware that your project MUST be based on PSR-4
|
||||||
|
* autoloading, with ONE OR MORE defined autoload-namespaces in "composer.json".
|
||||||
|
*
|
||||||
|
* You can read more about PSR-4 autoloading at the official Composer site:
|
||||||
|
*
|
||||||
|
* https://getcomposer.org/doc/04-schema.md#autoload
|
||||||
|
*
|
||||||
|
* This tool will ONLY parse classes that properly follow PSR-4 autoloading!
|
||||||
|
*
|
||||||
|
* In addition to the composer-file, you'll also have to specify whether you
|
||||||
|
* want to document virtual "--properties", virtual "--functions", or BOTH.
|
||||||
|
* Note that we'll ONLY document them when the individual classes support that
|
||||||
|
* kind of access (when it hasn't disabled its class-option for that feature).
|
||||||
|
*
|
||||||
|
* If you don't provide any documentation flags, we'll instead REMOVE all of
|
||||||
|
* the current class "virtual @property/@method" documentation. That can be
|
||||||
|
* useful for restoring your files if you don't want to document them anymore.
|
||||||
|
*
|
||||||
|
* You should also be aware of "--document-overridden", which will document
|
||||||
|
* virtual properties or functions even if they're already manually defined
|
||||||
|
* (overridden) by the class or its parents. That can be useful if you want to
|
||||||
|
* ensure that you ALWAYS document the virtual properties/functions in all of
|
||||||
|
* your class files even when it has been overridden somewhere. In that case,
|
||||||
|
* you should ensure that your overridden properties/functions have the SAME or
|
||||||
|
* a COMPATIBLE signature & return value, so their auto-docs are still correct.
|
||||||
|
*
|
||||||
|
* Tip: You can use the "--validate-only" param to check docs without writing to
|
||||||
|
* disk. That can be useful when making a non-destructive Git "pre-commit hook"
|
||||||
|
* to validate your repo and ensure that all files have updated documentation!
|
||||||
|
*
|
||||||
|
* This script always uses exit codes to indicate success. A non-zero exit code
|
||||||
|
* indicates that some files needed new class docs (in "--validate-only" mode),
|
||||||
|
* or that there was a general problem while processing.
|
||||||
|
*
|
||||||
|
* Lastly, you may appreciate the ability to silence all unimportant status
|
||||||
|
* messages! To do so, simply use ">/dev/null" to send STDOUT to the void...
|
||||||
|
* That way you'll ONLY see critical status messages during the processing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
date_default_timezone_set('UTC');
|
||||||
|
|
||||||
|
// Verify minimum PHP version.
|
||||||
|
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50600) {
|
||||||
|
fwrite(STDERR, 'LazyDoctor requires PHP 5.6 or higher.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a simple GetOptionKit autoloader. This is fine because
|
||||||
|
// GetOptionKit has no 3rd party library dependencies.
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
// Check if this is a "GetOptionKit" load-request.
|
||||||
|
static $prefix = 'GetOptionKit\\';
|
||||||
|
static $len = 13; // strlen($prefix)
|
||||||
|
if (strncmp($prefix, $class, $len) !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the "GetOptionKit" source folder.
|
||||||
|
static $dirs = [
|
||||||
|
__DIR__.'/../../../corneltek/getoptionkit/src',
|
||||||
|
__DIR__.'/../vendor/corneltek/getoptionkit/src',
|
||||||
|
];
|
||||||
|
$baseDir = null;
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (is_dir($dir) && ($dir = realpath($dir)) !== false) {
|
||||||
|
$baseDir = $dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($baseDir === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the relative class name.
|
||||||
|
$relativeClass = substr($class, $len);
|
||||||
|
|
||||||
|
// Generate PSR-4 file path to the class.
|
||||||
|
$file = sprintf('%s/%s.php', $baseDir, str_replace('\\', '/', $relativeClass));
|
||||||
|
if (is_file($file)) {
|
||||||
|
require $file;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parse command line options...
|
||||||
|
use GetOptionKit\OptionCollection;
|
||||||
|
use GetOptionKit\OptionParser;
|
||||||
|
use GetOptionKit\OptionPrinter\ConsoleOptionPrinter;
|
||||||
|
|
||||||
|
$specs = new OptionCollection();
|
||||||
|
$specs->add('c|composer:=file', 'Path to your project\'s composer.json file.');
|
||||||
|
$specs->add('p|properties?=boolean', 'Document virtual properties (if enabled for the classes).');
|
||||||
|
$specs->add('f|functions?=boolean', 'Document virtual functions (if enabled for the classes).');
|
||||||
|
$specs->add('o|document-overridden?=boolean', 'Always document virtual functions/properties even when they have been manually overridden by the class (or its parents).');
|
||||||
|
$specs->add('w|windows?=boolean', 'Generate Windows-style ("\r\n") documentation line endings instead of the default Unix-style ("\n").');
|
||||||
|
$specs->add('validate-only?=boolean', 'Validate current docs for all classes but don\'t write anything to disk.');
|
||||||
|
$specs->add('h|help?=boolean', 'Show all available options.');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$parser = new OptionParser($specs);
|
||||||
|
$result = $parser->parse($argv);
|
||||||
|
$options = [
|
||||||
|
'composer' => isset($result->keys['composer']) ? $result->keys['composer']->value : null,
|
||||||
|
'properties' => isset($result->keys['properties']) && $result->keys['properties']->value !== false,
|
||||||
|
'functions' => isset($result->keys['functions']) && $result->keys['functions']->value !== false,
|
||||||
|
'document-overridden' => isset($result->keys['document-overridden']) && $result->keys['document-overridden']->value !== false,
|
||||||
|
'windows' => isset($result->keys['windows']) && $result->keys['windows']->value !== false,
|
||||||
|
'validate-only' => isset($result->keys['validate-only']) && $result->keys['validate-only']->value !== false,
|
||||||
|
'help' => isset($result->keys['help']) && $result->keys['help']->value !== false,
|
||||||
|
];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Warns in case of invalid option values.
|
||||||
|
fwrite(STDERR, $e->getMessage().PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify options...
|
||||||
|
echo '[ LazyDoctor ]'.PHP_EOL.PHP_EOL;
|
||||||
|
if ($options['composer'] === null || $options['help']) {
|
||||||
|
if ($options['composer'] === null) {
|
||||||
|
fwrite(STDERR, 'You must provide the --composer option.'.PHP_EOL.PHP_EOL);
|
||||||
|
}
|
||||||
|
$printer = new ConsoleOptionPrinter();
|
||||||
|
echo 'Available options:'.PHP_EOL.PHP_EOL;
|
||||||
|
echo $printer->render($specs);
|
||||||
|
exit($options['composer'] === null && !$options['help'] ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options['composer']->getBasename() !== 'composer.json') {
|
||||||
|
fwrite(STDERR, 'You must point to your project\'s composer.json file.'.PHP_EOL.'You used: "'.$options['composer']->getRealPath().'".'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the composer.json file...
|
||||||
|
$json = @json_decode(file_get_contents($options['composer']->getRealPath()), true);
|
||||||
|
if ($json === null) {
|
||||||
|
fwrite(STDERR, 'Unable to decode composer.json.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the project folder's real root path...
|
||||||
|
$projectRoot = $options['composer']->getPathInfo()->getRealPath();
|
||||||
|
|
||||||
|
// Determine their namespace PSR-4 paths via their project's composer.json...
|
||||||
|
$namespaces = [];
|
||||||
|
foreach (['autoload', 'autoload-dev'] as $type) {
|
||||||
|
if (!isset($json[$type]['psr-4']) || !is_array($json[$type]['psr-4'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($json[$type]['psr-4'] as $namespace => $dir) {
|
||||||
|
// We don't support composer's empty "fallback" namespaces.
|
||||||
|
if ($namespace === '') {
|
||||||
|
fwrite(STDERR, 'Encountered illegal unnamed PSR-4 autoload namespace in composer.json.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the namespace ends in backslash.
|
||||||
|
if (substr_compare($namespace, '\\', strlen($namespace) - 1, 1) !== 0) {
|
||||||
|
fwrite(STDERR, 'Encountered illegal namespace "'.$namespace.'" (does not end in backslash) in composer.json.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the value is a string.
|
||||||
|
// NOTE: We allow empty strings, which corresponds to root folder.
|
||||||
|
if (!is_string($dir)) {
|
||||||
|
fwrite(STDERR, 'Encountered illegal non-string value for namespace "'.$namespace.'".'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now resolve the path name...
|
||||||
|
$path = sprintf('%s/%s', $projectRoot, $dir);
|
||||||
|
$realpath = realpath($path);
|
||||||
|
if ($realpath === false) {
|
||||||
|
fwrite(STDERR, 'Unable to resolve real path for "'.$path.'".'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't allow the same directory to be defined multiple times.
|
||||||
|
if (isset($namespaces[$realpath])) {
|
||||||
|
fwrite(STDERR, 'Encountered duplicate namespace directory "'.$realpath.'" in composer.json.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// And we're done! The namespace and its path have been resolved.
|
||||||
|
$namespaces[$realpath] = $namespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that we found some namespaces...
|
||||||
|
if (empty($namespaces)) {
|
||||||
|
fwrite(STDERR, 'There are no PSR-4 autoload namespaces in your composer.json.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now load the project's autoload.php file.
|
||||||
|
// NOTE: This is necessary so that we can autoload their classes...
|
||||||
|
$autoload = sprintf('%s/vendor/autoload.php', $projectRoot);
|
||||||
|
$realautoload = realpath($autoload);
|
||||||
|
if ($realautoload === false) {
|
||||||
|
fwrite(STDERR, 'Unable to find the project\'s Composer autoloader ("'.$autoload.'").'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
require $realautoload;
|
||||||
|
|
||||||
|
// Verify that their project's autoloader contains LazyJsonMapper...
|
||||||
|
if (!class_exists('\LazyJsonMapper\LazyJsonMapper', true)) { // TRUE = Autoload.
|
||||||
|
fwrite(STDERR, 'Target project doesn\'t contain the LazyJsonMapper library.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alright, display the current options...
|
||||||
|
echo 'Project: "'.$projectRoot.'".'.PHP_EOL
|
||||||
|
.'- Documentation Line Endings: '.($options['windows'] ? 'Windows ("\r\n")' : 'Unix ("\n")').'.'.PHP_EOL
|
||||||
|
.'- ['.($options['properties'] ? 'X' : ' ').'] Document Virtual Properties ("@property").'.PHP_EOL
|
||||||
|
.'- ['.($options['functions'] ? 'X' : ' ').'] Document Virtual Functions ("@method").'.PHP_EOL
|
||||||
|
.'- ['.($options['document-overridden'] ? 'X' : ' ').'] Document Overridden Properties/Functions.'.PHP_EOL;
|
||||||
|
if ($options['validate-only']) {
|
||||||
|
echo '- This is a validation run. Nothing will be written to disk.'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can now use our custom classes, since the autoloader has been imported...
|
||||||
|
use LazyJsonMapper\Exception\LazyJsonMapperException;
|
||||||
|
use LazyJsonMapper\Export\PropertyDescription;
|
||||||
|
use LazyJsonMapper\Property\PropertyMapCache;
|
||||||
|
use LazyJsonMapper\Property\PropertyMapCompiler;
|
||||||
|
use LazyJsonMapper\Utilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatic LazyJsonMapper-class documentation generator.
|
||||||
|
*
|
||||||
|
* @copyright 2017 The LazyJsonMapper Project
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* @author SteveJobzniak (https://github.com/SteveJobzniak)
|
||||||
|
*/
|
||||||
|
class LazyClassDocumentor
|
||||||
|
{
|
||||||
|
/** @var PropertyMapCache */
|
||||||
|
private static $_propertyMapCache;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $_compiledPropertyMapLink;
|
||||||
|
|
||||||
|
/** @var ReflectionClass */
|
||||||
|
private $_reflector;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $_options;
|
||||||
|
|
||||||
|
/** @var string Newline sequence. */
|
||||||
|
private $_nl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $class
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @throws ReflectionException
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$class,
|
||||||
|
array $options)
|
||||||
|
{
|
||||||
|
if (self::$_propertyMapCache === null) {
|
||||||
|
self::$_propertyMapCache = new PropertyMapCache();
|
||||||
|
}
|
||||||
|
$this->_reflector = new ReflectionClass($class);
|
||||||
|
$this->_options = $options;
|
||||||
|
$this->_nl = $options['windows'] ? "\r\n" : "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the current class.
|
||||||
|
*
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws LazyJsonMapperException
|
||||||
|
*
|
||||||
|
* @return bool `TRUE` if on-disk file has correct docs, otherwise `FALSE`.
|
||||||
|
*/
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
// Only process user-defined classes (never any built-in PHP classes).
|
||||||
|
if (!$this->_reflector->isUserDefined()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's nothing to do if this isn't a LazyJsonMapper subclass.
|
||||||
|
// NOTE: This properly skips "\LazyJsonMapper\LazyJsonMapper" itself.
|
||||||
|
if (!$this->_reflector->isSubclassOf('\LazyJsonMapper\LazyJsonMapper')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile this class property map if not yet built and cached.
|
||||||
|
$thisClassName = $this->_reflector->getName();
|
||||||
|
if (!isset(self::$_propertyMapCache->classMaps[$thisClassName])) {
|
||||||
|
try {
|
||||||
|
PropertyMapCompiler::compileClassPropertyMap( // Throws.
|
||||||
|
self::$_propertyMapCache,
|
||||||
|
$thisClassName
|
||||||
|
);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
fwrite(STDERR, '> Unable to compile the class property map for "'.$thisClassName.'". Reason: '.$e->getMessage().PHP_EOL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now link to the property map cache for our current class.
|
||||||
|
$this->_compiledPropertyMapLink = &self::$_propertyMapCache->classMaps[$thisClassName];
|
||||||
|
|
||||||
|
// Get the current class comment (string if ok, FALSE if none exists).
|
||||||
|
$currentDocComment = $this->_reflector->getDocComment();
|
||||||
|
if (is_string($currentDocComment)) {
|
||||||
|
$currentDocComment = trim($currentDocComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract all relevant lines from the current comment.
|
||||||
|
$finalDocLines = $this->_extractRelevantLines($currentDocComment);
|
||||||
|
|
||||||
|
// Generate the automatic summary line (classname followed by period).
|
||||||
|
$autoSummaryLine = $this->_reflector->getShortName().'.';
|
||||||
|
|
||||||
|
// If the 1st line is a classname followed by a period, update the name.
|
||||||
|
// NOTE: This ensures that we update all outdated auto-added classnames,
|
||||||
|
// and the risk of false positives is very low since we only document
|
||||||
|
// `LazyJsonMapper`-based classes with a `OneWord.`-style summary line.
|
||||||
|
// NOTE: Regex is from http://php.net/manual/en/language.oop5.basic.php,
|
||||||
|
// and yes we must run it in NON-UNICODE MODE, so that it parses on a
|
||||||
|
// byte by byte basis exactly like the real PHP classname interpreter.
|
||||||
|
if (
|
||||||
|
isset($finalDocLines[0]) // The 1st line MUST exist to proceed.
|
||||||
|
&& preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\.$/', $finalDocLines[0])
|
||||||
|
) {
|
||||||
|
$finalDocLines[0] = $autoSummaryLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the magic documentation lines for the current class.
|
||||||
|
$magicDocLines = $this->_generateMagicDocs();
|
||||||
|
if (!empty($magicDocLines)) {
|
||||||
|
// If there are no lines already... add the automatic summary line.
|
||||||
|
if (empty($finalDocLines)) {
|
||||||
|
$finalDocLines[] = $autoSummaryLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the 1st char of the 1st line. If it's an @tag of any kind,
|
||||||
|
// insert automatic summary line at top and empty line after that.
|
||||||
|
elseif ($finalDocLines[0][0] === '@') {
|
||||||
|
array_unshift(
|
||||||
|
$finalDocLines,
|
||||||
|
$autoSummaryLine,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$finalDocLines[] = ''; // Add empty line before our magic docs.
|
||||||
|
$finalDocLines = array_merge($finalDocLines, array_values($magicDocLines));
|
||||||
|
}
|
||||||
|
unset($magicDocLines);
|
||||||
|
|
||||||
|
// Generate the final doc-comment that this class is supposed to have.
|
||||||
|
if (!empty($finalDocLines)) {
|
||||||
|
// This will generate even if the class only contained an existing
|
||||||
|
// summary/tags and nothing was added by our magic handler.
|
||||||
|
foreach ($finalDocLines as &$line) {
|
||||||
|
$line = ($line === '' ? ' *' : " * {$line}");
|
||||||
|
}
|
||||||
|
unset($line);
|
||||||
|
$finalDocComment = sprintf(
|
||||||
|
'/**%s%s%s */',
|
||||||
|
$this->_nl,
|
||||||
|
implode($this->_nl, $finalDocLines),
|
||||||
|
$this->_nl
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// The FALSE signifies that we want no class doc-block at all...
|
||||||
|
$finalDocComment = false;
|
||||||
|
}
|
||||||
|
unset($finalDocLines);
|
||||||
|
|
||||||
|
// There's nothing to do if the doc-comment is already correct.
|
||||||
|
// NOTE: Both values are FALSE if no doc-comment exists and none wanted.
|
||||||
|
if ($currentDocComment === $finalDocComment) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The docs mismatch. If this is a validate-run, just return false now.
|
||||||
|
if ($this->_options['validate-only']) {
|
||||||
|
fwrite(STDERR, '> Outdated class docs encountered in "'.$thisClassName.'". Aborting scan...'.PHP_EOL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the contents of the file...
|
||||||
|
$classFileName = $this->_reflector->getFileName();
|
||||||
|
$fileLines = @file($classFileName);
|
||||||
|
if ($fileLines === false) {
|
||||||
|
fwrite(STDERR, '> Unable to read class file from disk: "'.$classFileName.'".'.PHP_EOL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the file into lines BEFORE the class and lines AFTER the class.
|
||||||
|
$classLine = $this->_reflector->getStartLine();
|
||||||
|
$startLines = array_slice($fileLines, 0, $classLine - 1);
|
||||||
|
$endLines = array_slice($fileLines, $classLine - 1);
|
||||||
|
unset($fileLines);
|
||||||
|
|
||||||
|
// Insert the new class documentation using a very careful algorithm.
|
||||||
|
if ($currentDocComment !== false) {
|
||||||
|
// Since the class already had PHPdoc, remove it and insert new doc.
|
||||||
|
// NOTE: A valid PHPdoc (getDocComment()) always starts with
|
||||||
|
// "/**[whitespace]". If it's just a "/*" or something like
|
||||||
|
// "/**Foo", then it's not detected by getDocComment(). However, the
|
||||||
|
// comment may be several lines above the class. So we'll have to do
|
||||||
|
// an intelligent search to find the old class-comment. As for the
|
||||||
|
// ending tag "*/", PHP doesn't care about whitespace around that.
|
||||||
|
// And it also doesn't let the user escape the "*/", which means
|
||||||
|
// that if we see that sequence we KNOW it's the end of a comment!
|
||||||
|
// NOTE: We'll search for the latest "/**[whitespace]" block and
|
||||||
|
// remove all lines from that until its closest "*/".
|
||||||
|
$deleteFrom = null;
|
||||||
|
$deleteTo = null;
|
||||||
|
for ($i = count($startLines) - 1; $i >= 0; --$i) {
|
||||||
|
if (strpos($startLines[$i], '*/') !== false) {
|
||||||
|
$deleteTo = $i;
|
||||||
|
}
|
||||||
|
if (preg_match('/^\s*\/\*\*\s/u', $startLines[$i])) {
|
||||||
|
$deleteFrom = $i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that we have found valid comment-offsets.
|
||||||
|
if ($deleteFrom === null || $deleteTo === null || $deleteTo < $deleteFrom) {
|
||||||
|
fwrite(STDERR, '> Unable to parse current class comment on disk: "'.$classFileName.'".'.PHP_EOL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now update the startLines array to replace the doc-comment...
|
||||||
|
foreach ($startLines as $k => $v) {
|
||||||
|
if ($k === $deleteFrom && $finalDocComment !== false) {
|
||||||
|
// We've found the first line of the old comment, and we
|
||||||
|
// have a new comment. So replace that array entry.
|
||||||
|
$startLines[$k] = $finalDocComment.$this->_nl;
|
||||||
|
} elseif ($k >= $deleteFrom && $k <= $deleteTo) {
|
||||||
|
// Delete all other comment lines, including the first line
|
||||||
|
// if we had no new doc-comment.
|
||||||
|
unset($startLines[$k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break if we've reached the final line to delete.
|
||||||
|
if ($k >= $deleteTo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($finalDocComment !== false) {
|
||||||
|
// There's no existing doc-comment. Just add ours above the class.
|
||||||
|
// NOTE: This only does something if we had a new comment to insert,
|
||||||
|
// which we SHOULD have since we came this far in this scenario...
|
||||||
|
$startLines[] = $finalDocComment.$this->_nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the new file contents.
|
||||||
|
$newFileContent = implode($startLines).implode($endLines);
|
||||||
|
unset($startLines);
|
||||||
|
unset($endLines);
|
||||||
|
|
||||||
|
// Perform an atomic file-write to disk, which ensures that we will
|
||||||
|
// never be able to corrupt the class-files on disk via partial writes.
|
||||||
|
$written = Utilities::atomicWrite($classFileName, $newFileContent);
|
||||||
|
if ($written !== false) {
|
||||||
|
echo '> Wrote updated class documentation to disk: "'.$classFileName.'".'.PHP_EOL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
fwrite(STDERR, '> Unable to write new class documentation to disk: "'.$classFileName.'".'.PHP_EOL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts all relevant lines from a doc-comment.
|
||||||
|
*
|
||||||
|
* @param string $currentDocComment
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function _extractRelevantLines(
|
||||||
|
$currentDocComment)
|
||||||
|
{
|
||||||
|
if (!is_string($currentDocComment)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the leading and trailing doc-comment tags (/** and */).
|
||||||
|
$currentDocComment = preg_replace('/(^\s*\/\*\*\s*|\s*\*\/$)/u', '', $currentDocComment);
|
||||||
|
|
||||||
|
// Process all lines. Skip all @method and @property lines.
|
||||||
|
$relevantLines = [];
|
||||||
|
$lines = preg_split('/\r?\n|\r/u', $currentDocComment);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
// Remove leading and trailing whitespace, and leading asterisks.
|
||||||
|
$line = trim(preg_replace('/^\s*\*+/u', '', $line));
|
||||||
|
|
||||||
|
// Skip this line if it's a @method or @property line.
|
||||||
|
// NOTE: Removing them is totally safe, because the LazyJsonMapper
|
||||||
|
// class has marked all of its magic property/function handlers as
|
||||||
|
// final, which means that people's subclasses CANNOT override them
|
||||||
|
// to add their own magic methods/properties. So therefore we KNOW
|
||||||
|
// that ALL existing @method/@property class doc lines belong to us!
|
||||||
|
if (preg_match('/^@(?:method|property)/u', $line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$relevantLines[] = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing empty lines from the relevant lines.
|
||||||
|
for ($i = count($relevantLines) - 1; $i >= 0; --$i) {
|
||||||
|
if ($relevantLines[$i] === '') {
|
||||||
|
unset($relevantLines[$i]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove leading empty lines from the relevant lines.
|
||||||
|
foreach ($relevantLines as $k => $v) {
|
||||||
|
if ($v !== '') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($relevantLines[$k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a re-indexed (properly 0-indexed) array.
|
||||||
|
return array_values($relevantLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate PHPdoc lines for all magic properties and functions.
|
||||||
|
*
|
||||||
|
* @throws ReflectionException
|
||||||
|
* @throws LazyJsonMapperException
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function _generateMagicDocs()
|
||||||
|
{
|
||||||
|
// Check whether we should (and can) document properties and functions.
|
||||||
|
$documentProperties = $this->_options['properties'] && $this->_reflector->getConstant('ALLOW_VIRTUAL_PROPERTIES');
|
||||||
|
$documentFunctions = $this->_options['functions'] && $this->_reflector->getConstant('ALLOW_VIRTUAL_FUNCTIONS');
|
||||||
|
if (!$documentProperties && !$documentFunctions) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export all JSON properties, with RELATIVE class-paths when possible.
|
||||||
|
// NOTE: We will document ALL properties. Even ones inherited from
|
||||||
|
// parents/imported maps. This ensures that users who are manually
|
||||||
|
// reading the source code can see EVERYTHING without needing an IDE.
|
||||||
|
$properties = [];
|
||||||
|
$ownerClassName = $this->_reflector->getName();
|
||||||
|
foreach ($this->_compiledPropertyMapLink as $propName => $propDef) {
|
||||||
|
$properties[$propName] = new PropertyDescription( // Throws.
|
||||||
|
$ownerClassName,
|
||||||
|
$propName,
|
||||||
|
$propDef,
|
||||||
|
true // Use relative class-paths when possible.
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the magic documentation...
|
||||||
|
$magicDocLines = [];
|
||||||
|
foreach (['functions', 'properties'] as $docType) {
|
||||||
|
if (($docType === 'functions' && !$documentFunctions)
|
||||||
|
|| ($docType === 'properties' && !$documentProperties)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate all lines for the current magic tag type...
|
||||||
|
$lineStorage = [];
|
||||||
|
foreach ($properties as $property) {
|
||||||
|
if ($docType === 'functions') {
|
||||||
|
// We will only document useful functions (not the "has",
|
||||||
|
// since those are useless for properties that are fully
|
||||||
|
// defined in the class map).
|
||||||
|
foreach (['get', 'set', 'is', 'unset'] as $funcType) {
|
||||||
|
// Generate the function name, ie "getSomething", and
|
||||||
|
// skip this function if it's already defined as a REAL
|
||||||
|
// (overridden) function in this class or its parents.
|
||||||
|
$functionName = $funcType.$property->func_case;
|
||||||
|
if (!$this->_options['document-overridden'] && $this->_reflector->hasMethod($functionName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alright, the function doesn't exist as a real class
|
||||||
|
// function, or the user wants to document it anyway...
|
||||||
|
// Document it via its calculated signature.
|
||||||
|
// NOTE: Classtypes use paths relative to current class!
|
||||||
|
$functionSignature = $property->{'function_'.$funcType};
|
||||||
|
$lineStorage[$functionName] = sprintf('@method %s', $functionSignature);
|
||||||
|
}
|
||||||
|
} elseif ($docType === 'properties') {
|
||||||
|
// Skip this property if it's already defined as a REAL
|
||||||
|
// (overridden) property in this class or its parents.
|
||||||
|
if (!$this->_options['document-overridden'] && $this->_reflector->hasProperty($property->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alright, the property doesn't exist as a real class
|
||||||
|
// property, or the user wants to document it anyway...
|
||||||
|
// Document it via its calculated signature.
|
||||||
|
// NOTE: Classtypes use paths relative to current class!
|
||||||
|
$lineStorage[$property->name] = sprintf(
|
||||||
|
'@property %s $%s',
|
||||||
|
$property->type,
|
||||||
|
$property->name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip this tag type if there was nothing to document...
|
||||||
|
if (empty($lineStorage)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert empty line separators between different magic tag types.
|
||||||
|
if (!empty($magicDocLines)) {
|
||||||
|
$magicDocLines[] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reorder lines by name and add them to the magic doc lines.
|
||||||
|
// NOTE: We use case sensitivity so that "getComments" and
|
||||||
|
// "getCommentThreads" etc aren't placed next to each other.
|
||||||
|
ksort($lineStorage, SORT_NATURAL); // Case-sensitive natural order.
|
||||||
|
$magicDocLines = array_merge($magicDocLines, array_values($lineStorage));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $magicDocLines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now process all PHP files under all of the project's namespace folders.
|
||||||
|
foreach ($namespaces as $realpath => $namespace) {
|
||||||
|
echo PHP_EOL.'Processing namespace "'.$namespace.'".'.PHP_EOL.'- Path: "'.$realpath.'".'.PHP_EOL;
|
||||||
|
$realpathlen = strlen($realpath);
|
||||||
|
|
||||||
|
$iterator = new RegexIterator(
|
||||||
|
new RecursiveIteratorIterator(new RecursiveDirectoryIterator($realpath)),
|
||||||
|
'/\.php$/i', RecursiveRegexIterator::GET_MATCH
|
||||||
|
);
|
||||||
|
foreach ($iterator as $file => $ext) {
|
||||||
|
// Determine the real path to the file (compatible with $realpath).
|
||||||
|
$realfile = realpath($file);
|
||||||
|
if ($realfile === false) {
|
||||||
|
fwrite(STDERR, 'Unable to determine real path to file "'.$file.'".'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now ensure that the file starts with the expected path...
|
||||||
|
if (strncmp($realpath, $realfile, $realpathlen) !== 0) {
|
||||||
|
fwrite(STDERR, 'Unexpected path to file "'.$realfile.'". Does not match project path.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
$class = substr($realfile, $realpathlen);
|
||||||
|
|
||||||
|
// Remove the leading slash for the folder...
|
||||||
|
if ($class[0] !== '/' && $class[0] !== '\\') {
|
||||||
|
fwrite(STDERR, 'Unexpected path to file "'.$realfile.'". Does not match project path.'.PHP_EOL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
$class = substr($class, 1);
|
||||||
|
|
||||||
|
// And now just generate the final class name...
|
||||||
|
$class = sprintf(
|
||||||
|
'%s%s',
|
||||||
|
$namespace,
|
||||||
|
str_replace('/', '\\', preg_replace('/\.php$/ui', '', $class))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Some files may not contain classes. For example, some people have
|
||||||
|
// functions.php files with functions, etc. So before we proceed, just
|
||||||
|
// ensure that the generated class name actually exists.
|
||||||
|
// NOTE: class_exists() ignores interfaces. Only finds classes. Good.
|
||||||
|
if (!class_exists($class, true)) { // TRUE = Autoload.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now process the current class.
|
||||||
|
$documentor = new LazyClassDocumentor($class, $options);
|
||||||
|
$result = $documentor->process();
|
||||||
|
if (!$result) {
|
||||||
|
if ($options['validate-only']) {
|
||||||
|
fwrite(STDERR, '> One or more files need updated class documentation or contain other errors.'.PHP_EOL);
|
||||||
|
} else {
|
||||||
|
fwrite(STDERR, '> Error while processing class "'.$class.'". Aborting...'.PHP_EOL);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
instafeed/vendor/binsoul/net-mqtt-client-react/LICENSE.md
vendored
Executable file
21
instafeed/vendor/binsoul/net-mqtt-client-react/LICENSE.md
vendored
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
# The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Sebastian Mößler <code@binsoul.de>
|
||||||
|
|
||||||
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
> of this software and associated documentation files (the "Software"), to deal
|
||||||
|
> in the Software without restriction, including without limitation the rights
|
||||||
|
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
> copies of the Software, and to permit persons to whom the Software is
|
||||||
|
> furnished to do so, subject to the following conditions:
|
||||||
|
>
|
||||||
|
> The above copyright notice and this permission notice shall be included in
|
||||||
|
> all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
> THE SOFTWARE.
|
||||||
145
instafeed/vendor/binsoul/net-mqtt-client-react/README.md
vendored
Executable file
145
instafeed/vendor/binsoul/net-mqtt-client-react/README.md
vendored
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
# net-mqtt-client-react
|
||||||
|
|
||||||
|
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||||
|
[![Software License][ico-license]](LICENSE.md)
|
||||||
|
[![Total Downloads][ico-downloads]][link-downloads]
|
||||||
|
|
||||||
|
This package provides an asynchronous MQTT client built on the [React socket](https://github.com/reactphp/socket) library. All client methods return a promise which is fulfilled if the operation succeeded or rejected if the operation failed. Incoming messages of subscribed topics are delivered via the "message" event.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Via composer:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
$ composer require binsoul/net-mqtt-client-react
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Connect to a public broker and run forever.
|
||||||
|
|
||||||
|
``` php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Client\React\ReactMqttClient;
|
||||||
|
use BinSoul\Net\Mqtt\Connection;
|
||||||
|
use BinSoul\Net\Mqtt\DefaultMessage;
|
||||||
|
use BinSoul\Net\Mqtt\DefaultSubscription;
|
||||||
|
use BinSoul\Net\Mqtt\Message;
|
||||||
|
use BinSoul\Net\Mqtt\Subscription;
|
||||||
|
use React\Socket\DnsConnector;
|
||||||
|
use React\Socket\TcpConnector;
|
||||||
|
|
||||||
|
include 'vendor/autoload.php';
|
||||||
|
|
||||||
|
// Setup client
|
||||||
|
$loop = \React\EventLoop\Factory::create();
|
||||||
|
$dnsResolverFactory = new \React\Dns\Resolver\Factory();
|
||||||
|
$connector = new DnsConnector(new TcpConnector($loop), $dnsResolverFactory->createCached('8.8.8.8', $loop));
|
||||||
|
$client = new ReactMqttClient($connector, $loop);
|
||||||
|
|
||||||
|
// Bind to events
|
||||||
|
$client->on('open', function () use ($client) {
|
||||||
|
// Network connection established
|
||||||
|
echo sprintf("Open: %s:%s\n", $client->getHost(), $client->getPort());
|
||||||
|
});
|
||||||
|
|
||||||
|
$client->on('close', function () use ($client, $loop) {
|
||||||
|
// Network connection closed
|
||||||
|
echo sprintf("Close: %s:%s\n", $client->getHost(), $client->getPort());
|
||||||
|
|
||||||
|
$loop->stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
$client->on('connect', function (Connection $connection) {
|
||||||
|
// Broker connected
|
||||||
|
echo sprintf("Connect: client=%s\n", $connection->getClientID());
|
||||||
|
});
|
||||||
|
|
||||||
|
$client->on('disconnect', function (Connection $connection) {
|
||||||
|
// Broker disconnected
|
||||||
|
echo sprintf("Disconnect: client=%s\n", $connection->getClientID());
|
||||||
|
});
|
||||||
|
|
||||||
|
$client->on('message', function (Message $message) {
|
||||||
|
// Incoming message
|
||||||
|
echo 'Message';
|
||||||
|
|
||||||
|
if ($message->isDuplicate()) {
|
||||||
|
echo ' (duplicate)';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($message->isRetained()) {
|
||||||
|
echo ' (retained)';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ': '.$message->getTopic().' => '.mb_strimwidth($message->getPayload(), 0, 50, '...');
|
||||||
|
echo "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
$client->on('warning', function (\Exception $e) {
|
||||||
|
echo sprintf("Warning: %s\n", $e->getMessage());
|
||||||
|
});
|
||||||
|
|
||||||
|
$client->on('error', function (\Exception $e) use ($loop) {
|
||||||
|
echo sprintf("Error: %s\n", $e->getMessage());
|
||||||
|
|
||||||
|
$loop->stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect to broker
|
||||||
|
$client->connect('test.mosquitto.org')->then(
|
||||||
|
function () use ($client) {
|
||||||
|
// Subscribe to all topics
|
||||||
|
$client->subscribe(new DefaultSubscription('#'))
|
||||||
|
->then(function (Subscription $subscription) {
|
||||||
|
echo sprintf("Subscribe: %s\n", $subscription->getFilter());
|
||||||
|
})
|
||||||
|
->otherwise(function (\Exception $e) {
|
||||||
|
echo sprintf("Error: %s\n", $e->getMessage());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Publish humidity once
|
||||||
|
$client->publish(new DefaultMessage('sensors/humidity', '55%'))
|
||||||
|
->then(function (Message $message) {
|
||||||
|
echo sprintf("Publish: %s => %s\n", $message->getTopic(), $message->getPayload());
|
||||||
|
})
|
||||||
|
->otherwise(function (\Exception $e) {
|
||||||
|
echo sprintf("Error: %s\n", $e->getMessage());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Publish a random temperature every 10 seconds
|
||||||
|
$generator = function () {
|
||||||
|
return mt_rand(-20, 30);
|
||||||
|
};
|
||||||
|
|
||||||
|
$client->publishPeriodically(10, new DefaultMessage('sensors/temperature'), $generator)
|
||||||
|
->progress(function (Message $message) {
|
||||||
|
echo sprintf("Publish: %s => %s\n", $message->getTopic(), $message->getPayload());
|
||||||
|
})
|
||||||
|
->otherwise(function (\Exception $e) {
|
||||||
|
echo sprintf("Error: %s\n", $e->getMessage());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
$ composer test
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||||
|
|
||||||
|
[ico-version]: https://img.shields.io/packagist/v/binsoul/net-mqtt-client-react.svg?style=flat-square
|
||||||
|
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
|
||||||
|
[ico-downloads]: https://img.shields.io/packagist/dt/binsoul/net-mqtt-client-react.svg?style=flat-square
|
||||||
|
|
||||||
|
[link-packagist]: https://packagist.org/packages/binsoul/net-mqtt-client-react
|
||||||
|
[link-downloads]: https://packagist.org/packages/binsoul/net-mqtt-client-react
|
||||||
|
[link-author]: https://github.com/binsoul
|
||||||
51
instafeed/vendor/binsoul/net-mqtt-client-react/composer.json
vendored
Executable file
51
instafeed/vendor/binsoul/net-mqtt-client-react/composer.json
vendored
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"name": "binsoul/net-mqtt-client-react",
|
||||||
|
"description": "Asynchronous MQTT client built on React",
|
||||||
|
"keywords": [
|
||||||
|
"net",
|
||||||
|
"mqtt",
|
||||||
|
"client"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/binsoul/net-mqtt-client-react",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Sebastian Mößler",
|
||||||
|
"email": "code@binsoul.de",
|
||||||
|
"homepage": "https://github.com/binsoul",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "~5.6|~7.0",
|
||||||
|
"binsoul/net-mqtt": "~0.2",
|
||||||
|
"react/promise": "~2.0",
|
||||||
|
"react/socket": "~0.8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "~4.0||~5.0",
|
||||||
|
"friendsofphp/php-cs-fixer": "~1.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"BinSoul\\Net\\Mqtt\\Client\\React\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"BinSoul\\Test\\Net\\Mqtt\\Client\\React\\": "tests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "phpunit",
|
||||||
|
"fix-style": [
|
||||||
|
"php-cs-fixer fix src",
|
||||||
|
"php-cs-fixer fix tests"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
instafeed/vendor/binsoul/net-mqtt-client-react/src/ReactFlow.php
vendored
Executable file
112
instafeed/vendor/binsoul/net-mqtt-client-react/src/ReactFlow.php
vendored
Executable file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Client\React;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Flow;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use React\Promise\Deferred;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates flows with data required for the {@see ReactMqttClient} class.
|
||||||
|
*/
|
||||||
|
class ReactFlow implements Flow
|
||||||
|
{
|
||||||
|
/** @var Flow */
|
||||||
|
private $decorated;
|
||||||
|
/** @var Deferred */
|
||||||
|
private $deferred;
|
||||||
|
/** @var Packet */
|
||||||
|
private $packet;
|
||||||
|
/** @var bool */
|
||||||
|
private $isSilent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Flow $decorated
|
||||||
|
* @param Deferred $deferred
|
||||||
|
* @param Packet $packet
|
||||||
|
* @param bool $isSilent
|
||||||
|
*/
|
||||||
|
public function __construct(Flow $decorated, Deferred $deferred, Packet $packet = null, $isSilent = false)
|
||||||
|
{
|
||||||
|
$this->decorated = $decorated;
|
||||||
|
$this->deferred = $deferred;
|
||||||
|
$this->packet = $packet;
|
||||||
|
$this->isSilent = $isSilent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return $this->decorated->getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$this->packet = $this->decorated->start();
|
||||||
|
|
||||||
|
return $this->packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
return $this->decorated->accept($packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
$this->packet = $this->decorated->next($packet);
|
||||||
|
|
||||||
|
return $this->packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isFinished()
|
||||||
|
{
|
||||||
|
return $this->decorated->isFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSuccess()
|
||||||
|
{
|
||||||
|
return $this->decorated->isSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult()
|
||||||
|
{
|
||||||
|
return $this->decorated->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorMessage()
|
||||||
|
{
|
||||||
|
return $this->decorated->getErrorMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the associated deferred.
|
||||||
|
*
|
||||||
|
* @return Deferred
|
||||||
|
*/
|
||||||
|
public function getDeferred()
|
||||||
|
{
|
||||||
|
return $this->deferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current packet.
|
||||||
|
*
|
||||||
|
* @return Packet
|
||||||
|
*/
|
||||||
|
public function getPacket()
|
||||||
|
{
|
||||||
|
return $this->packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the flow should emit events.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isSilent()
|
||||||
|
{
|
||||||
|
return $this->isSilent;
|
||||||
|
}
|
||||||
|
}
|
||||||
701
instafeed/vendor/binsoul/net-mqtt-client-react/src/ReactMqttClient.php
vendored
Executable file
701
instafeed/vendor/binsoul/net-mqtt-client-react/src/ReactMqttClient.php
vendored
Executable file
@@ -0,0 +1,701 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Client\React;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Connection;
|
||||||
|
use BinSoul\Net\Mqtt\DefaultConnection;
|
||||||
|
use BinSoul\Net\Mqtt\DefaultIdentifierGenerator;
|
||||||
|
use BinSoul\Net\Mqtt\Flow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\IncomingPublishFlow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\OutgoingConnectFlow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\OutgoingDisconnectFlow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\OutgoingPingFlow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\OutgoingPublishFlow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\OutgoingSubscribeFlow;
|
||||||
|
use BinSoul\Net\Mqtt\Flow\OutgoingUnsubscribeFlow;
|
||||||
|
use BinSoul\Net\Mqtt\DefaultMessage;
|
||||||
|
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||||
|
use BinSoul\Net\Mqtt\Message;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\StreamParser;
|
||||||
|
use BinSoul\Net\Mqtt\Subscription;
|
||||||
|
use Evenement\EventEmitter;
|
||||||
|
use React\EventLoop\Timer\TimerInterface;
|
||||||
|
use React\Promise\Deferred;
|
||||||
|
use React\EventLoop\LoopInterface;
|
||||||
|
use React\Promise\ExtendedPromiseInterface;
|
||||||
|
use React\Promise\RejectedPromise;
|
||||||
|
use React\Socket\ConnectorInterface;
|
||||||
|
use React\Stream\DuplexStreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to a MQTT broker and subscribes to topics or publishes messages.
|
||||||
|
*
|
||||||
|
* The following events are emitted:
|
||||||
|
* - open - The network connection to the server is established.
|
||||||
|
* - close - The network connection to the server is closed.
|
||||||
|
* - warning - An event of severity "warning" occurred.
|
||||||
|
* - error - An event of severity "error" occurred.
|
||||||
|
*
|
||||||
|
* If a flow finishes it's result is also emitted, e.g.:
|
||||||
|
* - connect - The client connected to the broker.
|
||||||
|
* - disconnect - The client disconnected from the broker.
|
||||||
|
* - subscribe - The client subscribed to a topic filter.
|
||||||
|
* - unsubscribe - The client unsubscribed from topic filter.
|
||||||
|
* - publish - A message was published.
|
||||||
|
* - message - A message was received.
|
||||||
|
*/
|
||||||
|
class ReactMqttClient extends EventEmitter
|
||||||
|
{
|
||||||
|
/** @var ConnectorInterface */
|
||||||
|
private $connector;
|
||||||
|
/** @var LoopInterface */
|
||||||
|
private $loop;
|
||||||
|
/** @var DuplexStreamInterface */
|
||||||
|
private $stream;
|
||||||
|
/** @var StreamParser */
|
||||||
|
private $parser;
|
||||||
|
/** @var IdentifierGenerator */
|
||||||
|
private $identifierGenerator;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $host;
|
||||||
|
/** @var int */
|
||||||
|
private $port;
|
||||||
|
/** @var Connection */
|
||||||
|
private $connection;
|
||||||
|
/** @var bool */
|
||||||
|
private $isConnected = false;
|
||||||
|
/** @var bool */
|
||||||
|
private $isConnecting = false;
|
||||||
|
/** @var bool */
|
||||||
|
private $isDisconnecting = false;
|
||||||
|
|
||||||
|
/** @var TimerInterface[] */
|
||||||
|
private $timer = [];
|
||||||
|
|
||||||
|
/** @var ReactFlow[] */
|
||||||
|
private $receivingFlows = [];
|
||||||
|
/** @var ReactFlow[] */
|
||||||
|
private $sendingFlows = [];
|
||||||
|
/** @var ReactFlow */
|
||||||
|
private $writtenFlow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param ConnectorInterface $connector
|
||||||
|
* @param LoopInterface $loop
|
||||||
|
* @param IdentifierGenerator $identifierGenerator
|
||||||
|
* @param StreamParser $parser
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
ConnectorInterface $connector,
|
||||||
|
LoopInterface $loop,
|
||||||
|
IdentifierGenerator $identifierGenerator = null,
|
||||||
|
StreamParser $parser = null
|
||||||
|
) {
|
||||||
|
$this->connector = $connector;
|
||||||
|
$this->loop = $loop;
|
||||||
|
|
||||||
|
$this->parser = $parser;
|
||||||
|
if ($this->parser === null) {
|
||||||
|
$this->parser = new StreamParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parser->onError(function (\Exception $e) {
|
||||||
|
$this->emitWarning($e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->identifierGenerator = $identifierGenerator;
|
||||||
|
if ($this->identifierGenerator === null) {
|
||||||
|
$this->identifierGenerator = new DefaultIdentifierGenerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the host.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getHost()
|
||||||
|
{
|
||||||
|
return $this->host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the port.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPort()
|
||||||
|
{
|
||||||
|
return $this->port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the client is connected.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isConnected()
|
||||||
|
{
|
||||||
|
return $this->isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the underlying stream or null if the client is not connected.
|
||||||
|
*
|
||||||
|
* @return DuplexStreamInterface|null
|
||||||
|
*/
|
||||||
|
public function getStream()
|
||||||
|
{
|
||||||
|
return $this->stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to a broker.
|
||||||
|
*
|
||||||
|
* @param string $host
|
||||||
|
* @param int $port
|
||||||
|
* @param Connection $connection
|
||||||
|
* @param int $timeout
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
public function connect($host, $port = 1883, Connection $connection = null, $timeout = 5)
|
||||||
|
{
|
||||||
|
if ($this->isConnected || $this->isConnecting) {
|
||||||
|
return new RejectedPromise(new \LogicException('The client is already connected.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->isConnecting = true;
|
||||||
|
$this->isConnected = false;
|
||||||
|
|
||||||
|
$this->host = $host;
|
||||||
|
$this->port = $port;
|
||||||
|
|
||||||
|
if ($connection === null) {
|
||||||
|
$connection = new DefaultConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($connection->isCleanSession()) {
|
||||||
|
$this->cleanPreviousSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($connection->getClientID() === '') {
|
||||||
|
$connection = $connection->withClientID($this->identifierGenerator->generateClientID());
|
||||||
|
}
|
||||||
|
|
||||||
|
$deferred = new Deferred();
|
||||||
|
|
||||||
|
$this->establishConnection($this->host, $this->port, $timeout)
|
||||||
|
->then(function (DuplexStreamInterface $stream) use ($connection, $deferred, $timeout) {
|
||||||
|
$this->stream = $stream;
|
||||||
|
|
||||||
|
$this->emit('open', [$connection, $this]);
|
||||||
|
|
||||||
|
$this->registerClient($connection, $timeout)
|
||||||
|
->then(function (Connection $connection) use ($deferred) {
|
||||||
|
$this->isConnecting = false;
|
||||||
|
$this->isConnected = true;
|
||||||
|
$this->connection = $connection;
|
||||||
|
|
||||||
|
$this->emit('connect', [$connection, $this]);
|
||||||
|
$deferred->resolve($this->connection);
|
||||||
|
})
|
||||||
|
->otherwise(function (\Exception $e) use ($deferred, $connection) {
|
||||||
|
$this->isConnecting = false;
|
||||||
|
|
||||||
|
$this->emitError($e);
|
||||||
|
$deferred->reject($e);
|
||||||
|
|
||||||
|
if ($this->stream !== null) {
|
||||||
|
$this->stream->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->emit('close', [$connection, $this]);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->otherwise(function (\Exception $e) use ($deferred) {
|
||||||
|
$this->isConnecting = false;
|
||||||
|
|
||||||
|
$this->emitError($e);
|
||||||
|
$deferred->reject($e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $deferred->promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects from a broker.
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
public function disconnect()
|
||||||
|
{
|
||||||
|
if (!$this->isConnected || $this->isDisconnecting) {
|
||||||
|
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->isDisconnecting = true;
|
||||||
|
|
||||||
|
$deferred = new Deferred();
|
||||||
|
|
||||||
|
$this->startFlow(new OutgoingDisconnectFlow($this->connection), true)
|
||||||
|
->then(function (Connection $connection) use ($deferred) {
|
||||||
|
$this->isDisconnecting = false;
|
||||||
|
$this->isConnected = false;
|
||||||
|
|
||||||
|
$this->emit('disconnect', [$connection, $this]);
|
||||||
|
$deferred->resolve($connection);
|
||||||
|
|
||||||
|
if ($this->stream !== null) {
|
||||||
|
$this->stream->close();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->otherwise(function () use ($deferred) {
|
||||||
|
$this->isDisconnecting = false;
|
||||||
|
$deferred->reject($this->connection);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $deferred->promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes to a topic filter.
|
||||||
|
*
|
||||||
|
* @param Subscription $subscription
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
public function subscribe(Subscription $subscription)
|
||||||
|
{
|
||||||
|
if (!$this->isConnected) {
|
||||||
|
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->startFlow(new OutgoingSubscribeFlow([$subscription], $this->identifierGenerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribes from a topic filter.
|
||||||
|
*
|
||||||
|
* @param Subscription $subscription
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
public function unsubscribe(Subscription $subscription)
|
||||||
|
{
|
||||||
|
if (!$this->isConnected) {
|
||||||
|
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->startFlow(new OutgoingUnsubscribeFlow([$subscription], $this->identifierGenerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes a message.
|
||||||
|
*
|
||||||
|
* @param Message $message
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
public function publish(Message $message)
|
||||||
|
{
|
||||||
|
if (!$this->isConnected) {
|
||||||
|
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->startFlow(new OutgoingPublishFlow($message, $this->identifierGenerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the given generator periodically and publishes the return value.
|
||||||
|
*
|
||||||
|
* @param int $interval
|
||||||
|
* @param Message $message
|
||||||
|
* @param callable $generator
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
public function publishPeriodically($interval, Message $message, callable $generator)
|
||||||
|
{
|
||||||
|
if (!$this->isConnected) {
|
||||||
|
return new RejectedPromise(new \LogicException('The client is not connected.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$deferred = new Deferred();
|
||||||
|
|
||||||
|
$this->timer[] = $this->loop->addPeriodicTimer(
|
||||||
|
$interval,
|
||||||
|
function () use ($message, $generator, $deferred) {
|
||||||
|
$this->publish($message->withPayload($generator($message->getTopic())))->then(
|
||||||
|
function ($value) use ($deferred) {
|
||||||
|
$deferred->notify($value);
|
||||||
|
},
|
||||||
|
function (\Exception $e) use ($deferred) {
|
||||||
|
$deferred->reject($e);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $deferred->promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits warnings.
|
||||||
|
*
|
||||||
|
* @param \Exception $e
|
||||||
|
*/
|
||||||
|
private function emitWarning(\Exception $e)
|
||||||
|
{
|
||||||
|
$this->emit('warning', [$e, $this]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits errors.
|
||||||
|
*
|
||||||
|
* @param \Exception $e
|
||||||
|
*/
|
||||||
|
private function emitError(\Exception $e)
|
||||||
|
{
|
||||||
|
$this->emit('error', [$e, $this]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes a network connection to a server.
|
||||||
|
*
|
||||||
|
* @param string $host
|
||||||
|
* @param int $port
|
||||||
|
* @param int $timeout
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
private function establishConnection($host, $port, $timeout)
|
||||||
|
{
|
||||||
|
$deferred = new Deferred();
|
||||||
|
|
||||||
|
$timer = $this->loop->addTimer(
|
||||||
|
$timeout,
|
||||||
|
function () use ($deferred, $timeout) {
|
||||||
|
$exception = new \RuntimeException(sprintf('Connection timed out after %d seconds.', $timeout));
|
||||||
|
$deferred->reject($exception);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->connector->connect($host.':'.$port)
|
||||||
|
->always(function () use ($timer) {
|
||||||
|
$this->loop->cancelTimer($timer);
|
||||||
|
})
|
||||||
|
->then(function (DuplexStreamInterface $stream) use ($deferred) {
|
||||||
|
$stream->on('data', function ($data) {
|
||||||
|
$this->handleReceive($data);
|
||||||
|
});
|
||||||
|
|
||||||
|
$stream->on('close', function () {
|
||||||
|
$this->handleClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
$stream->on('error', function (\Exception $e) {
|
||||||
|
$this->handleError($e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$deferred->resolve($stream);
|
||||||
|
})
|
||||||
|
->otherwise(function (\Exception $e) use ($deferred) {
|
||||||
|
$deferred->reject($e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $deferred->promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new client with the broker.
|
||||||
|
*
|
||||||
|
* @param Connection $connection
|
||||||
|
* @param int $timeout
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
private function registerClient(Connection $connection, $timeout)
|
||||||
|
{
|
||||||
|
$deferred = new Deferred();
|
||||||
|
|
||||||
|
$responseTimer = $this->loop->addTimer(
|
||||||
|
$timeout,
|
||||||
|
function () use ($deferred, $timeout) {
|
||||||
|
$exception = new \RuntimeException(sprintf('No response after %d seconds.', $timeout));
|
||||||
|
$deferred->reject($exception);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->startFlow(new OutgoingConnectFlow($connection, $this->identifierGenerator), true)
|
||||||
|
->always(function () use ($responseTimer) {
|
||||||
|
$this->loop->cancelTimer($responseTimer);
|
||||||
|
})->then(function (Connection $connection) use ($deferred) {
|
||||||
|
$this->timer[] = $this->loop->addPeriodicTimer(
|
||||||
|
floor($connection->getKeepAlive() * 0.75),
|
||||||
|
function () {
|
||||||
|
$this->startFlow(new OutgoingPingFlow());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$deferred->resolve($connection);
|
||||||
|
})->otherwise(function (\Exception $e) use ($deferred) {
|
||||||
|
$deferred->reject($e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $deferred->promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles incoming data.
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
*/
|
||||||
|
private function handleReceive($data)
|
||||||
|
{
|
||||||
|
if (!$this->isConnected && !$this->isConnecting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$flowCount = count($this->receivingFlows);
|
||||||
|
|
||||||
|
$packets = $this->parser->push($data);
|
||||||
|
foreach ($packets as $packet) {
|
||||||
|
$this->handlePacket($packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($flowCount > count($this->receivingFlows)) {
|
||||||
|
$this->receivingFlows = array_values($this->receivingFlows);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handleSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles an incoming packet.
|
||||||
|
*
|
||||||
|
* @param Packet $packet
|
||||||
|
*/
|
||||||
|
private function handlePacket(Packet $packet)
|
||||||
|
{
|
||||||
|
switch ($packet->getPacketType()) {
|
||||||
|
case Packet::TYPE_PUBLISH:
|
||||||
|
/* @var PublishRequestPacket $packet */
|
||||||
|
$message = new DefaultMessage(
|
||||||
|
$packet->getTopic(),
|
||||||
|
$packet->getPayload(),
|
||||||
|
$packet->getQosLevel(),
|
||||||
|
$packet->isRetained(),
|
||||||
|
$packet->isDuplicate()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->startFlow(new IncomingPublishFlow($message, $packet->getIdentifier()));
|
||||||
|
break;
|
||||||
|
case Packet::TYPE_CONNACK:
|
||||||
|
case Packet::TYPE_PINGRESP:
|
||||||
|
case Packet::TYPE_SUBACK:
|
||||||
|
case Packet::TYPE_UNSUBACK:
|
||||||
|
case Packet::TYPE_PUBREL:
|
||||||
|
case Packet::TYPE_PUBACK:
|
||||||
|
case Packet::TYPE_PUBREC:
|
||||||
|
case Packet::TYPE_PUBCOMP:
|
||||||
|
$flowFound = false;
|
||||||
|
foreach ($this->receivingFlows as $index => $flow) {
|
||||||
|
if ($flow->accept($packet)) {
|
||||||
|
$flowFound = true;
|
||||||
|
|
||||||
|
unset($this->receivingFlows[$index]);
|
||||||
|
$this->continueFlow($flow, $packet);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$flowFound) {
|
||||||
|
$this->emitWarning(
|
||||||
|
new \LogicException(sprintf('Received unexpected packet of type %d.', $packet->getPacketType()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$this->emitWarning(
|
||||||
|
new \LogicException(sprintf('Cannot handle packet of type %d.', $packet->getPacketType()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles outgoing packets.
|
||||||
|
*/
|
||||||
|
private function handleSend()
|
||||||
|
{
|
||||||
|
$flow = null;
|
||||||
|
if ($this->writtenFlow !== null) {
|
||||||
|
$flow = $this->writtenFlow;
|
||||||
|
$this->writtenFlow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($this->sendingFlows) > 0) {
|
||||||
|
$this->writtenFlow = array_shift($this->sendingFlows);
|
||||||
|
$this->stream->write($this->writtenFlow->getPacket());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($flow !== null) {
|
||||||
|
if ($flow->isFinished()) {
|
||||||
|
$this->loop->nextTick(function () use ($flow) {
|
||||||
|
$this->finishFlow($flow);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$this->receivingFlows[] = $flow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles closing of the stream.
|
||||||
|
*/
|
||||||
|
private function handleClose()
|
||||||
|
{
|
||||||
|
foreach ($this->timer as $timer) {
|
||||||
|
$this->loop->cancelTimer($timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->timer = [];
|
||||||
|
|
||||||
|
$connection = $this->connection;
|
||||||
|
|
||||||
|
$this->isConnecting = false;
|
||||||
|
$this->isDisconnecting = false;
|
||||||
|
$this->isConnected = false;
|
||||||
|
$this->connection = null;
|
||||||
|
$this->stream = null;
|
||||||
|
|
||||||
|
if ($connection !== null) {
|
||||||
|
$this->emit('close', [$connection, $this]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles errors of the stream.
|
||||||
|
*
|
||||||
|
* @param \Exception $e
|
||||||
|
*/
|
||||||
|
private function handleError(\Exception $e)
|
||||||
|
{
|
||||||
|
$this->emitError($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the given flow.
|
||||||
|
*
|
||||||
|
* @param Flow $flow
|
||||||
|
* @param bool $isSilent
|
||||||
|
*
|
||||||
|
* @return ExtendedPromiseInterface
|
||||||
|
*/
|
||||||
|
private function startFlow(Flow $flow, $isSilent = false)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$packet = $flow->start();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->emitError($e);
|
||||||
|
|
||||||
|
return new RejectedPromise($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
$deferred = new Deferred();
|
||||||
|
$internalFlow = new ReactFlow($flow, $deferred, $packet, $isSilent);
|
||||||
|
|
||||||
|
if ($packet !== null) {
|
||||||
|
if ($this->writtenFlow !== null) {
|
||||||
|
$this->sendingFlows[] = $internalFlow;
|
||||||
|
} else {
|
||||||
|
$this->stream->write($packet);
|
||||||
|
$this->writtenFlow = $internalFlow;
|
||||||
|
$this->handleSend();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->loop->nextTick(function () use ($internalFlow) {
|
||||||
|
$this->finishFlow($internalFlow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $deferred->promise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continues the given flow.
|
||||||
|
*
|
||||||
|
* @param ReactFlow $flow
|
||||||
|
* @param Packet $packet
|
||||||
|
*/
|
||||||
|
private function continueFlow(ReactFlow $flow, Packet $packet)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = $flow->next($packet);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->emitError($e);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response !== null) {
|
||||||
|
if ($this->writtenFlow !== null) {
|
||||||
|
$this->sendingFlows[] = $flow;
|
||||||
|
} else {
|
||||||
|
$this->stream->write($response);
|
||||||
|
$this->writtenFlow = $flow;
|
||||||
|
$this->handleSend();
|
||||||
|
}
|
||||||
|
} elseif ($flow->isFinished()) {
|
||||||
|
$this->loop->nextTick(function () use ($flow) {
|
||||||
|
$this->finishFlow($flow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes the given flow.
|
||||||
|
*
|
||||||
|
* @param ReactFlow $flow
|
||||||
|
*/
|
||||||
|
private function finishFlow(ReactFlow $flow)
|
||||||
|
{
|
||||||
|
if ($flow->isSuccess()) {
|
||||||
|
if (!$flow->isSilent()) {
|
||||||
|
$this->emit($flow->getCode(), [$flow->getResult(), $this]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$flow->getDeferred()->resolve($flow->getResult());
|
||||||
|
} else {
|
||||||
|
$result = new \RuntimeException($flow->getErrorMessage());
|
||||||
|
$this->emitWarning($result);
|
||||||
|
|
||||||
|
$flow->getDeferred()->reject($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans previous session by rejecting all pending flows.
|
||||||
|
*/
|
||||||
|
private function cleanPreviousSession()
|
||||||
|
{
|
||||||
|
$error = new \RuntimeException('Connection has been closed.');
|
||||||
|
|
||||||
|
foreach ($this->receivingFlows as $receivingFlow) {
|
||||||
|
$receivingFlow->getDeferred()->reject($error);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->sendingFlows as $sendingFlow) {
|
||||||
|
$sendingFlow->getDeferred()->reject($error);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->receivingFlows = [];
|
||||||
|
$this->sendingFlows = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
21
instafeed/vendor/binsoul/net-mqtt/LICENSE.md
vendored
Executable file
21
instafeed/vendor/binsoul/net-mqtt/LICENSE.md
vendored
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
# The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Sebastian Mößler <code@binsoul.de>
|
||||||
|
|
||||||
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
> of this software and associated documentation files (the "Software"), to deal
|
||||||
|
> in the Software without restriction, including without limitation the rights
|
||||||
|
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
> copies of the Software, and to permit persons to whom the Software is
|
||||||
|
> furnished to do so, subject to the following conditions:
|
||||||
|
>
|
||||||
|
> The above copyright notice and this permission notice shall be included in
|
||||||
|
> all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
> THE SOFTWARE.
|
||||||
36
instafeed/vendor/binsoul/net-mqtt/README.md
vendored
Executable file
36
instafeed/vendor/binsoul/net-mqtt/README.md
vendored
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
# net-mqtt
|
||||||
|
|
||||||
|
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||||
|
[![Software License][ico-license]](LICENSE.md)
|
||||||
|
[![Total Downloads][ico-downloads]][link-downloads]
|
||||||
|
|
||||||
|
MQTT is a machine-to-machine (M2M) / Internet of Things (IoT) connectivity protocol. It provides a lightweight method of carrying out messaging using a publish/subscribe model.
|
||||||
|
|
||||||
|
This package implements the MQTT protocol versions 3.1 and 3.1.1.
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Via composer:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
$ composer require binsoul/net-mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
$ composer test
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||||
|
|
||||||
|
[ico-version]: https://img.shields.io/packagist/v/binsoul/net-mqtt.svg?style=flat-square
|
||||||
|
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
|
||||||
|
[ico-downloads]: https://img.shields.io/packagist/dt/binsoul/net-mqtt.svg?style=flat-square
|
||||||
|
|
||||||
|
[link-packagist]: https://packagist.org/packages/binsoul/net-mqtt
|
||||||
|
[link-downloads]: https://packagist.org/packages/binsoul/net-mqtt
|
||||||
|
[link-author]: https://github.com/binsoul
|
||||||
47
instafeed/vendor/binsoul/net-mqtt/composer.json
vendored
Executable file
47
instafeed/vendor/binsoul/net-mqtt/composer.json
vendored
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "binsoul/net-mqtt",
|
||||||
|
"description": "MQTT protocol implementation",
|
||||||
|
"keywords": [
|
||||||
|
"net",
|
||||||
|
"mqtt"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/binsoul/net-mqtt",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Sebastian Mößler",
|
||||||
|
"email": "code@binsoul.de",
|
||||||
|
"homepage": "https://github.com/binsoul",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "~5.6|~7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "~4.0||~5.0",
|
||||||
|
"friendsofphp/php-cs-fixer": "~1.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"BinSoul\\Net\\Mqtt\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"BinSoul\\Test\\Net\\Mqtt\\": "tests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "phpunit",
|
||||||
|
"fix-style": [
|
||||||
|
"php-cs-fixer fix src",
|
||||||
|
"php-cs-fixer fix tests"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
instafeed/vendor/binsoul/net-mqtt/src/Connection.php
vendored
Executable file
90
instafeed/vendor/binsoul/net-mqtt/src/Connection.php
vendored
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the connection of a MQTT client.
|
||||||
|
*/
|
||||||
|
interface Connection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getProtocol();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getClientID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isCleanSession();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUsername();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPassword();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Message|null
|
||||||
|
*/
|
||||||
|
public function getWill();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getKeepAlive();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new connection with the given protocol.
|
||||||
|
*
|
||||||
|
* @param int $protocol
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withProtocol($protocol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new connection with the given client id.
|
||||||
|
*
|
||||||
|
* @param string $clientID
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withClientID($clientID);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new connection with the given credentials.
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
* @param string $password
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withCredentials($username, $password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new connection with the given will.
|
||||||
|
*
|
||||||
|
* @param Message $will
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withWill(Message $will);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new connection with the given keep alive timeout.
|
||||||
|
*
|
||||||
|
* @param int $timeout
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withKeepAlive($timeout);
|
||||||
|
}
|
||||||
129
instafeed/vendor/binsoul/net-mqtt/src/DefaultConnection.php
vendored
Executable file
129
instafeed/vendor/binsoul/net-mqtt/src/DefaultConnection.php
vendored
Executable file
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a default implementation of the {@see Connection} interface.
|
||||||
|
*/
|
||||||
|
class DefaultConnection implements Connection
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $username;
|
||||||
|
/** @var string */
|
||||||
|
private $password;
|
||||||
|
/** @var Message|null */
|
||||||
|
private $will;
|
||||||
|
/** @var string */
|
||||||
|
private $clientID;
|
||||||
|
/** @var int */
|
||||||
|
private $keepAlive;
|
||||||
|
/** @var int */
|
||||||
|
private $protocol;
|
||||||
|
/** @var bool */
|
||||||
|
private $clean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
* @param string $password
|
||||||
|
* @param Message|null $will
|
||||||
|
* @param string $clientID
|
||||||
|
* @param int $keepAlive
|
||||||
|
* @param int $protocol
|
||||||
|
* @param bool $clean
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$username = '',
|
||||||
|
$password = '',
|
||||||
|
Message $will = null,
|
||||||
|
$clientID = '',
|
||||||
|
$keepAlive = 60,
|
||||||
|
$protocol = 4,
|
||||||
|
$clean = true
|
||||||
|
) {
|
||||||
|
$this->username = $username;
|
||||||
|
$this->password = $password;
|
||||||
|
$this->will = $will;
|
||||||
|
$this->clientID = $clientID;
|
||||||
|
$this->keepAlive = $keepAlive;
|
||||||
|
$this->protocol = $protocol;
|
||||||
|
$this->clean = $clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProtocol()
|
||||||
|
{
|
||||||
|
return $this->protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientID()
|
||||||
|
{
|
||||||
|
return $this->clientID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCleanSession()
|
||||||
|
{
|
||||||
|
return $this->clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUsername()
|
||||||
|
{
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPassword()
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWill()
|
||||||
|
{
|
||||||
|
return $this->will;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKeepAlive()
|
||||||
|
{
|
||||||
|
return $this->keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withProtocol($protocol)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->protocol = $protocol;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withClientID($clientID)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->clientID = $clientID;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withCredentials($username, $password)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->username = $username;
|
||||||
|
$result->password = $password;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withWill(Message $will = null)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->will = $will;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withKeepAlive($timeout)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->keepAlive = $timeout;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
instafeed/vendor/binsoul/net-mqtt/src/DefaultIdentifierGenerator.php
vendored
Executable file
38
instafeed/vendor/binsoul/net-mqtt/src/DefaultIdentifierGenerator.php
vendored
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a default implementation of the {@see IdentifierGenerator} interface.
|
||||||
|
*/
|
||||||
|
class DefaultIdentifierGenerator implements IdentifierGenerator
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
private $currentIdentifier = 0;
|
||||||
|
|
||||||
|
public function generatePacketID()
|
||||||
|
{
|
||||||
|
++$this->currentIdentifier;
|
||||||
|
if ($this->currentIdentifier > 0xFFFF) {
|
||||||
|
$this->currentIdentifier = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->currentIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateClientID()
|
||||||
|
{
|
||||||
|
if (function_exists('random_bytes')) {
|
||||||
|
$data = random_bytes(9);
|
||||||
|
} elseif (function_exists('openssl_random_pseudo_bytes')) {
|
||||||
|
$data = openssl_random_pseudo_bytes(9);
|
||||||
|
} else {
|
||||||
|
$data = '';
|
||||||
|
for ($i = 1; $i <= 8; ++$i) {
|
||||||
|
$data = chr(mt_rand(0, 255)).$data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'BNMCR'.bin2hex($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
119
instafeed/vendor/binsoul/net-mqtt/src/DefaultMessage.php
vendored
Executable file
119
instafeed/vendor/binsoul/net-mqtt/src/DefaultMessage.php
vendored
Executable file
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a default implementation of the {@see Message} interface.
|
||||||
|
*/
|
||||||
|
class DefaultMessage implements Message
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $topic;
|
||||||
|
/** @var string */
|
||||||
|
private $payload;
|
||||||
|
/** @var bool */
|
||||||
|
private $isRetained;
|
||||||
|
/** @var bool */
|
||||||
|
private $isDuplicate = false;
|
||||||
|
/** @var int */
|
||||||
|
private $qosLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param string $topic
|
||||||
|
* @param string $payload
|
||||||
|
* @param int $qosLevel
|
||||||
|
* @param bool $retain
|
||||||
|
* @param bool $isDuplicate
|
||||||
|
*/
|
||||||
|
public function __construct($topic, $payload = '', $qosLevel = 0, $retain = false, $isDuplicate = false)
|
||||||
|
{
|
||||||
|
$this->topic = $topic;
|
||||||
|
$this->payload = $payload;
|
||||||
|
$this->isRetained = $retain;
|
||||||
|
$this->qosLevel = $qosLevel;
|
||||||
|
$this->isDuplicate = $isDuplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTopic()
|
||||||
|
{
|
||||||
|
return $this->topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPayload()
|
||||||
|
{
|
||||||
|
return $this->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQosLevel()
|
||||||
|
{
|
||||||
|
return $this->qosLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDuplicate()
|
||||||
|
{
|
||||||
|
return $this->isDuplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRetained()
|
||||||
|
{
|
||||||
|
return $this->isRetained;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withTopic($topic)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->topic = $topic;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPayload($payload)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->payload = $payload;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withQosLevel($level)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->qosLevel = $level;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function retain()
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->isRetained = true;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function release()
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->isRetained = false;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function duplicate()
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->isDuplicate = true;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function original()
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->isDuplicate = false;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
instafeed/vendor/binsoul/net-mqtt/src/DefaultSubscription.php
vendored
Executable file
52
instafeed/vendor/binsoul/net-mqtt/src/DefaultSubscription.php
vendored
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a default implementation of the {@see Subscription} interface.
|
||||||
|
*/
|
||||||
|
class DefaultSubscription implements Subscription
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $filter;
|
||||||
|
/** @var int */
|
||||||
|
private $qosLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param string $filter
|
||||||
|
* @param int $qosLevel
|
||||||
|
*/
|
||||||
|
public function __construct($filter, $qosLevel = 0)
|
||||||
|
{
|
||||||
|
$this->filter = $filter;
|
||||||
|
$this->qosLevel = $qosLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilter()
|
||||||
|
{
|
||||||
|
return $this->filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQosLevel()
|
||||||
|
{
|
||||||
|
return $this->qosLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withFilter($filter)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->filter = $filter;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withQosLevel($level)
|
||||||
|
{
|
||||||
|
$result = clone $this;
|
||||||
|
$result->qosLevel = $level;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
instafeed/vendor/binsoul/net-mqtt/src/Exception/EndOfStreamException.php
vendored
Executable file
10
instafeed/vendor/binsoul/net-mqtt/src/Exception/EndOfStreamException.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be thrown if the end of a stream is reached but more bytes were requested.
|
||||||
|
*/
|
||||||
|
class EndOfStreamException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
10
instafeed/vendor/binsoul/net-mqtt/src/Exception/MalformedPacketException.php
vendored
Executable file
10
instafeed/vendor/binsoul/net-mqtt/src/Exception/MalformedPacketException.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be thrown if a packet is malformed.
|
||||||
|
*/
|
||||||
|
class MalformedPacketException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
10
instafeed/vendor/binsoul/net-mqtt/src/Exception/UnknownPacketTypeException.php
vendored
Executable file
10
instafeed/vendor/binsoul/net-mqtt/src/Exception/UnknownPacketTypeException.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be thrown if a packet type is unknown.
|
||||||
|
*/
|
||||||
|
class UnknownPacketTypeException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
71
instafeed/vendor/binsoul/net-mqtt/src/Flow.php
vendored
Executable file
71
instafeed/vendor/binsoul/net-mqtt/src/Flow.php
vendored
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a sequence of packages exchanged between clients and brokers.
|
||||||
|
*/
|
||||||
|
interface Flow
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the unique code.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the flow.
|
||||||
|
*
|
||||||
|
* @return Packet|null First packet of the flow
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the flow can handle the given packet.
|
||||||
|
*
|
||||||
|
* @param Packet $packet Packet to accept
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function accept(Packet $packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continues the flow.
|
||||||
|
*
|
||||||
|
* @param Packet $packet Packet to respond
|
||||||
|
*
|
||||||
|
* @return Packet|null Next packet of the flow
|
||||||
|
*/
|
||||||
|
public function next(Packet $packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the flow is finished.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isFinished();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the flow finished successfully.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isSuccess();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of the flow if it finished successfully.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getResult();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an error message if the flow didn't finish successfully.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getErrorMessage();
|
||||||
|
}
|
||||||
74
instafeed/vendor/binsoul/net-mqtt/src/Flow/AbstractFlow.php
vendored
Executable file
74
instafeed/vendor/binsoul/net-mqtt/src/Flow/AbstractFlow.php
vendored
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Flow;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an abstract implementation of the {@see Flow} interface.
|
||||||
|
*/
|
||||||
|
abstract class AbstractFlow implements Flow
|
||||||
|
{
|
||||||
|
/** @var bool */
|
||||||
|
private $isFinished = false;
|
||||||
|
/** @var bool */
|
||||||
|
private $isSuccess = false;
|
||||||
|
/** @var mixed */
|
||||||
|
private $result;
|
||||||
|
/** @var string */
|
||||||
|
private $error = '';
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isFinished()
|
||||||
|
{
|
||||||
|
return $this->isFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSuccess()
|
||||||
|
{
|
||||||
|
return $this->isFinished && $this->isSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult()
|
||||||
|
{
|
||||||
|
return $this->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorMessage()
|
||||||
|
{
|
||||||
|
return $this->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the flow as successful and sets the result.
|
||||||
|
*
|
||||||
|
* @param mixed|null $result
|
||||||
|
*/
|
||||||
|
protected function succeed($result = null)
|
||||||
|
{
|
||||||
|
$this->isFinished = true;
|
||||||
|
$this->isSuccess = true;
|
||||||
|
$this->result = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the flow as failed and sets the error message.
|
||||||
|
*
|
||||||
|
* @param string $error
|
||||||
|
*/
|
||||||
|
protected function fail($error = '')
|
||||||
|
{
|
||||||
|
$this->isFinished = true;
|
||||||
|
$this->isSuccess = false;
|
||||||
|
$this->error = $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
instafeed/vendor/binsoul/net-mqtt/src/Flow/IncomingPingFlow.php
vendored
Executable file
23
instafeed/vendor/binsoul/net-mqtt/src/Flow/IncomingPingFlow.php
vendored
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PingResponsePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an incoming PING packet.
|
||||||
|
*/
|
||||||
|
class IncomingPingFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'pong';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$this->succeed();
|
||||||
|
|
||||||
|
return new PingResponsePacket();
|
||||||
|
}
|
||||||
|
}
|
||||||
80
instafeed/vendor/binsoul/net-mqtt/src/Flow/IncomingPublishFlow.php
vendored
Executable file
80
instafeed/vendor/binsoul/net-mqtt/src/Flow/IncomingPublishFlow.php
vendored
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Message;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishAckPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishCompletePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishReceivedPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishReleasePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an incoming PUBLISH packet.
|
||||||
|
*/
|
||||||
|
class IncomingPublishFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
/** @var int|null */
|
||||||
|
private $identifier;
|
||||||
|
/** @var Message */
|
||||||
|
private $message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Message $message
|
||||||
|
* @param int|null $identifier
|
||||||
|
*/
|
||||||
|
public function __construct(Message $message, $identifier = null)
|
||||||
|
{
|
||||||
|
$this->message = $message;
|
||||||
|
$this->identifier = $identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'message';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$packet = null;
|
||||||
|
$emit = true;
|
||||||
|
if ($this->message->getQosLevel() === 1) {
|
||||||
|
$packet = new PublishAckPacket();
|
||||||
|
} elseif ($this->message->getQosLevel() === 2) {
|
||||||
|
$packet = new PublishReceivedPacket();
|
||||||
|
$emit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($packet !== null) {
|
||||||
|
$packet->setIdentifier($this->identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($emit) {
|
||||||
|
$this->succeed($this->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
if ($this->message->getQosLevel() !== 2 || $packet->getPacketType() !== Packet::TYPE_PUBREL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var PublishReleasePacket $packet */
|
||||||
|
return $packet->getIdentifier() === $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
$this->succeed($this->message);
|
||||||
|
|
||||||
|
$response = new PublishCompletePacket();
|
||||||
|
$response->setIdentifier($this->identifier);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
70
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingConnectFlow.php
vendored
Executable file
70
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingConnectFlow.php
vendored
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Connection;
|
||||||
|
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\ConnectRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\ConnectResponsePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an outgoing CONNECT packet.
|
||||||
|
*/
|
||||||
|
class OutgoingConnectFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
/** @var Connection */
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Connection $connection
|
||||||
|
* @param IdentifierGenerator $generator
|
||||||
|
*/
|
||||||
|
public function __construct(Connection $connection, IdentifierGenerator $generator)
|
||||||
|
{
|
||||||
|
$this->connection = $connection;
|
||||||
|
|
||||||
|
if ($this->connection->getClientID() === '') {
|
||||||
|
$this->connection = $this->connection->withClientID($generator->generateClientID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'connect';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$packet = new ConnectRequestPacket();
|
||||||
|
$packet->setProtocolLevel($this->connection->getProtocol());
|
||||||
|
$packet->setKeepAlive($this->connection->getKeepAlive());
|
||||||
|
$packet->setClientID($this->connection->getClientID());
|
||||||
|
$packet->setCleanSession($this->connection->isCleanSession());
|
||||||
|
$packet->setUsername($this->connection->getUsername());
|
||||||
|
$packet->setPassword($this->connection->getPassword());
|
||||||
|
$will = $this->connection->getWill();
|
||||||
|
if ($will !== null && $will->getTopic() !== '' && $will->getPayload() !== '') {
|
||||||
|
$packet->setWill($will->getTopic(), $will->getPayload(), $will->getQosLevel(), $will->isRetained());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
return $packet->getPacketType() === Packet::TYPE_CONNACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
/** @var ConnectResponsePacket $packet */
|
||||||
|
if ($packet->isSuccess()) {
|
||||||
|
$this->succeed($this->connection);
|
||||||
|
} else {
|
||||||
|
$this->fail($packet->getErrorName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingDisconnectFlow.php
vendored
Executable file
37
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingDisconnectFlow.php
vendored
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Connection;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\DisconnectRequestPacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an outgoing DISCONNECT packet.
|
||||||
|
*/
|
||||||
|
class OutgoingDisconnectFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
/** @var Connection */
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Connection $connection
|
||||||
|
*/
|
||||||
|
public function __construct(Connection $connection)
|
||||||
|
{
|
||||||
|
$this->connection = $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'disconnect';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$this->succeed($this->connection);
|
||||||
|
|
||||||
|
return new DisconnectRequestPacket();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingPingFlow.php
vendored
Executable file
32
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingPingFlow.php
vendored
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PingRequestPacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an outgoing PING packet.
|
||||||
|
*/
|
||||||
|
class OutgoingPingFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'ping';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
return new PingRequestPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
return $packet->getPacketType() === Packet::TYPE_PINGRESP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
$this->succeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
102
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingPublishFlow.php
vendored
Executable file
102
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingPublishFlow.php
vendored
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||||
|
use BinSoul\Net\Mqtt\Message;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishAckPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishCompletePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishReceivedPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishReleasePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishRequestPacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an outgoing PUBLISH packet.
|
||||||
|
*/
|
||||||
|
class OutgoingPublishFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
/** @var int|null */
|
||||||
|
private $identifier;
|
||||||
|
/** @var Message */
|
||||||
|
private $message;
|
||||||
|
/** @var bool */
|
||||||
|
private $receivedPubRec = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Message $message
|
||||||
|
* @param IdentifierGenerator $generator
|
||||||
|
*/
|
||||||
|
public function __construct(Message $message, IdentifierGenerator $generator)
|
||||||
|
{
|
||||||
|
$this->message = $message;
|
||||||
|
if ($this->message->getQosLevel() > 0) {
|
||||||
|
$this->identifier = $generator->generatePacketID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'publish';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$packet = new PublishRequestPacket();
|
||||||
|
$packet->setTopic($this->message->getTopic());
|
||||||
|
$packet->setPayload($this->message->getPayload());
|
||||||
|
$packet->setRetained($this->message->isRetained());
|
||||||
|
$packet->setDuplicate($this->message->isDuplicate());
|
||||||
|
$packet->setQosLevel($this->message->getQosLevel());
|
||||||
|
|
||||||
|
if ($this->message->getQosLevel() === 0) {
|
||||||
|
$this->succeed($this->message);
|
||||||
|
} else {
|
||||||
|
$packet->setIdentifier($this->identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
if ($this->message->getQosLevel() === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$packetType = $packet->getPacketType();
|
||||||
|
|
||||||
|
if ($packetType === Packet::TYPE_PUBACK && $this->message->getQosLevel() === 1) {
|
||||||
|
/* @var PublishAckPacket $packet */
|
||||||
|
return $packet->getIdentifier() === $this->identifier;
|
||||||
|
} elseif ($this->message->getQosLevel() === 2) {
|
||||||
|
if ($packetType === Packet::TYPE_PUBREC) {
|
||||||
|
/* @var PublishReceivedPacket $packet */
|
||||||
|
return $packet->getIdentifier() === $this->identifier;
|
||||||
|
} elseif ($this->receivedPubRec && $packetType === Packet::TYPE_PUBCOMP) {
|
||||||
|
/* @var PublishCompletePacket $packet */
|
||||||
|
return $packet->getIdentifier() === $this->identifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
$packetType = $packet->getPacketType();
|
||||||
|
|
||||||
|
if ($packetType === Packet::TYPE_PUBACK || $packetType === Packet::TYPE_PUBCOMP) {
|
||||||
|
$this->succeed($this->message);
|
||||||
|
} elseif ($packetType === Packet::TYPE_PUBREC) {
|
||||||
|
$this->receivedPubRec = true;
|
||||||
|
|
||||||
|
$response = new PublishReleasePacket();
|
||||||
|
$response->setIdentifier($this->identifier);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingSubscribeFlow.php
vendored
Executable file
82
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingSubscribeFlow.php
vendored
Executable file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\SubscribeRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\SubscribeResponsePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Subscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an outgoing SUBSCRIBE packet.
|
||||||
|
*/
|
||||||
|
class OutgoingSubscribeFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
private $identifier;
|
||||||
|
/** @var Subscription[] */
|
||||||
|
private $subscriptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Subscription[] $subscriptions
|
||||||
|
* @param IdentifierGenerator $generator
|
||||||
|
*/
|
||||||
|
public function __construct(array $subscriptions, IdentifierGenerator $generator)
|
||||||
|
{
|
||||||
|
$this->subscriptions = array_values($subscriptions);
|
||||||
|
$this->identifier = $generator->generatePacketID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'subscribe';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$packet = new SubscribeRequestPacket();
|
||||||
|
$packet->setTopic($this->subscriptions[0]->getFilter());
|
||||||
|
$packet->setQosLevel($this->subscriptions[0]->getQosLevel());
|
||||||
|
$packet->setIdentifier($this->identifier);
|
||||||
|
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
if ($packet->getPacketType() !== Packet::TYPE_SUBACK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var SubscribeResponsePacket $packet */
|
||||||
|
return $packet->getIdentifier() === $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
/* @var SubscribeResponsePacket $packet */
|
||||||
|
$returnCodes = $packet->getReturnCodes();
|
||||||
|
if (count($returnCodes) !== count($this->subscriptions)) {
|
||||||
|
throw new \LogicException(
|
||||||
|
sprintf(
|
||||||
|
'SUBACK: Expected %d return codes but got %d.',
|
||||||
|
count($this->subscriptions),
|
||||||
|
count($returnCodes)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($returnCodes as $index => $code) {
|
||||||
|
if ($packet->isError($code)) {
|
||||||
|
$this->fail(sprintf('Failed to subscribe to "%s".', $this->subscriptions[$index]->getFilter()));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->succeed($this->subscriptions[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingUnsubscribeFlow.php
vendored
Executable file
61
instafeed/vendor/binsoul/net-mqtt/src/Flow/OutgoingUnsubscribeFlow.php
vendored
Executable file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Flow;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\IdentifierGenerator;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\UnsubscribeRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\UnsubscribeResponsePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Subscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a flow starting with an outgoing UNSUBSCRIBE packet.
|
||||||
|
*/
|
||||||
|
class OutgoingUnsubscribeFlow extends AbstractFlow
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
private $identifier;
|
||||||
|
/** @var Subscription[] */
|
||||||
|
private $subscriptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param Subscription[] $subscriptions
|
||||||
|
* @param IdentifierGenerator $generator
|
||||||
|
*/
|
||||||
|
public function __construct(array $subscriptions, IdentifierGenerator $generator)
|
||||||
|
{
|
||||||
|
$this->subscriptions = array_values($subscriptions);
|
||||||
|
$this->identifier = $generator->generatePacketID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCode()
|
||||||
|
{
|
||||||
|
return 'unsubscribe';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$packet = new UnsubscribeRequestPacket();
|
||||||
|
$packet->setTopic($this->subscriptions[0]->getFilter());
|
||||||
|
$packet->setIdentifier($this->identifier);
|
||||||
|
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(Packet $packet)
|
||||||
|
{
|
||||||
|
if ($packet->getPacketType() !== Packet::TYPE_UNSUBACK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var UnsubscribeResponsePacket $packet */
|
||||||
|
return $packet->getIdentifier() === $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(Packet $packet)
|
||||||
|
{
|
||||||
|
$this->succeed($this->subscriptions[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
instafeed/vendor/binsoul/net-mqtt/src/IdentifierGenerator.php
vendored
Executable file
23
instafeed/vendor/binsoul/net-mqtt/src/IdentifierGenerator.php
vendored
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates identifiers.
|
||||||
|
*/
|
||||||
|
interface IdentifierGenerator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates a packet identifier between 1 and 0xFFFF.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function generatePacketID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a client identifier of up to 23 bytes.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function generateClientID();
|
||||||
|
}
|
||||||
99
instafeed/vendor/binsoul/net-mqtt/src/Message.php
vendored
Executable file
99
instafeed/vendor/binsoul/net-mqtt/src/Message.php
vendored
Executable file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a message.
|
||||||
|
*/
|
||||||
|
interface Message
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the topic.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTopic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the payload.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPayload();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quality of service level.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getQosLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the message is a duplicate.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDuplicate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the message is retained.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isRetained();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message with the given topic.
|
||||||
|
*
|
||||||
|
* @param string $topic
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withTopic($topic);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message with the given payload.
|
||||||
|
*
|
||||||
|
* @param string $payload
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withPayload($payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message with the given quality of service level.
|
||||||
|
*
|
||||||
|
* @param int $level
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withQosLevel($level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message flagged as retained.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function retain();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message flagged as not retained.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function release();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message flagged as duplicate.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function duplicate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new message flagged as original.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function original();
|
||||||
|
}
|
||||||
52
instafeed/vendor/binsoul/net-mqtt/src/Packet.php
vendored
Executable file
52
instafeed/vendor/binsoul/net-mqtt/src/Packet.php
vendored
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a packet of the MQTT protocol.
|
||||||
|
*/
|
||||||
|
interface Packet
|
||||||
|
{
|
||||||
|
const TYPE_CONNECT = 1;
|
||||||
|
const TYPE_CONNACK = 2;
|
||||||
|
const TYPE_PUBLISH = 3;
|
||||||
|
const TYPE_PUBACK = 4;
|
||||||
|
const TYPE_PUBREC = 5;
|
||||||
|
const TYPE_PUBREL = 6;
|
||||||
|
const TYPE_PUBCOMP = 7;
|
||||||
|
const TYPE_SUBSCRIBE = 8;
|
||||||
|
const TYPE_SUBACK = 9;
|
||||||
|
const TYPE_UNSUBSCRIBE = 10;
|
||||||
|
const TYPE_UNSUBACK = 11;
|
||||||
|
const TYPE_PINGREQ = 12;
|
||||||
|
const TYPE_PINGRESP = 13;
|
||||||
|
const TYPE_DISCONNECT = 14;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the packet.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getPacketType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the packet from the given stream.
|
||||||
|
*
|
||||||
|
* @param PacketStream $stream
|
||||||
|
*/
|
||||||
|
public function read(PacketStream $stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the packet to the given stream.
|
||||||
|
*
|
||||||
|
* @param PacketStream $stream
|
||||||
|
*/
|
||||||
|
public function write(PacketStream $stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the serialized form of the packet.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString();
|
||||||
|
}
|
||||||
279
instafeed/vendor/binsoul/net-mqtt/src/Packet/BasePacket.php
vendored
Executable file
279
instafeed/vendor/binsoul/net-mqtt/src/Packet/BasePacket.php
vendored
Executable file
@@ -0,0 +1,279 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the base class for all packets.
|
||||||
|
*/
|
||||||
|
abstract class BasePacket implements Packet
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Type of the packet. See {@see Packet}.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected static $packetType = 0;
|
||||||
|
/**
|
||||||
|
* Flags of the packet.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $packetFlags = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes of a variable length packet.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $remainingPacketLength = 0;
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$output = new PacketStream();
|
||||||
|
$this->write($output);
|
||||||
|
|
||||||
|
return $output->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$byte = $stream->readByte();
|
||||||
|
|
||||||
|
if ($byte >> 4 !== static::$packetType) {
|
||||||
|
throw new MalformedPacketException(
|
||||||
|
sprintf(
|
||||||
|
'Expected packet type %02x but got %02x.',
|
||||||
|
$byte >> 4,
|
||||||
|
static::$packetType
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->packetFlags = $byte & 0x0F;
|
||||||
|
$this->readRemainingLength($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$stream->writeByte(((static::$packetType & 0x0F) << 4) + ($this->packetFlags & 0x0F));
|
||||||
|
$this->writeRemainingLength($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the remaining length from the given stream.
|
||||||
|
*
|
||||||
|
* @param PacketStream $stream
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
*/
|
||||||
|
private function readRemainingLength(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$this->remainingPacketLength = 0;
|
||||||
|
$multiplier = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$encodedByte = $stream->readByte();
|
||||||
|
|
||||||
|
$this->remainingPacketLength += ($encodedByte & 127) * $multiplier;
|
||||||
|
$multiplier *= 128;
|
||||||
|
|
||||||
|
if ($multiplier > 128 * 128 * 128 * 128) {
|
||||||
|
throw new MalformedPacketException('Malformed remaining length.');
|
||||||
|
}
|
||||||
|
} while (($encodedByte & 128) !== 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the remaining length to the given stream.
|
||||||
|
*
|
||||||
|
* @param PacketStream $stream
|
||||||
|
*/
|
||||||
|
private function writeRemainingLength(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$x = $this->remainingPacketLength;
|
||||||
|
do {
|
||||||
|
$encodedByte = $x % 128;
|
||||||
|
$x = (int) ($x / 128);
|
||||||
|
if ($x > 0) {
|
||||||
|
$encodedByte |= 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stream->writeByte($encodedByte);
|
||||||
|
} while ($x > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPacketType()
|
||||||
|
{
|
||||||
|
return static::$packetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the packet flags.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getPacketFlags()
|
||||||
|
{
|
||||||
|
return $this->packetFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remaining length.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRemainingPacketLength()
|
||||||
|
{
|
||||||
|
return $this->remainingPacketLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the packet flags have a specific value.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function assertPacketFlags($value, $fromPacket = true)
|
||||||
|
{
|
||||||
|
if ($this->packetFlags !== $value) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'Expected flags %02x but got %02x.',
|
||||||
|
$value,
|
||||||
|
$this->packetFlags
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the remaining length is greater than zero and has a specific value.
|
||||||
|
*
|
||||||
|
* @param int|null $value value to test or null if any value greater than zero is valid
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function assertRemainingPacketLength($value = null, $fromPacket = true)
|
||||||
|
{
|
||||||
|
if ($value === null && $this->remainingPacketLength === 0) {
|
||||||
|
$this->throwException('Expected payload but remaining packet length is zero.', $fromPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value !== null && $this->remainingPacketLength !== $value) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'Expected remaining packet length of %d bytes but got %d.',
|
||||||
|
$value,
|
||||||
|
$this->remainingPacketLength
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the given string is a well-formed MQTT string.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function assertValidStringLength($value, $fromPacket = true)
|
||||||
|
{
|
||||||
|
if (strlen($value) > 0xFFFF) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'The string "%s" is longer than 65535 byte.',
|
||||||
|
substr($value, 0, 50)
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the given string is a well-formed MQTT string.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function assertValidString($value, $fromPacket = true)
|
||||||
|
{
|
||||||
|
$this->assertValidStringLength($value, $fromPacket);
|
||||||
|
|
||||||
|
if (!mb_check_encoding($value, 'UTF-8')) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'The string "%s" is not well-formed UTF-8.',
|
||||||
|
substr($value, 0, 50)
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/[\xD8-\xDF][\x00-\xFF]|\x00\x00/x', $value)) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'The string "%s" contains invalid characters.',
|
||||||
|
substr($value, 0, 50)
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the given quality of service level is valid.
|
||||||
|
*
|
||||||
|
* @param int $level
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function assertValidQosLevel($level, $fromPacket = true)
|
||||||
|
{
|
||||||
|
if ($level < 0 || $level > 2) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'Expected a quality of service level between 0 and 2 but got %d.',
|
||||||
|
$level
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws a MalformedPacketException for packet validation and an InvalidArgumentException otherwise.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function throwException($message, $fromPacket)
|
||||||
|
{
|
||||||
|
if ($fromPacket) {
|
||||||
|
throw new MalformedPacketException($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \InvalidArgumentException($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
405
instafeed/vendor/binsoul/net-mqtt/src/Packet/ConnectRequestPacket.php
vendored
Executable file
405
instafeed/vendor/binsoul/net-mqtt/src/Packet/ConnectRequestPacket.php
vendored
Executable file
@@ -0,0 +1,405 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the CONNECT packet.
|
||||||
|
*/
|
||||||
|
class ConnectRequestPacket extends BasePacket
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
private $protocolLevel = 4;
|
||||||
|
/** @var string */
|
||||||
|
private $protocolName = 'MQTT';
|
||||||
|
/** @var int */
|
||||||
|
private $flags = 2;
|
||||||
|
/** @var string */
|
||||||
|
protected $clientID = '';
|
||||||
|
/** @var int */
|
||||||
|
private $keepAlive = 60;
|
||||||
|
/** @var string */
|
||||||
|
private $willTopic = '';
|
||||||
|
/** @var string */
|
||||||
|
private $willMessage = '';
|
||||||
|
/** @var string */
|
||||||
|
private $username = '';
|
||||||
|
/** @var string */
|
||||||
|
private $password = '';
|
||||||
|
|
||||||
|
protected static $packetType = Packet::TYPE_CONNECT;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
$this->assertPacketFlags(0);
|
||||||
|
$this->assertRemainingPacketLength();
|
||||||
|
|
||||||
|
$this->protocolName = $stream->readString();
|
||||||
|
$this->protocolLevel = $stream->readByte();
|
||||||
|
$this->flags = $stream->readByte();
|
||||||
|
$this->keepAlive = $stream->readWord();
|
||||||
|
$this->clientID = $stream->readString();
|
||||||
|
|
||||||
|
if ($this->hasWill()) {
|
||||||
|
$this->willTopic = $stream->readString();
|
||||||
|
$this->willMessage = $stream->readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasUsername()) {
|
||||||
|
$this->username = $stream->readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasPassword()) {
|
||||||
|
$this->password = $stream->readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertValidWill();
|
||||||
|
$this->assertValidString($this->clientID);
|
||||||
|
$this->assertValidString($this->willTopic);
|
||||||
|
$this->assertValidString($this->username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
if ($this->clientID === '') {
|
||||||
|
$this->clientID = 'BinSoul'.mt_rand(100000, 999999);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = new PacketStream();
|
||||||
|
|
||||||
|
$data->writeString($this->protocolName);
|
||||||
|
$data->writeByte($this->protocolLevel);
|
||||||
|
$data->writeByte($this->flags);
|
||||||
|
$data->writeWord($this->keepAlive);
|
||||||
|
$data->writeString($this->clientID);
|
||||||
|
|
||||||
|
if ($this->hasWill()) {
|
||||||
|
$data->writeString($this->willTopic);
|
||||||
|
$data->writeString($this->willMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasUsername()) {
|
||||||
|
$data->writeString($this->username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasPassword()) {
|
||||||
|
$data->writeString($this->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->remainingPacketLength = $data->length();
|
||||||
|
|
||||||
|
parent::write($stream);
|
||||||
|
$stream->write($data->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the protocol level.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getProtocolLevel()
|
||||||
|
{
|
||||||
|
return $this->protocolLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the protocol level.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setProtocolLevel($value)
|
||||||
|
{
|
||||||
|
if ($value < 3 || $value > 4) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Unknown protocol level %d.', $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->protocolLevel = $value;
|
||||||
|
if ($this->protocolLevel === 3) {
|
||||||
|
$this->protocolName = 'MQIsdp';
|
||||||
|
} elseif ($this->protocolLevel === 4) {
|
||||||
|
$this->protocolName = 'MQTT';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the client id.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getClientID()
|
||||||
|
{
|
||||||
|
return $this->clientID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the client id.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function setClientID($value)
|
||||||
|
{
|
||||||
|
$this->clientID = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the keep alive time in seconds.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getKeepAlive()
|
||||||
|
{
|
||||||
|
return $this->keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the keep alive time in seconds.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setKeepAlive($value)
|
||||||
|
{
|
||||||
|
if ($value > 65535) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
sprintf(
|
||||||
|
'Expected a keep alive time lower than 65535 but got %d.',
|
||||||
|
$value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->keepAlive = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the clean session flag is set.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isCleanSession()
|
||||||
|
{
|
||||||
|
return ($this->flags & 2) === 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the clean session flag.
|
||||||
|
*
|
||||||
|
* @param bool $value
|
||||||
|
*/
|
||||||
|
public function setCleanSession($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
$this->flags |= 2;
|
||||||
|
} else {
|
||||||
|
$this->flags &= ~2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if a will is set.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasWill()
|
||||||
|
{
|
||||||
|
return ($this->flags & 4) === 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the desired quality of service level of the will.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getWillQosLevel()
|
||||||
|
{
|
||||||
|
return ($this->flags & 24) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the will should be retained.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWillRetained()
|
||||||
|
{
|
||||||
|
return ($this->flags & 32) === 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the will topic.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getWillTopic()
|
||||||
|
{
|
||||||
|
return $this->willTopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the will message.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getWillMessage()
|
||||||
|
{
|
||||||
|
return $this->willMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the will.
|
||||||
|
*
|
||||||
|
* @param string $topic
|
||||||
|
* @param string $message
|
||||||
|
* @param int $qosLevel
|
||||||
|
* @param bool $isRetained
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setWill($topic, $message, $qosLevel = 0, $isRetained = false)
|
||||||
|
{
|
||||||
|
$this->assertValidString($topic, false);
|
||||||
|
if ($topic === '') {
|
||||||
|
throw new \InvalidArgumentException('The topic must not be empty.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertValidStringLength($message, false);
|
||||||
|
if ($message === '') {
|
||||||
|
throw new \InvalidArgumentException('The message must not be empty.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertValidQosLevel($qosLevel, false);
|
||||||
|
|
||||||
|
$this->willTopic = $topic;
|
||||||
|
$this->willMessage = $message;
|
||||||
|
|
||||||
|
$this->flags |= 4;
|
||||||
|
$this->flags |= ($qosLevel << 3);
|
||||||
|
|
||||||
|
if ($isRetained) {
|
||||||
|
$this->flags |= 32;
|
||||||
|
} else {
|
||||||
|
$this->flags &= ~32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the will.
|
||||||
|
*/
|
||||||
|
public function removeWill()
|
||||||
|
{
|
||||||
|
$this->flags &= ~60;
|
||||||
|
$this->willTopic = '';
|
||||||
|
$this->willMessage = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if a username is set.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasUsername()
|
||||||
|
{
|
||||||
|
return $this->flags & 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUsername()
|
||||||
|
{
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the username.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setUsername($value)
|
||||||
|
{
|
||||||
|
$this->assertValidString($value, false);
|
||||||
|
|
||||||
|
$this->username = $value;
|
||||||
|
if ($this->username !== '') {
|
||||||
|
$this->flags |= 64;
|
||||||
|
} else {
|
||||||
|
$this->flags &= ~64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if a password is set.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasPassword()
|
||||||
|
{
|
||||||
|
return $this->flags & 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the password.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPassword()
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the password.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setPassword($value)
|
||||||
|
{
|
||||||
|
$this->assertValidStringLength($value, false);
|
||||||
|
|
||||||
|
$this->password = $value;
|
||||||
|
if ($this->password !== '') {
|
||||||
|
$this->flags |= 128;
|
||||||
|
} else {
|
||||||
|
$this->flags &= ~128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that all will flags and quality of service are correct.
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
*/
|
||||||
|
private function assertValidWill()
|
||||||
|
{
|
||||||
|
if ($this->hasWill()) {
|
||||||
|
$this->assertValidQosLevel($this->getWillQosLevel(), true);
|
||||||
|
} else {
|
||||||
|
if ($this->getWillQosLevel() > 0) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'Expected a will quality of service level of zero but got %d.',
|
||||||
|
$this->getWillQosLevel()
|
||||||
|
),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isWillRetained()) {
|
||||||
|
$this->throwException('There is not will but the will retain flag is set.', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
instafeed/vendor/binsoul/net-mqtt/src/Packet/ConnectResponsePacket.php
vendored
Executable file
111
instafeed/vendor/binsoul/net-mqtt/src/Packet/ConnectResponsePacket.php
vendored
Executable file
@@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the CONNACK packet.
|
||||||
|
*/
|
||||||
|
class ConnectResponsePacket extends BasePacket
|
||||||
|
{
|
||||||
|
/** @var string[][] */
|
||||||
|
private static $returnCodes = [
|
||||||
|
0 => [
|
||||||
|
'Connection accepted',
|
||||||
|
'',
|
||||||
|
],
|
||||||
|
1 => [
|
||||||
|
'Unacceptable protocol version',
|
||||||
|
'The Server does not support the level of the MQTT protocol requested by the client.',
|
||||||
|
],
|
||||||
|
2 => [
|
||||||
|
'Identifier rejected',
|
||||||
|
'The client identifier is correct UTF-8 but not allowed by the server.',
|
||||||
|
],
|
||||||
|
3 => [
|
||||||
|
'Server unavailable',
|
||||||
|
'The network connection has been made but the MQTT service is unavailable',
|
||||||
|
],
|
||||||
|
4 => [
|
||||||
|
'Bad user name or password',
|
||||||
|
'The data in the user name or password is malformed.',
|
||||||
|
],
|
||||||
|
5 => [
|
||||||
|
'Not authorized',
|
||||||
|
'The client is not authorized to connect.',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $flags = 0;
|
||||||
|
/** @var int */
|
||||||
|
private $returnCode;
|
||||||
|
|
||||||
|
protected static $packetType = Packet::TYPE_CONNACK;
|
||||||
|
protected $remainingPacketLength = 2;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
$this->assertPacketFlags(0);
|
||||||
|
$this->assertRemainingPacketLength(2);
|
||||||
|
|
||||||
|
$this->flags = $stream->readByte();
|
||||||
|
$this->returnCode = $stream->readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$this->remainingPacketLength = 2;
|
||||||
|
parent::write($stream);
|
||||||
|
|
||||||
|
$stream->writeByte($this->flags);
|
||||||
|
$stream->writeByte($this->returnCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the return code.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getReturnCode()
|
||||||
|
{
|
||||||
|
return $this->returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the connection was successful.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isSuccess()
|
||||||
|
{
|
||||||
|
return $this->returnCode === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the connection failed.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isError()
|
||||||
|
{
|
||||||
|
return $this->returnCode > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the returned error code.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getErrorName()
|
||||||
|
{
|
||||||
|
if (isset(self::$returnCodes[$this->returnCode])) {
|
||||||
|
return self::$returnCodes[$this->returnCode][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Error '.$this->returnCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
instafeed/vendor/binsoul/net-mqtt/src/Packet/DisconnectRequestPacket.php
vendored
Executable file
22
instafeed/vendor/binsoul/net-mqtt/src/Packet/DisconnectRequestPacket.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the DISCONNECT packet.
|
||||||
|
*/
|
||||||
|
class DisconnectRequestPacket extends BasePacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_DISCONNECT;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
|
||||||
|
$this->assertPacketFlags(0);
|
||||||
|
$this->assertRemainingPacketLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
62
instafeed/vendor/binsoul/net-mqtt/src/Packet/IdentifiablePacket.php
vendored
Executable file
62
instafeed/vendor/binsoul/net-mqtt/src/Packet/IdentifiablePacket.php
vendored
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides methods for packets with an identifier.
|
||||||
|
*/
|
||||||
|
trait IdentifiablePacket
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
private static $nextIdentifier = 0;
|
||||||
|
/** @var int|null */
|
||||||
|
protected $identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier or generates a new one.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function generateIdentifier()
|
||||||
|
{
|
||||||
|
if ($this->identifier === null) {
|
||||||
|
++self::$nextIdentifier;
|
||||||
|
self::$nextIdentifier &= 0xFFFF;
|
||||||
|
|
||||||
|
$this->identifier = self::$nextIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier.
|
||||||
|
*
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function getIdentifier()
|
||||||
|
{
|
||||||
|
return $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the identifier.
|
||||||
|
*
|
||||||
|
* @param int|null $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setIdentifier($value)
|
||||||
|
{
|
||||||
|
if ($value !== null && ($value < 0 || $value > 0xFFFF)) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
sprintf(
|
||||||
|
'Expected an identifier between 0x0000 and 0xFFFF but got %x',
|
||||||
|
$value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->identifier = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
instafeed/vendor/binsoul/net-mqtt/src/Packet/IdentifierOnlyPacket.php
vendored
Executable file
42
instafeed/vendor/binsoul/net-mqtt/src/Packet/IdentifierOnlyPacket.php
vendored
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a base class for PUB* packets.
|
||||||
|
*/
|
||||||
|
abstract class IdentifierOnlyPacket extends BasePacket
|
||||||
|
{
|
||||||
|
use IdentifiablePacket;
|
||||||
|
|
||||||
|
protected $remainingPacketLength = 2;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
$this->assertPacketFlags($this->getExpectedPacketFlags());
|
||||||
|
$this->assertRemainingPacketLength(2);
|
||||||
|
|
||||||
|
$this->identifier = $stream->readWord();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$this->remainingPacketLength = 2;
|
||||||
|
parent::write($stream);
|
||||||
|
|
||||||
|
$stream->writeWord($this->generateIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the expected packet flags.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function getExpectedPacketFlags()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
instafeed/vendor/binsoul/net-mqtt/src/Packet/PingRequestPacket.php
vendored
Executable file
22
instafeed/vendor/binsoul/net-mqtt/src/Packet/PingRequestPacket.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PINGREQ packet.
|
||||||
|
*/
|
||||||
|
class PingRequestPacket extends BasePacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_PINGREQ;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
|
||||||
|
$this->assertPacketFlags(0);
|
||||||
|
$this->assertRemainingPacketLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
instafeed/vendor/binsoul/net-mqtt/src/Packet/PingResponsePacket.php
vendored
Executable file
22
instafeed/vendor/binsoul/net-mqtt/src/Packet/PingResponsePacket.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PINGRESP packet.
|
||||||
|
*/
|
||||||
|
class PingResponsePacket extends BasePacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_PINGRESP;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
|
||||||
|
$this->assertPacketFlags(0);
|
||||||
|
$this->assertRemainingPacketLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishAckPacket.php
vendored
Executable file
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishAckPacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PUBACK packet.
|
||||||
|
*/
|
||||||
|
class PublishAckPacket extends IdentifierOnlyPacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_PUBACK;
|
||||||
|
}
|
||||||
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishCompletePacket.php
vendored
Executable file
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishCompletePacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PUBCOMP packet.
|
||||||
|
*/
|
||||||
|
class PublishCompletePacket extends IdentifierOnlyPacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_PUBCOMP;
|
||||||
|
}
|
||||||
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishReceivedPacket.php
vendored
Executable file
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishReceivedPacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PUBREC packet.
|
||||||
|
*/
|
||||||
|
class PublishReceivedPacket extends IdentifierOnlyPacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_PUBREC;
|
||||||
|
}
|
||||||
19
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishReleasePacket.php
vendored
Executable file
19
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishReleasePacket.php
vendored
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PUBREL packet.
|
||||||
|
*/
|
||||||
|
class PublishReleasePacket extends IdentifierOnlyPacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_PUBREL;
|
||||||
|
protected $packetFlags = 2;
|
||||||
|
|
||||||
|
protected function getExpectedPacketFlags()
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
176
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishRequestPacket.php
vendored
Executable file
176
instafeed/vendor/binsoul/net-mqtt/src/Packet/PublishRequestPacket.php
vendored
Executable file
@@ -0,0 +1,176 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the PUBLISH packet.
|
||||||
|
*/
|
||||||
|
class PublishRequestPacket extends BasePacket
|
||||||
|
{
|
||||||
|
use IdentifiablePacket;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $topic;
|
||||||
|
/** @var string */
|
||||||
|
private $payload;
|
||||||
|
|
||||||
|
protected static $packetType = Packet::TYPE_PUBLISH;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
$this->assertRemainingPacketLength();
|
||||||
|
|
||||||
|
$originalPosition = $stream->getPosition();
|
||||||
|
$this->topic = $stream->readString();
|
||||||
|
$this->identifier = null;
|
||||||
|
if ($this->getQosLevel() > 0) {
|
||||||
|
$this->identifier = $stream->readWord();
|
||||||
|
}
|
||||||
|
|
||||||
|
$payloadLength = $this->remainingPacketLength - ($stream->getPosition() - $originalPosition);
|
||||||
|
$this->payload = $stream->read($payloadLength);
|
||||||
|
|
||||||
|
$this->assertValidQosLevel($this->getQosLevel());
|
||||||
|
$this->assertValidString($this->topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$data = new PacketStream();
|
||||||
|
|
||||||
|
$data->writeString($this->topic);
|
||||||
|
if ($this->getQosLevel() > 0) {
|
||||||
|
$data->writeWord($this->generateIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
$data->write($this->payload);
|
||||||
|
|
||||||
|
$this->remainingPacketLength = $data->length();
|
||||||
|
|
||||||
|
parent::write($stream);
|
||||||
|
$stream->write($data->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the topic.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTopic()
|
||||||
|
{
|
||||||
|
return $this->topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the topic.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setTopic($value)
|
||||||
|
{
|
||||||
|
$this->assertValidString($value, false);
|
||||||
|
if ($value === '') {
|
||||||
|
throw new \InvalidArgumentException('The topic must not be empty.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->topic = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the payload.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPayload()
|
||||||
|
{
|
||||||
|
return $this->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the payload.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function setPayload($value)
|
||||||
|
{
|
||||||
|
$this->payload = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the packet is a duplicate.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDuplicate()
|
||||||
|
{
|
||||||
|
return ($this->packetFlags & 8) === 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the packet as duplicate.
|
||||||
|
*
|
||||||
|
* @param bool $value
|
||||||
|
*/
|
||||||
|
public function setDuplicate($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
$this->packetFlags |= 8;
|
||||||
|
} else {
|
||||||
|
$this->packetFlags &= ~8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the packet is retained.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isRetained()
|
||||||
|
{
|
||||||
|
return ($this->packetFlags & 1) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the packet as retained.
|
||||||
|
*
|
||||||
|
* @param bool $value
|
||||||
|
*/
|
||||||
|
public function setRetained($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
$this->packetFlags |= 1;
|
||||||
|
} else {
|
||||||
|
$this->packetFlags &= ~1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quality of service level.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getQosLevel()
|
||||||
|
{
|
||||||
|
return ($this->packetFlags & 6) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the quality of service level.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setQosLevel($value)
|
||||||
|
{
|
||||||
|
$this->assertValidQosLevel($value, false);
|
||||||
|
|
||||||
|
$this->packetFlags |= ($value & 3) << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
66
instafeed/vendor/binsoul/net-mqtt/src/Packet/StrictConnectRequestPacket.php
vendored
Executable file
66
instafeed/vendor/binsoul/net-mqtt/src/Packet/StrictConnectRequestPacket.php
vendored
Executable file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the CONNECT packet with strict rules for client ids.
|
||||||
|
*/
|
||||||
|
class StrictConnectRequestPacket extends ConnectRequestPacket
|
||||||
|
{
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
|
||||||
|
$this->assertValidClientID($this->clientID, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the client id.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setClientID($value)
|
||||||
|
{
|
||||||
|
$this->assertValidClientID($value, false);
|
||||||
|
|
||||||
|
$this->clientID = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that a client id is shorter than 24 bytes and only contains characters 0-9, a-z or A-Z.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
private function assertValidClientID($value, $fromPacket)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (strlen($value) > 23) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'Expected client id shorter than 24 bytes but got "%s".',
|
||||||
|
$value
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value !== '' && !ctype_alnum($value)) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf(
|
||||||
|
'Expected a client id containing characters 0-9, a-z or A-Z but got "%s".',
|
||||||
|
$value
|
||||||
|
),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
instafeed/vendor/binsoul/net-mqtt/src/Packet/SubscribeRequestPacket.php
vendored
Executable file
101
instafeed/vendor/binsoul/net-mqtt/src/Packet/SubscribeRequestPacket.php
vendored
Executable file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the SUBSCRIBE packet.
|
||||||
|
*/
|
||||||
|
class SubscribeRequestPacket extends BasePacket
|
||||||
|
{
|
||||||
|
use IdentifiablePacket;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $topic;
|
||||||
|
/** @var int */
|
||||||
|
private $qosLevel;
|
||||||
|
|
||||||
|
protected static $packetType = Packet::TYPE_SUBSCRIBE;
|
||||||
|
protected $packetFlags = 2;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
$this->assertPacketFlags(2);
|
||||||
|
$this->assertRemainingPacketLength();
|
||||||
|
|
||||||
|
$this->identifier = $stream->readWord();
|
||||||
|
$this->topic = $stream->readString();
|
||||||
|
$this->qosLevel = $stream->readByte();
|
||||||
|
|
||||||
|
$this->assertValidQosLevel($this->qosLevel);
|
||||||
|
$this->assertValidString($this->topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$data = new PacketStream();
|
||||||
|
|
||||||
|
$data->writeWord($this->generateIdentifier());
|
||||||
|
$data->writeString($this->topic);
|
||||||
|
$data->writeByte($this->qosLevel);
|
||||||
|
|
||||||
|
$this->remainingPacketLength = $data->length();
|
||||||
|
|
||||||
|
parent::write($stream);
|
||||||
|
$stream->write($data->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the topic.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTopic()
|
||||||
|
{
|
||||||
|
return $this->topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the topic.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setTopic($value)
|
||||||
|
{
|
||||||
|
$this->assertValidString($value, false);
|
||||||
|
if ($value === '') {
|
||||||
|
throw new \InvalidArgumentException('The topic must not be empty.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->topic = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quality of service level.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getQosLevel()
|
||||||
|
{
|
||||||
|
return $this->qosLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the quality of service level.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setQosLevel($value)
|
||||||
|
{
|
||||||
|
$this->assertValidQosLevel($value, false);
|
||||||
|
|
||||||
|
$this->qosLevel = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
132
instafeed/vendor/binsoul/net-mqtt/src/Packet/SubscribeResponsePacket.php
vendored
Executable file
132
instafeed/vendor/binsoul/net-mqtt/src/Packet/SubscribeResponsePacket.php
vendored
Executable file
@@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the SUBACK packet.
|
||||||
|
*/
|
||||||
|
class SubscribeResponsePacket extends BasePacket
|
||||||
|
{
|
||||||
|
use IdentifiablePacket;
|
||||||
|
|
||||||
|
private static $qosLevels = [
|
||||||
|
0 => ['Maximum QoS 0'],
|
||||||
|
1 => ['Maximum QoS 1'],
|
||||||
|
2 => ['Maximum QoS 2'],
|
||||||
|
128 => ['Failure'],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var int[] */
|
||||||
|
private $returnCodes;
|
||||||
|
|
||||||
|
protected static $packetType = Packet::TYPE_SUBACK;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
$this->assertPacketFlags(0);
|
||||||
|
$this->assertRemainingPacketLength();
|
||||||
|
|
||||||
|
$this->identifier = $stream->readWord();
|
||||||
|
|
||||||
|
$returnCodeLength = $this->remainingPacketLength - 2;
|
||||||
|
for ($n = 0; $n < $returnCodeLength; ++$n) {
|
||||||
|
$returnCode = $stream->readByte();
|
||||||
|
$this->assertValidReturnCode($returnCode);
|
||||||
|
|
||||||
|
$this->returnCodes[] = $returnCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$data = new PacketStream();
|
||||||
|
|
||||||
|
$data->writeWord($this->generateIdentifier());
|
||||||
|
foreach ($this->returnCodes as $returnCode) {
|
||||||
|
$data->writeByte($returnCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->remainingPacketLength = $data->length();
|
||||||
|
|
||||||
|
parent::write($stream);
|
||||||
|
$stream->write($data->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the given return code is an error.
|
||||||
|
*
|
||||||
|
* @param int $returnCode
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isError($returnCode)
|
||||||
|
{
|
||||||
|
return $returnCode === 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the given return code is an error.
|
||||||
|
*
|
||||||
|
* @param int $returnCode
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getReturnCodeName($returnCode)
|
||||||
|
{
|
||||||
|
if (isset(self::$qosLevels[$returnCode])) {
|
||||||
|
return self::$qosLevels[$returnCode][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Unknown '.$returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the return codes.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getReturnCodes()
|
||||||
|
{
|
||||||
|
return $this->returnCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the return codes.
|
||||||
|
*
|
||||||
|
* @param int[] $value
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setReturnCodes(array $value)
|
||||||
|
{
|
||||||
|
foreach ($value as $returnCode) {
|
||||||
|
$this->assertValidReturnCode($returnCode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->returnCodes = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that a return code is valid.
|
||||||
|
*
|
||||||
|
* @param int $returnCode
|
||||||
|
* @param bool $fromPacket
|
||||||
|
*
|
||||||
|
* @throws MalformedPacketException
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
private function assertValidReturnCode($returnCode, $fromPacket = true)
|
||||||
|
{
|
||||||
|
if (!in_array($returnCode, [0, 1, 2, 128])) {
|
||||||
|
$this->throwException(
|
||||||
|
sprintf('Malformed return code %02x.', $returnCode),
|
||||||
|
$fromPacket
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
instafeed/vendor/binsoul/net-mqtt/src/Packet/UnsubscribeRequestPacket.php
vendored
Executable file
68
instafeed/vendor/binsoul/net-mqtt/src/Packet/UnsubscribeRequestPacket.php
vendored
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\PacketStream;
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the UNSUBSCRIBE packet.
|
||||||
|
*/
|
||||||
|
class UnsubscribeRequestPacket extends BasePacket
|
||||||
|
{
|
||||||
|
use IdentifiablePacket;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $topic;
|
||||||
|
|
||||||
|
protected static $packetType = Packet::TYPE_UNSUBSCRIBE;
|
||||||
|
protected $packetFlags = 2;
|
||||||
|
|
||||||
|
public function read(PacketStream $stream)
|
||||||
|
{
|
||||||
|
parent::read($stream);
|
||||||
|
|
||||||
|
$this->assertPacketFlags(2);
|
||||||
|
$this->assertRemainingPacketLength();
|
||||||
|
|
||||||
|
$originalPosition = $stream->getPosition();
|
||||||
|
|
||||||
|
do {
|
||||||
|
$this->identifier = $stream->readWord();
|
||||||
|
$this->topic = $stream->readString();
|
||||||
|
} while (($stream->getPosition() - $originalPosition) <= $this->remainingPacketLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(PacketStream $stream)
|
||||||
|
{
|
||||||
|
$data = new PacketStream();
|
||||||
|
|
||||||
|
$data->writeWord($this->generateIdentifier());
|
||||||
|
$data->writeString($this->topic);
|
||||||
|
|
||||||
|
$this->remainingPacketLength = $data->length();
|
||||||
|
|
||||||
|
parent::write($stream);
|
||||||
|
$stream->write($data->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the topic.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTopic()
|
||||||
|
{
|
||||||
|
return $this->topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the topic.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function setTopic($value)
|
||||||
|
{
|
||||||
|
$this->topic = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/UnsubscribeResponsePacket.php
vendored
Executable file
13
instafeed/vendor/binsoul/net-mqtt/src/Packet/UnsubscribeResponsePacket.php
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the UNSUBACK packet.
|
||||||
|
*/
|
||||||
|
class UnsubscribeResponsePacket extends IdentifierOnlyPacket
|
||||||
|
{
|
||||||
|
protected static $packetType = Packet::TYPE_UNSUBACK;
|
||||||
|
}
|
||||||
67
instafeed/vendor/binsoul/net-mqtt/src/PacketFactory.php
vendored
Executable file
67
instafeed/vendor/binsoul/net-mqtt/src/PacketFactory.php
vendored
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\UnknownPacketTypeException;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\ConnectRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\ConnectResponsePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\DisconnectRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PingRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PingResponsePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishAckPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishCompletePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishReceivedPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\PublishReleasePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\SubscribeRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\SubscribeResponsePacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\UnsubscribeRequestPacket;
|
||||||
|
use BinSoul\Net\Mqtt\Packet\UnsubscribeResponsePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds instances of the {@see Packet} interface.
|
||||||
|
*/
|
||||||
|
class PacketFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Map of packet types to packet classes.
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private static $mapping = [
|
||||||
|
Packet::TYPE_CONNECT => ConnectRequestPacket::class,
|
||||||
|
Packet::TYPE_CONNACK => ConnectResponsePacket::class,
|
||||||
|
Packet::TYPE_PUBLISH => PublishRequestPacket::class,
|
||||||
|
Packet::TYPE_PUBACK => PublishAckPacket::class,
|
||||||
|
Packet::TYPE_PUBREC => PublishReceivedPacket::class,
|
||||||
|
Packet::TYPE_PUBREL => PublishReleasePacket::class,
|
||||||
|
Packet::TYPE_PUBCOMP => PublishCompletePacket::class,
|
||||||
|
Packet::TYPE_SUBSCRIBE => SubscribeRequestPacket::class,
|
||||||
|
Packet::TYPE_SUBACK => SubscribeResponsePacket::class,
|
||||||
|
Packet::TYPE_UNSUBSCRIBE => UnsubscribeRequestPacket::class,
|
||||||
|
Packet::TYPE_UNSUBACK => UnsubscribeResponsePacket::class,
|
||||||
|
Packet::TYPE_PINGREQ => PingRequestPacket::class,
|
||||||
|
Packet::TYPE_PINGRESP => PingResponsePacket::class,
|
||||||
|
Packet::TYPE_DISCONNECT => DisconnectRequestPacket::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a packet object for the given type.
|
||||||
|
*
|
||||||
|
* @param int $type
|
||||||
|
*
|
||||||
|
* @throws UnknownPacketTypeException
|
||||||
|
*
|
||||||
|
* @return Packet
|
||||||
|
*/
|
||||||
|
public function build($type)
|
||||||
|
{
|
||||||
|
if (!isset(self::$mapping[$type])) {
|
||||||
|
throw new UnknownPacketTypeException(sprintf('Unknown packet type %d.', $type));
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = self::$mapping[$type];
|
||||||
|
|
||||||
|
return new $class();
|
||||||
|
}
|
||||||
|
}
|
||||||
216
instafeed/vendor/binsoul/net-mqtt/src/PacketStream.php
vendored
Executable file
216
instafeed/vendor/binsoul/net-mqtt/src/PacketStream.php
vendored
Executable file
@@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\EndOfStreamException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides methods to operate on a stream of bytes.
|
||||||
|
*/
|
||||||
|
class PacketStream
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $data;
|
||||||
|
/** @var int */
|
||||||
|
private $position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*
|
||||||
|
* @param string $data initial data of the stream
|
||||||
|
*/
|
||||||
|
public function __construct($data = '')
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
$this->position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the desired number of bytes.
|
||||||
|
*
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @throws EndOfStreamException
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function read($count)
|
||||||
|
{
|
||||||
|
$contentLength = strlen($this->data);
|
||||||
|
if ($this->position > $contentLength || $count > $contentLength - $this->position) {
|
||||||
|
throw new EndOfStreamException(
|
||||||
|
sprintf(
|
||||||
|
'End of stream reached when trying to read %d bytes. content length=%d, position=%d',
|
||||||
|
$count,
|
||||||
|
$contentLength,
|
||||||
|
$this->position
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunk = substr($this->data, $this->position, $count);
|
||||||
|
if ($chunk === false) {
|
||||||
|
$chunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$readBytes = strlen($chunk);
|
||||||
|
$this->position += $readBytes;
|
||||||
|
|
||||||
|
return $chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a single byte.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function readByte()
|
||||||
|
{
|
||||||
|
return ord($this->read(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a single word.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function readWord()
|
||||||
|
{
|
||||||
|
return ($this->readByte() << 8) + $this->readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a length prefixed string.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function readString()
|
||||||
|
{
|
||||||
|
$length = $this->readWord();
|
||||||
|
|
||||||
|
return $this->read($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the given value.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function write($value)
|
||||||
|
{
|
||||||
|
$this->data .= $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a single byte.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*/
|
||||||
|
public function writeByte($value)
|
||||||
|
{
|
||||||
|
$this->write(chr($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a single word.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*/
|
||||||
|
public function writeWord($value)
|
||||||
|
{
|
||||||
|
$this->write(chr(($value & 0xFFFF) >> 8));
|
||||||
|
$this->write(chr($value & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a length prefixed string.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
*/
|
||||||
|
public function writeString($string)
|
||||||
|
{
|
||||||
|
$this->writeWord(strlen($string));
|
||||||
|
$this->write($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of the stream.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function length()
|
||||||
|
{
|
||||||
|
return strlen($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes until the end of the stream.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRemainingBytes()
|
||||||
|
{
|
||||||
|
return $this->length() - $this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the whole content of the stream.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the internal position of the stream relative to the current position.
|
||||||
|
*
|
||||||
|
* @param int $offset
|
||||||
|
*/
|
||||||
|
public function seek($offset)
|
||||||
|
{
|
||||||
|
$this->position += $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the internal position of the stream.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getPosition()
|
||||||
|
{
|
||||||
|
return $this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal position of the stream.
|
||||||
|
*
|
||||||
|
* @param int $value
|
||||||
|
*/
|
||||||
|
public function setPosition($value)
|
||||||
|
{
|
||||||
|
$this->position = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all bytes from the beginning to the current position.
|
||||||
|
*/
|
||||||
|
public function cut()
|
||||||
|
{
|
||||||
|
$this->data = substr($this->data, $this->position);
|
||||||
|
if ($this->data === false) {
|
||||||
|
$this->data = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->position = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
90
instafeed/vendor/binsoul/net-mqtt/src/StreamParser.php
vendored
Executable file
90
instafeed/vendor/binsoul/net-mqtt/src/StreamParser.php
vendored
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
use BinSoul\Net\Mqtt\Exception\EndOfStreamException;
|
||||||
|
use BinSoul\Net\Mqtt\Exception\MalformedPacketException;
|
||||||
|
use BinSoul\Net\Mqtt\Exception\UnknownPacketTypeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides methods to parse a stream of bytes into packets.
|
||||||
|
*/
|
||||||
|
class StreamParser
|
||||||
|
{
|
||||||
|
/** @var PacketStream */
|
||||||
|
private $buffer;
|
||||||
|
/** @var PacketFactory */
|
||||||
|
private $factory;
|
||||||
|
/** @var callable */
|
||||||
|
private $errorCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of this class.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->buffer = new PacketStream();
|
||||||
|
$this->factory = new PacketFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an error callback.
|
||||||
|
*
|
||||||
|
* @param callable $callback
|
||||||
|
*/
|
||||||
|
public function onError($callback)
|
||||||
|
{
|
||||||
|
$this->errorCallback = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the given data to the internal buffer and parses it.
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
*
|
||||||
|
* @return Packet[]
|
||||||
|
*/
|
||||||
|
public function push($data)
|
||||||
|
{
|
||||||
|
$this->buffer->write($data);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
while ($this->buffer->getRemainingBytes() > 0) {
|
||||||
|
$type = $this->buffer->readByte() >> 4;
|
||||||
|
try {
|
||||||
|
$packet = $this->factory->build($type);
|
||||||
|
} catch (UnknownPacketTypeException $e) {
|
||||||
|
$this->handleError($e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->buffer->seek(-1);
|
||||||
|
$position = $this->buffer->getPosition();
|
||||||
|
try {
|
||||||
|
$packet->read($this->buffer);
|
||||||
|
$result[] = $packet;
|
||||||
|
$this->buffer->cut();
|
||||||
|
} catch (EndOfStreamException $e) {
|
||||||
|
$this->buffer->setPosition($position);
|
||||||
|
break;
|
||||||
|
} catch (MalformedPacketException $e) {
|
||||||
|
$this->handleError($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the registered error callback.
|
||||||
|
*
|
||||||
|
* @param \Throwable $exception
|
||||||
|
*/
|
||||||
|
private function handleError($exception)
|
||||||
|
{
|
||||||
|
if ($this->errorCallback !== null) {
|
||||||
|
$callback = $this->errorCallback;
|
||||||
|
$callback($exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
instafeed/vendor/binsoul/net-mqtt/src/Subscription.php
vendored
Executable file
41
instafeed/vendor/binsoul/net-mqtt/src/Subscription.php
vendored
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a subscription.
|
||||||
|
*/
|
||||||
|
interface Subscription
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the topic filter.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFilter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quality of service level.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getQosLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new subscription with the given topic filter.
|
||||||
|
*
|
||||||
|
* @param string $filter
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withFilter($filter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new subscription with the given quality of service level.
|
||||||
|
*
|
||||||
|
* @param int $level
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withQosLevel($level);
|
||||||
|
}
|
||||||
53
instafeed/vendor/binsoul/net-mqtt/src/TopicMatcher.php
vendored
Executable file
53
instafeed/vendor/binsoul/net-mqtt/src/TopicMatcher.php
vendored
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace BinSoul\Net\Mqtt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a topic filter with an actual topic.
|
||||||
|
*
|
||||||
|
* @author Alin Eugen Deac <ade@vestergaardcompany.com>
|
||||||
|
*/
|
||||||
|
class TopicMatcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if the given topic matches the filter.
|
||||||
|
*
|
||||||
|
* @param string $filter e.g. A/B/+, A/B/#
|
||||||
|
* @param string $topic e.g. A/B/C, A/B/foo/bar/baz
|
||||||
|
*
|
||||||
|
* @return bool true if topic matches the pattern
|
||||||
|
*/
|
||||||
|
public function matches($filter, $topic)
|
||||||
|
{
|
||||||
|
// Created by Steffen (https://github.com/kernelguy)
|
||||||
|
$tokens = explode('/', $filter);
|
||||||
|
$parts = [];
|
||||||
|
for ($i = 0, $count = count($tokens); $i < $count; ++$i) {
|
||||||
|
$token = $tokens[$i];
|
||||||
|
switch ($token) {
|
||||||
|
case '+':
|
||||||
|
$parts[] = '[^/#\+]*';
|
||||||
|
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
if ($i === 0) {
|
||||||
|
$parts[] = '[^\+\$]*';
|
||||||
|
} else {
|
||||||
|
$parts[] = '[^\+]*';
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$parts[] = str_replace('+', '\+', $token);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = implode('/', $parts);
|
||||||
|
$regex = str_replace('$', '\$', $regex);
|
||||||
|
$regex = ';^'.$regex.'$;';
|
||||||
|
|
||||||
|
return preg_match($regex, $topic) === 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
instafeed/vendor/clue/http-proxy-react/.gitignore
vendored
Executable file
2
instafeed/vendor/clue/http-proxy-react/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
/vendor/
|
||||||
|
/composer.lock
|
||||||
27
instafeed/vendor/clue/http-proxy-react/.travis.yml
vendored
Executable file
27
instafeed/vendor/clue/http-proxy-react/.travis.yml
vendored
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
# - 5.3 # requires old distro, see below
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7
|
||||||
|
- hhvm # ignore errors, see below
|
||||||
|
|
||||||
|
# lock distro so new future defaults will not break the build
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
dist: precise
|
||||||
|
allow_failures:
|
||||||
|
- php: hhvm
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
install:
|
||||||
|
- composer install --no-interaction
|
||||||
|
|
||||||
|
script:
|
||||||
|
- vendor/bin/phpunit --coverage-text
|
||||||
103
instafeed/vendor/clue/http-proxy-react/CHANGELOG.md
vendored
Executable file
103
instafeed/vendor/clue/http-proxy-react/CHANGELOG.md
vendored
Executable file
@@ -0,0 +1,103 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 1.3.0 (2018-02-13)
|
||||||
|
|
||||||
|
* Feature: Support communication over Unix domain sockets (UDS)
|
||||||
|
(#20 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// new: now supports communication over Unix domain sockets (UDS)
|
||||||
|
$proxy = new ProxyConnector('http+unix:///tmp/proxy.sock', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Reduce memory consumption by avoiding circular reference from stream reader
|
||||||
|
(#18 by @valga)
|
||||||
|
|
||||||
|
* Improve documentation
|
||||||
|
(#19 by @clue)
|
||||||
|
|
||||||
|
## 1.2.0 (2017-08-30)
|
||||||
|
|
||||||
|
* Feature: Use socket error codes for connection rejections
|
||||||
|
(#17 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$promise = $proxy->connect('imap.example.com:143');
|
||||||
|
$promise->then(null, function (Exeption $e) {
|
||||||
|
if ($e->getCode() === SOCKET_EACCES) {
|
||||||
|
echo 'Failed to authenticate with proxy!';
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
* Improve test suite by locking Travis distro so new defaults will not break the build and
|
||||||
|
optionally exclude tests that rely on working internet connection
|
||||||
|
(#15 and #16 by @clue)
|
||||||
|
|
||||||
|
## 1.1.0 (2017-06-11)
|
||||||
|
|
||||||
|
* Feature: Support proxy authentication if proxy URL contains username/password
|
||||||
|
(#14 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// new: username/password will now be passed to HTTP proxy server
|
||||||
|
$proxy = new ProxyConnector('user:pass@127.0.0.1:8080', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.0.0 (2017-06-10)
|
||||||
|
|
||||||
|
* First stable release, now following SemVer
|
||||||
|
|
||||||
|
> Contains no other changes, so it's actually fully compatible with the v0.3.2 release.
|
||||||
|
|
||||||
|
## 0.3.2 (2017-06-10)
|
||||||
|
|
||||||
|
* Fix: Fix rejecting invalid URIs and unexpected URI schemes
|
||||||
|
(#13 by @clue)
|
||||||
|
|
||||||
|
* Fix HHVM build for now again and ignore future HHVM build errors
|
||||||
|
(#12 by @clue)
|
||||||
|
|
||||||
|
* Documentation for Connector concepts (TCP/TLS, timeouts, DNS resolution)
|
||||||
|
(#11 by @clue)
|
||||||
|
|
||||||
|
## 0.3.1 (2017-05-10)
|
||||||
|
|
||||||
|
* Feature: Forward compatibility with upcoming Socket v1.0 and v0.8
|
||||||
|
(#10 by @clue)
|
||||||
|
|
||||||
|
## 0.3.0 (2017-04-10)
|
||||||
|
|
||||||
|
* Feature / BC break: Replace deprecated SocketClient with new Socket component
|
||||||
|
(#9 by @clue)
|
||||||
|
|
||||||
|
This implies that the `ProxyConnector` from this package now implements the
|
||||||
|
`React\Socket\ConnectorInterface` instead of the legacy
|
||||||
|
`React\SocketClient\ConnectorInterface`.
|
||||||
|
|
||||||
|
## 0.2.0 (2017-04-10)
|
||||||
|
|
||||||
|
* Feature / BC break: Update SocketClient to v0.7 or v0.6 and
|
||||||
|
use `connect($uri)` instead of `create($host, $port)`
|
||||||
|
(#8 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old
|
||||||
|
$connector->create($host, $port)->then(function (Stream $conn) {
|
||||||
|
$conn->write("…");
|
||||||
|
});
|
||||||
|
|
||||||
|
// new
|
||||||
|
$connector->connect($uri)->then(function (ConnectionInterface $conn) {
|
||||||
|
$conn->write("…");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
* Improve test suite by adding PHPUnit to require-dev
|
||||||
|
(#7 by @clue)
|
||||||
|
|
||||||
|
|
||||||
|
## 0.1.0 (2016-11-01)
|
||||||
|
|
||||||
|
* First tagged release
|
||||||
21
instafeed/vendor/clue/http-proxy-react/LICENSE
vendored
Executable file
21
instafeed/vendor/clue/http-proxy-react/LICENSE
vendored
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Christian Lück
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
422
instafeed/vendor/clue/http-proxy-react/README.md
vendored
Executable file
422
instafeed/vendor/clue/http-proxy-react/README.md
vendored
Executable file
@@ -0,0 +1,422 @@
|
|||||||
|
# clue/http-proxy-react [](https://travis-ci.org/clue/php-http-proxy-react)
|
||||||
|
|
||||||
|
Async HTTP proxy connector, use any TCP/IP-based protocol through an HTTP
|
||||||
|
CONNECT proxy server, built on top of [ReactPHP](https://reactphp.org).
|
||||||
|
|
||||||
|
HTTP CONNECT proxy servers (also commonly known as "HTTPS proxy" or "SSL proxy")
|
||||||
|
are commonly used to tunnel HTTPS traffic through an intermediary ("proxy"), to
|
||||||
|
conceal the origin address (anonymity) or to circumvent address blocking
|
||||||
|
(geoblocking). While many (public) HTTP CONNECT proxy servers often limit this
|
||||||
|
to HTTPS port `443` only, this can technically be used to tunnel any
|
||||||
|
TCP/IP-based protocol (HTTP, SMTP, IMAP etc.).
|
||||||
|
This library provides a simple API to create these tunneled connection for you.
|
||||||
|
Because it implements ReactPHP's standard
|
||||||
|
[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface),
|
||||||
|
it can simply be used in place of a normal connector.
|
||||||
|
This makes it fairly simple to add HTTP CONNECT proxy support to pretty much any
|
||||||
|
existing higher-level protocol implementation.
|
||||||
|
|
||||||
|
* **Async execution of connections** -
|
||||||
|
Send any number of HTTP CONNECT requests in parallel and process their
|
||||||
|
responses as soon as results come in.
|
||||||
|
The Promise-based design provides a *sane* interface to working with out of
|
||||||
|
bound responses and possible connection errors.
|
||||||
|
* **Standard interfaces** -
|
||||||
|
Allows easy integration with existing higher-level components by implementing
|
||||||
|
ReactPHP's standard
|
||||||
|
[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface).
|
||||||
|
* **Lightweight, SOLID design** -
|
||||||
|
Provides a thin abstraction that is [*just good enough*](http://en.wikipedia.org/wiki/Principle_of_good_enough)
|
||||||
|
and does not get in your way.
|
||||||
|
Builds on top of well-tested components and well-established concepts instead of reinventing the wheel.
|
||||||
|
* **Good test coverage** -
|
||||||
|
Comes with an automated tests suite and is regularly tested against actual proxy servers in the wild
|
||||||
|
|
||||||
|
**Table of contents**
|
||||||
|
|
||||||
|
* [Quickstart example](#quickstart-example)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [ProxyConnector](#proxyconnector)
|
||||||
|
* [Plain TCP connections](#plain-tcp-connections)
|
||||||
|
* [Secure TLS connections](#secure-tls-connections)
|
||||||
|
* [Connection timeout](#connection-timeout)
|
||||||
|
* [DNS resolution](#dns-resolution)
|
||||||
|
* [Authentication](#authentication)
|
||||||
|
* [Advanced secure proxy connections](#advanced-secure-proxy-connections)
|
||||||
|
* [Advanced Unix domain sockets](#advanced-unix-domain-sockets)
|
||||||
|
* [Install](#install)
|
||||||
|
* [Tests](#tests)
|
||||||
|
* [License](#license)
|
||||||
|
* [More](#more)
|
||||||
|
|
||||||
|
### Quickstart example
|
||||||
|
|
||||||
|
The following example code demonstrates how this library can be used to send a
|
||||||
|
secure HTTPS request to google.com through a local HTTP proxy server:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('127.0.0.1:8080', new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tls://google.com:443')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
|
||||||
|
$stream->on('data', function ($chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
|
```
|
||||||
|
|
||||||
|
See also the [examples](examples).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### ProxyConnector
|
||||||
|
|
||||||
|
The `ProxyConnector` is responsible for creating plain TCP/IP connections to
|
||||||
|
any destination by using an intermediary HTTP CONNECT proxy.
|
||||||
|
|
||||||
|
```
|
||||||
|
[you] -> [proxy] -> [destination]
|
||||||
|
```
|
||||||
|
|
||||||
|
Its constructor simply accepts an HTTP proxy URL and a connector used to connect
|
||||||
|
to the proxy server address:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$connector = new Connector($loop);
|
||||||
|
$proxy = new ProxyConnector('http://127.0.0.1:8080', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
The proxy URL may or may not contain a scheme and port definition. The default
|
||||||
|
port will be `80` for HTTP (or `443` for HTTPS), but many common HTTP proxy
|
||||||
|
servers use custom ports (often the alternative HTTP port `8080`).
|
||||||
|
In its most simple form, the given connector will be a
|
||||||
|
[`\React\Socket\Connector`](https://github.com/reactphp/socket#connector) if you
|
||||||
|
want to connect to a given IP address as above.
|
||||||
|
|
||||||
|
This is the main class in this package.
|
||||||
|
Because it implements ReactPHP's standard
|
||||||
|
[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface),
|
||||||
|
it can simply be used in place of a normal connector.
|
||||||
|
Accordingly, it provides only a single public method, the
|
||||||
|
[`connect()`](https://github.com/reactphp/socket#connect) method.
|
||||||
|
The `connect(string $uri): PromiseInterface<ConnectionInterface, Exception>`
|
||||||
|
method can be used to establish a streaming connection.
|
||||||
|
It returns a [Promise](https://github.com/reactphp/promise) which either
|
||||||
|
fulfills with a [ConnectionInterface](https://github.com/reactphp/socket#connectioninterface)
|
||||||
|
on success or rejects with an `Exception` on error.
|
||||||
|
|
||||||
|
This makes it fairly simple to add HTTP CONNECT proxy support to pretty much any
|
||||||
|
higher-level component:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- $client = new SomeClient($connector);
|
||||||
|
+ $proxy = new ProxyConnector('http://127.0.0.1:8080', $connector);
|
||||||
|
+ $client = new SomeClient($proxy);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Plain TCP connections
|
||||||
|
|
||||||
|
HTTP CONNECT proxies are most frequently used to issue HTTPS requests to your destination.
|
||||||
|
However, this is actually performed on a higher protocol layer and this
|
||||||
|
connector is actually inherently a general-purpose plain TCP/IP connector.
|
||||||
|
As documented above, you can simply invoke its `connect()` method to establish
|
||||||
|
a streaming plain TCP/IP connection and use any higher level protocol like so:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$proxy = new ProxyConnector('http://127.0.0.1:8080', $connector);
|
||||||
|
|
||||||
|
$proxy->connect('tcp://smtp.googlemail.com:587')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("EHLO local\r\n");
|
||||||
|
$stream->on('data', function ($chunk) use ($stream) {
|
||||||
|
echo $chunk;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You can either use the `ProxyConnector` directly or you may want to wrap this connector
|
||||||
|
in ReactPHP's [`Connector`](https://github.com/reactphp/socket#connector):
|
||||||
|
|
||||||
|
```php
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tcp://smtp.googlemail.com:587')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("EHLO local\r\n");
|
||||||
|
$stream->on('data', function ($chunk) use ($stream) {
|
||||||
|
echo $chunk;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that HTTP CONNECT proxies often restrict which ports one may connect to.
|
||||||
|
Many (public) proxy servers do in fact limit this to HTTPS (443) only.
|
||||||
|
|
||||||
|
#### Secure TLS connections
|
||||||
|
|
||||||
|
This class can also be used if you want to establish a secure TLS connection
|
||||||
|
(formerly known as SSL) between you and your destination, such as when using
|
||||||
|
secure HTTPS to your destination site. You can simply wrap this connector in
|
||||||
|
ReactPHP's [`Connector`](https://github.com/reactphp/socket#connector) or the
|
||||||
|
low-level [`SecureConnector`](https://github.com/reactphp/socket#secureconnector):
|
||||||
|
|
||||||
|
```php
|
||||||
|
$proxy = new ProxyConnector('http://127.0.0.1:8080', $connector);
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tls://smtp.googlemail.com:465')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("EHLO local\r\n");
|
||||||
|
$stream->on('data', function ($chunk) use ($stream) {
|
||||||
|
echo $chunk;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note how secure TLS connections are in fact entirely handled outside of
|
||||||
|
this HTTP CONNECT client implementation.
|
||||||
|
|
||||||
|
#### Connection timeout
|
||||||
|
|
||||||
|
By default, the `ProxyConnector` does not implement any timeouts for establishing remote
|
||||||
|
connections.
|
||||||
|
Your underlying operating system may impose limits on pending and/or idle TCP/IP
|
||||||
|
connections, anywhere in a range of a few minutes to several hours.
|
||||||
|
|
||||||
|
Many use cases require more control over the timeout and likely values much
|
||||||
|
smaller, usually in the range of a few seconds only.
|
||||||
|
|
||||||
|
You can use ReactPHP's [`Connector`](https://github.com/reactphp/socket#connector)
|
||||||
|
or the low-level
|
||||||
|
[`TimeoutConnector`](https://github.com/reactphp/socket#timeoutconnector)
|
||||||
|
to decorate any given `ConnectorInterface` instance.
|
||||||
|
It provides the same `connect()` method, but will automatically reject the
|
||||||
|
underlying connection attempt if it takes too long:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'dns' => false,
|
||||||
|
'timeout' => 3.0
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tcp://google.com:80')->then(function ($stream) {
|
||||||
|
// connection succeeded within 3.0 seconds
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
See also any of the [examples](examples).
|
||||||
|
|
||||||
|
> Note how connection timeout is in fact entirely handled outside of this
|
||||||
|
HTTP CONNECT client implementation.
|
||||||
|
|
||||||
|
#### DNS resolution
|
||||||
|
|
||||||
|
By default, the `ProxyConnector` does not perform any DNS resolution at all and simply
|
||||||
|
forwards any hostname you're trying to connect to the remote proxy server.
|
||||||
|
The remote proxy server is thus responsible for looking up any hostnames via DNS
|
||||||
|
(this default mode is thus called *remote DNS resolution*).
|
||||||
|
|
||||||
|
As an alternative, you can also send the destination IP to the remote proxy
|
||||||
|
server.
|
||||||
|
In this mode you either have to stick to using IPs only (which is ofen unfeasable)
|
||||||
|
or perform any DNS lookups locally and only transmit the resolved destination IPs
|
||||||
|
(this mode is thus called *local DNS resolution*).
|
||||||
|
|
||||||
|
The default *remote DNS resolution* is useful if your local `ProxyConnector` either can
|
||||||
|
not resolve target hostnames because it has no direct access to the internet or
|
||||||
|
if it should not resolve target hostnames because its outgoing DNS traffic might
|
||||||
|
be intercepted.
|
||||||
|
|
||||||
|
As noted above, the `ProxyConnector` defaults to using remote DNS resolution.
|
||||||
|
However, wrapping the `ProxyConnector` in ReactPHP's
|
||||||
|
[`Connector`](https://github.com/reactphp/socket#connector) actually
|
||||||
|
performs local DNS resolution unless explicitly defined otherwise.
|
||||||
|
Given that remote DNS resolution is assumed to be the preferred mode, all
|
||||||
|
other examples explicitly disable DNS resoltion like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to explicitly use *local DNS resolution*, you can use the following code:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// set up Connector which uses Google's public DNS (8.8.8.8)
|
||||||
|
$connector = Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'dns' => '8.8.8.8'
|
||||||
|
));
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note how local DNS resolution is in fact entirely handled outside of this
|
||||||
|
HTTP CONNECT client implementation.
|
||||||
|
|
||||||
|
#### Authentication
|
||||||
|
|
||||||
|
If your HTTP proxy server requires authentication, you may pass the username and
|
||||||
|
password as part of the HTTP proxy URL like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$proxy = new ProxyConnector('http://user:pass@127.0.0.1:8080', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that both the username and password must be percent-encoded if they contain
|
||||||
|
special characters:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$user = 'he:llo';
|
||||||
|
$pass = 'p@ss';
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector(
|
||||||
|
rawurlencode($user) . ':' . rawurlencode($pass) . '@127.0.0.1:8080',
|
||||||
|
$connector
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
> The authentication details will be used for basic authentication and will be
|
||||||
|
transferred in the `Proxy-Authorization` HTTP request header for each
|
||||||
|
connection attempt.
|
||||||
|
If the authentication details are missing or not accepted by the remote HTTP
|
||||||
|
proxy server, it is expected to reject each connection attempt with a
|
||||||
|
`407` (Proxy Authentication Required) response status code and an exception
|
||||||
|
error code of `SOCKET_EACCES` (13).
|
||||||
|
|
||||||
|
#### Advanced secure proxy connections
|
||||||
|
|
||||||
|
Note that communication between the client and the proxy is usually via an
|
||||||
|
unencrypted, plain TCP/IP HTTP connection. Note that this is the most common
|
||||||
|
setup, because you can still establish a TLS connection between you and the
|
||||||
|
destination host as above.
|
||||||
|
|
||||||
|
If you want to connect to a (rather rare) HTTPS proxy, you may want use the
|
||||||
|
`https://` scheme (HTTPS default port 443) and use ReactPHP's
|
||||||
|
[`Connector`](https://github.com/reactphp/socket#connector) or the low-level
|
||||||
|
[`SecureConnector`](https://github.com/reactphp/socket#secureconnector)
|
||||||
|
instance to create a secure connection to the proxy:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$connector = new Connector($loop);
|
||||||
|
$proxy = new ProxyConnector('https://127.0.0.1:443', $connector);
|
||||||
|
|
||||||
|
$proxy->connect('tcp://smtp.googlemail.com:587');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Advanced Unix domain sockets
|
||||||
|
|
||||||
|
HTTP CONNECT proxy servers support forwarding TCP/IP based connections and
|
||||||
|
higher level protocols.
|
||||||
|
In some advanced cases, it may be useful to let your HTTP CONNECT proxy server
|
||||||
|
listen on a Unix domain socket (UDS) path instead of a IP:port combination.
|
||||||
|
For example, this allows you to rely on file system permissions instead of
|
||||||
|
having to rely on explicit [authentication](#authentication).
|
||||||
|
|
||||||
|
You can simply use the `http+unix://` URI scheme like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$proxy = new ProxyConnector('http+unix:///tmp/proxy.sock', $connector);
|
||||||
|
|
||||||
|
$proxy->connect('tcp://google.com:80')->then(function (ConnectionInterface $stream) {
|
||||||
|
// connected…
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, you can also combine this with [authentication](#authentication)
|
||||||
|
like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$proxy = new ProxyConnector('http+unix://user:pass@/tmp/proxy.sock', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note that Unix domain sockets (UDS) are considered advanced usage and PHP only
|
||||||
|
has limited support for this.
|
||||||
|
In particular, enabling [secure TLS](#secure-tls-connections) may not be
|
||||||
|
supported.
|
||||||
|
|
||||||
|
> Note that the HTTP CONNECT protocol does not support the notion of UDS paths.
|
||||||
|
The above works reasonably well because UDS is only used for the connection between
|
||||||
|
client and proxy server and the path will not actually passed over the protocol.
|
||||||
|
This implies that this does not support connecting to UDS destination paths.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
The recommended way to install this library is [through Composer](https://getcomposer.org).
|
||||||
|
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
|
||||||
|
|
||||||
|
This project follows [SemVer](http://semver.org/).
|
||||||
|
This will install the latest supported version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ composer require clue/http-proxy-react:^1.3
|
||||||
|
```
|
||||||
|
|
||||||
|
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
|
||||||
|
|
||||||
|
This project aims to run on any platform and thus does not require any PHP
|
||||||
|
extensions and supports running on legacy PHP 5.3 through current PHP 7+ and
|
||||||
|
HHVM.
|
||||||
|
It's *highly recommended to use PHP 7+* for this project.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
To run the test suite, you first need to clone this repo and then install all
|
||||||
|
dependencies [through Composer](https://getcomposer.org):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the test suite, go to the project root and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ php vendor/bin/phpunit
|
||||||
|
```
|
||||||
|
|
||||||
|
The test suite contains tests that rely on a working internet connection,
|
||||||
|
alternatively you can also run it like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ php vendor/bin/phpunit --exclude-group internet
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
* If you want to learn more about how the
|
||||||
|
[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
|
||||||
|
and its usual implementations look like, refer to the documentation of the underlying
|
||||||
|
[react/socket](https://github.com/reactphp/socket) component.
|
||||||
|
* If you want to learn more about processing streams of data, refer to the
|
||||||
|
documentation of the underlying
|
||||||
|
[react/stream](https://github.com/reactphp/stream) component.
|
||||||
|
* As an alternative to an HTTP CONNECT proxy, you may also want to look into
|
||||||
|
using a SOCKS (SOCKS4/SOCKS5) proxy instead.
|
||||||
|
You may want to use [clue/socks-react](https://github.com/clue/php-socks-react)
|
||||||
|
which also provides an implementation of the same
|
||||||
|
[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
|
||||||
|
so that supporting either proxy protocol should be fairly trivial.
|
||||||
|
* If you're dealing with public proxies, you'll likely have to work with mixed
|
||||||
|
quality and unreliable proxies. You may want to look into using
|
||||||
|
[clue/connection-manager-extra](https://github.com/clue/php-connection-manager-extra)
|
||||||
|
which allows retrying unreliable ones, implying connection timeouts,
|
||||||
|
concurrently working with multiple connectors and more.
|
||||||
|
* If you're looking for an end-user HTTP CONNECT proxy server daemon, you may
|
||||||
|
want to use [LeProxy](https://leproxy.org/).
|
||||||
30
instafeed/vendor/clue/http-proxy-react/composer.json
vendored
Executable file
30
instafeed/vendor/clue/http-proxy-react/composer.json
vendored
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "clue/http-proxy-react",
|
||||||
|
"description": "Async HTTP proxy connector, use any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP",
|
||||||
|
"keywords": ["HTTP", "CONNECT", "proxy", "ReactPHP", "async"],
|
||||||
|
"homepage": "https://github.com/clue/php-http-proxy-react",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Christian Lück",
|
||||||
|
"email": "christian@lueck.tv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": { "Clue\\React\\HttpProxy\\": "src/" }
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": { "Tests\\Clue\\React\\HttpProxy\\": "tests/" }
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3",
|
||||||
|
"react/promise": " ^2.1 || ^1.2.1",
|
||||||
|
"react/socket": "^1.0 || ^0.8.4",
|
||||||
|
"ringcentral/psr7": "^1.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^5.0 || ^4.8",
|
||||||
|
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
|
||||||
|
"clue/block-react": "^1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
instafeed/vendor/clue/http-proxy-react/examples/01-proxy-https.php
vendored
Executable file
30
instafeed/vendor/clue/http-proxy-react/examples/01-proxy-https.php
vendored
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// A simple example which requests https://google.com/ through an HTTP CONNECT proxy.
|
||||||
|
// The proxy can be given as first argument and defaults to localhost:8080 otherwise.
|
||||||
|
|
||||||
|
use Clue\React\HttpProxy\ProxyConnector;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$url = isset($argv[1]) ? $argv[1] : '127.0.0.1:8080';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector($url, new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tls://google.com:443')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
|
||||||
|
$stream->on('data', function ($chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
37
instafeed/vendor/clue/http-proxy-react/examples/02-optional-proxy-https.php
vendored
Executable file
37
instafeed/vendor/clue/http-proxy-react/examples/02-optional-proxy-https.php
vendored
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// A simple example which requests https://google.com/ either directly or through
|
||||||
|
// an HTTP CONNECT proxy.
|
||||||
|
// The Proxy can be given as first argument or does not use a proxy otherwise.
|
||||||
|
// This example highlights how changing from direct connection to using a proxy
|
||||||
|
// actually adds very little complexity and does not mess with your actual
|
||||||
|
// network protocol otherwise.
|
||||||
|
|
||||||
|
use Clue\React\HttpProxy\ProxyConnector;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$connector = new Connector($loop);
|
||||||
|
|
||||||
|
// first argument given? use this as the proxy URL
|
||||||
|
if (isset($argv[1])) {
|
||||||
|
$proxy = new ProxyConnector($argv[1], $connector);
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$connector->connect('tls://google.com:443')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
|
||||||
|
$stream->on('data', function ($chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
32
instafeed/vendor/clue/http-proxy-react/examples/11-proxy-smtp.php
vendored
Executable file
32
instafeed/vendor/clue/http-proxy-react/examples/11-proxy-smtp.php
vendored
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// A simple example which uses a plain SMTP connection to Googlemail through a HTTP CONNECT proxy.
|
||||||
|
// Proxy can be given as first argument and defaults to localhost:8080 otherwise.
|
||||||
|
// Please note that MANY public proxies do not allow SMTP connections, YMMV.
|
||||||
|
|
||||||
|
use Clue\React\HttpProxy\ProxyConnector;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$url = isset($argv[1]) ? $argv[1] : '127.0.0.1:8080';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector($url, new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tcp://smtp.googlemail.com:587')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("EHLO local\r\n");
|
||||||
|
$stream->on('data', function ($chunk) use ($stream) {
|
||||||
|
echo $chunk;
|
||||||
|
$stream->write("QUIT\r\n");
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
35
instafeed/vendor/clue/http-proxy-react/examples/12-proxy-smtps.php
vendored
Executable file
35
instafeed/vendor/clue/http-proxy-react/examples/12-proxy-smtps.php
vendored
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// A simple example which uses a secure SMTP connection to Googlemail through a HTTP CONNECT proxy.
|
||||||
|
// Proxy can be given as first argument and defaults to localhost:8080 otherwise.
|
||||||
|
// This example highlights how changing from plain connections (see previous
|
||||||
|
// example) to using a secure connection actually adds very little complexity
|
||||||
|
// and does not mess with your actual network protocol otherwise.
|
||||||
|
// Please note that MANY public proxies do not allow SMTP connections, YMMV.
|
||||||
|
|
||||||
|
use Clue\React\HttpProxy\ProxyConnector;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$url = isset($argv[1]) ? $argv[1] : '127.0.0.1:8080';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector($url, new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $proxy,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
$connector->connect('tls://smtp.googlemail.com:465')->then(function (ConnectionInterface $stream) {
|
||||||
|
$stream->write("EHLO local\r\n");
|
||||||
|
$stream->on('data', function ($chunk) use ($stream) {
|
||||||
|
echo $chunk;
|
||||||
|
$stream->write("QUIT\r\n");
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
14
instafeed/vendor/clue/http-proxy-react/phpunit.xml.dist
vendored
Executable file
14
instafeed/vendor/clue/http-proxy-react/phpunit.xml.dist
vendored
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<phpunit bootstrap="vendor/autoload.php" colors="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite>
|
||||||
|
<directory>./tests/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory>./src/</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
||||||
213
instafeed/vendor/clue/http-proxy-react/src/ProxyConnector.php
vendored
Executable file
213
instafeed/vendor/clue/http-proxy-react/src/ProxyConnector.php
vendored
Executable file
@@ -0,0 +1,213 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Clue\React\HttpProxy;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use RuntimeException;
|
||||||
|
use RingCentral\Psr7;
|
||||||
|
use React\Promise;
|
||||||
|
use React\Promise\Deferred;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
use React\Socket\ConnectorInterface;
|
||||||
|
use React\Socket\FixedUriConnector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple Connector that uses an HTTP CONNECT proxy to create plain TCP/IP connections to any destination
|
||||||
|
*
|
||||||
|
* [you] -> [proxy] -> [destination]
|
||||||
|
*
|
||||||
|
* This is most frequently used to issue HTTPS requests to your destination.
|
||||||
|
* However, this is actually performed on a higher protocol layer and this
|
||||||
|
* connector is actually inherently a general-purpose plain TCP/IP connector.
|
||||||
|
*
|
||||||
|
* Note that HTTP CONNECT proxies often restrict which ports one may connect to.
|
||||||
|
* Many (public) proxy servers do in fact limit this to HTTPS (443) only.
|
||||||
|
*
|
||||||
|
* If you want to establish a TLS connection (such as HTTPS) between you and
|
||||||
|
* your destination, you may want to wrap this connector in a SecureConnector
|
||||||
|
* instance.
|
||||||
|
*
|
||||||
|
* Note that communication between the client and the proxy is usually via an
|
||||||
|
* unencrypted, plain TCP/IP HTTP connection. Note that this is the most common
|
||||||
|
* setup, because you can still establish a TLS connection between you and the
|
||||||
|
* destination host as above.
|
||||||
|
*
|
||||||
|
* If you want to connect to a (rather rare) HTTPS proxy, you may want use its
|
||||||
|
* HTTPS port (443) and use a SecureConnector instance to create a secure
|
||||||
|
* connection to the proxy.
|
||||||
|
*
|
||||||
|
* @link https://tools.ietf.org/html/rfc7231#section-4.3.6
|
||||||
|
*/
|
||||||
|
class ProxyConnector implements ConnectorInterface
|
||||||
|
{
|
||||||
|
private $connector;
|
||||||
|
private $proxyUri;
|
||||||
|
private $proxyAuth = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a new ProxyConnector which uses the given $proxyUrl
|
||||||
|
*
|
||||||
|
* @param string $proxyUrl The proxy URL may or may not contain a scheme and
|
||||||
|
* port definition. The default port will be `80` for HTTP (or `443` for
|
||||||
|
* HTTPS), but many common HTTP proxy servers use custom ports.
|
||||||
|
* @param ConnectorInterface $connector In its most simple form, the given
|
||||||
|
* connector will be a \React\Socket\Connector if you want to connect to
|
||||||
|
* a given IP address.
|
||||||
|
* @throws InvalidArgumentException if the proxy URL is invalid
|
||||||
|
*/
|
||||||
|
public function __construct($proxyUrl, ConnectorInterface $connector)
|
||||||
|
{
|
||||||
|
// support `http+unix://` scheme for Unix domain socket (UDS) paths
|
||||||
|
if (preg_match('/^http\+unix:\/\/(.*?@)?(.+?)$/', $proxyUrl, $match)) {
|
||||||
|
// rewrite URI to parse authentication from dummy host
|
||||||
|
$proxyUrl = 'http://' . $match[1] . 'localhost';
|
||||||
|
|
||||||
|
// connector uses Unix transport scheme and explicit path given
|
||||||
|
$connector = new FixedUriConnector(
|
||||||
|
'unix://' . $match[2],
|
||||||
|
$connector
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($proxyUrl, '://') === false) {
|
||||||
|
$proxyUrl = 'http://' . $proxyUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($proxyUrl);
|
||||||
|
if (!$parts || !isset($parts['scheme'], $parts['host']) || ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https')) {
|
||||||
|
throw new InvalidArgumentException('Invalid proxy URL "' . $proxyUrl . '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply default port and TCP/TLS transport for given scheme
|
||||||
|
if (!isset($parts['port'])) {
|
||||||
|
$parts['port'] = $parts['scheme'] === 'https' ? 443 : 80;
|
||||||
|
}
|
||||||
|
$parts['scheme'] = $parts['scheme'] === 'https' ? 'tls' : 'tcp';
|
||||||
|
|
||||||
|
$this->connector = $connector;
|
||||||
|
$this->proxyUri = $parts['scheme'] . '://' . $parts['host'] . ':' . $parts['port'];
|
||||||
|
|
||||||
|
// prepare Proxy-Authorization header if URI contains username/password
|
||||||
|
if (isset($parts['user']) || isset($parts['pass'])) {
|
||||||
|
$this->proxyAuth = 'Proxy-Authorization: Basic ' . base64_encode(
|
||||||
|
rawurldecode($parts['user'] . ':' . (isset($parts['pass']) ? $parts['pass'] : ''))
|
||||||
|
) . "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect($uri)
|
||||||
|
{
|
||||||
|
if (strpos($uri, '://') === false) {
|
||||||
|
$uri = 'tcp://' . $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($uri);
|
||||||
|
if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
|
||||||
|
return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$host = trim($parts['host'], '[]');
|
||||||
|
$port = $parts['port'];
|
||||||
|
|
||||||
|
// construct URI to HTTP CONNECT proxy server to connect to
|
||||||
|
$proxyUri = $this->proxyUri;
|
||||||
|
|
||||||
|
// append path from URI if given
|
||||||
|
if (isset($parts['path'])) {
|
||||||
|
$proxyUri .= $parts['path'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse query args
|
||||||
|
$args = array();
|
||||||
|
if (isset($parts['query'])) {
|
||||||
|
parse_str($parts['query'], $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append hostname from URI to query string unless explicitly given
|
||||||
|
if (!isset($args['hostname'])) {
|
||||||
|
$args['hostname'] = $parts['host'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// append query string
|
||||||
|
$proxyUri .= '?' . http_build_query($args, '', '&');;
|
||||||
|
|
||||||
|
// append fragment from URI if given
|
||||||
|
if (isset($parts['fragment'])) {
|
||||||
|
$proxyUri .= '#' . $parts['fragment'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$auth = $this->proxyAuth;
|
||||||
|
|
||||||
|
return $this->connector->connect($proxyUri)->then(function (ConnectionInterface $stream) use ($host, $port, $auth) {
|
||||||
|
$deferred = new Deferred(function ($_, $reject) use ($stream) {
|
||||||
|
$reject(new RuntimeException('Connection canceled while waiting for response from proxy (ECONNABORTED)', defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103));
|
||||||
|
$stream->close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// keep buffering data until headers are complete
|
||||||
|
$buffer = '';
|
||||||
|
$fn = function ($chunk) use (&$buffer, $deferred, $stream) {
|
||||||
|
$buffer .= $chunk;
|
||||||
|
|
||||||
|
$pos = strpos($buffer, "\r\n\r\n");
|
||||||
|
if ($pos !== false) {
|
||||||
|
// try to parse headers as response message
|
||||||
|
try {
|
||||||
|
$response = Psr7\parse_response(substr($buffer, 0, $pos));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$deferred->reject(new RuntimeException('Invalid response received from proxy (EBADMSG)', defined('SOCKET_EBADMSG') ? SOCKET_EBADMSG: 71, $e));
|
||||||
|
$stream->close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->getStatusCode() === 407) {
|
||||||
|
// map status code 407 (Proxy Authentication Required) to EACCES
|
||||||
|
$deferred->reject(new RuntimeException('Proxy denied connection due to invalid authentication ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (EACCES)', defined('SOCKET_EACCES') ? SOCKET_EACCES : 13));
|
||||||
|
return $stream->close();
|
||||||
|
} elseif ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
|
||||||
|
// map non-2xx status code to ECONNREFUSED
|
||||||
|
$deferred->reject(new RuntimeException('Proxy refused connection with HTTP error code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (ECONNREFUSED)', defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111));
|
||||||
|
return $stream->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// all okay, resolve with stream instance
|
||||||
|
$deferred->resolve($stream);
|
||||||
|
|
||||||
|
// emit remaining incoming as data event
|
||||||
|
$buffer = (string)substr($buffer, $pos + 4);
|
||||||
|
if ($buffer !== '') {
|
||||||
|
$stream->emit('data', array($buffer));
|
||||||
|
$buffer = '';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop buffering when 8 KiB have been read
|
||||||
|
if (isset($buffer[8192])) {
|
||||||
|
$deferred->reject(new RuntimeException('Proxy must not send more than 8 KiB of headers (EMSGSIZE)', defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 90));
|
||||||
|
$stream->close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$stream->on('data', $fn);
|
||||||
|
|
||||||
|
$stream->on('error', function (Exception $e) use ($deferred) {
|
||||||
|
$deferred->reject(new RuntimeException('Stream error while waiting for response from proxy (EIO)', defined('SOCKET_EIO') ? SOCKET_EIO : 5, $e));
|
||||||
|
});
|
||||||
|
|
||||||
|
$stream->on('close', function () use ($deferred) {
|
||||||
|
$deferred->reject(new RuntimeException('Connection to proxy lost while waiting for response (ECONNRESET)', defined('SOCKET_ECONNRESET') ? SOCKET_ECONNRESET : 104));
|
||||||
|
});
|
||||||
|
|
||||||
|
$stream->write("CONNECT " . $host . ":" . $port . " HTTP/1.1\r\nHost: " . $host . ":" . $port . "\r\n" . $auth . "\r\n");
|
||||||
|
|
||||||
|
return $deferred->promise()->then(function (ConnectionInterface $stream) use ($fn) {
|
||||||
|
// Stop buffering when connection has been established.
|
||||||
|
$stream->removeListener('data', $fn);
|
||||||
|
return new Promise\FulfilledPromise($stream);
|
||||||
|
});
|
||||||
|
}, function (Exception $e) use ($proxyUri) {
|
||||||
|
throw new RuntimeException('Unable to connect to proxy (ECONNREFUSED)', defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111, $e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
80
instafeed/vendor/clue/http-proxy-react/tests/AbstractTestCase.php
vendored
Executable file
80
instafeed/vendor/clue/http-proxy-react/tests/AbstractTestCase.php
vendored
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Clue\React\HttpProxy;
|
||||||
|
|
||||||
|
use PHPUnit_Framework_TestCase;
|
||||||
|
|
||||||
|
abstract class AbstractTestCase extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
protected function expectCallableNever()
|
||||||
|
{
|
||||||
|
$mock = $this->createCallableMock();
|
||||||
|
$mock
|
||||||
|
->expects($this->never())
|
||||||
|
->method('__invoke');
|
||||||
|
|
||||||
|
return $mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function expectCallableOnce()
|
||||||
|
{
|
||||||
|
$mock = $this->createCallableMock();
|
||||||
|
$mock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('__invoke');
|
||||||
|
|
||||||
|
return $mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function expectCallableOnceWith($value)
|
||||||
|
{
|
||||||
|
$mock = $this->createCallableMock();
|
||||||
|
$mock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('__invoke')
|
||||||
|
->with($this->equalTo($value));
|
||||||
|
|
||||||
|
return $mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function expectCallableOnceWithExceptionCode($code)
|
||||||
|
{
|
||||||
|
$mock = $this->createCallableMock();
|
||||||
|
$mock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('__invoke')
|
||||||
|
->with($this->callback(function ($e) use ($code) {
|
||||||
|
return $e->getCode() === $code;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return $mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function expectCallableOnceParameter($type)
|
||||||
|
{
|
||||||
|
$mock = $this->createCallableMock();
|
||||||
|
$mock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('__invoke')
|
||||||
|
->with($this->isInstanceOf($type));
|
||||||
|
|
||||||
|
return $mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @link https://github.com/reactphp/react/blob/master/tests/React/Tests/Socket/TestCase.php (taken from reactphp/react)
|
||||||
|
*/
|
||||||
|
protected function createCallableMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Tests\\Clue\\React\\HttpProxy\\CallableStub')->getMock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CallableStub
|
||||||
|
{
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
75
instafeed/vendor/clue/http-proxy-react/tests/FunctionalTest.php
vendored
Executable file
75
instafeed/vendor/clue/http-proxy-react/tests/FunctionalTest.php
vendored
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Clue\React\HttpProxy;
|
||||||
|
|
||||||
|
use React\EventLoop\Factory;
|
||||||
|
use Clue\React\HttpProxy\ProxyConnector;
|
||||||
|
use React\Socket\TcpConnector;
|
||||||
|
use React\Socket\DnsConnector;
|
||||||
|
use Clue\React\Block;
|
||||||
|
use React\Socket\SecureConnector;
|
||||||
|
|
||||||
|
/** @group internet */
|
||||||
|
class FunctionalTest extends AbstractTestCase
|
||||||
|
{
|
||||||
|
private $loop;
|
||||||
|
private $tcpConnector;
|
||||||
|
private $dnsConnector;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->loop = Factory::create();
|
||||||
|
|
||||||
|
$this->tcpConnector = new TcpConnector($this->loop);
|
||||||
|
|
||||||
|
$f = new \React\Dns\Resolver\Factory();
|
||||||
|
$resolver = $f->create('8.8.8.8', $this->loop);
|
||||||
|
|
||||||
|
$this->dnsConnector = new DnsConnector($this->tcpConnector, $resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNonListeningSocketRejectsConnection()
|
||||||
|
{
|
||||||
|
$proxy = new ProxyConnector('127.0.0.1:9999', $this->dnsConnector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$this->setExpectedException('RuntimeException', 'Unable to connect to proxy', SOCKET_ECONNREFUSED);
|
||||||
|
Block\await($promise, $this->loop, 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPlainGoogleDoesNotAcceptConnectMethod()
|
||||||
|
{
|
||||||
|
$proxy = new ProxyConnector('google.com', $this->dnsConnector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$this->setExpectedException('RuntimeException', '405 (Method Not Allowed)', SOCKET_ECONNREFUSED);
|
||||||
|
Block\await($promise, $this->loop, 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSecureGoogleDoesNotAcceptConnectMethod()
|
||||||
|
{
|
||||||
|
if (!function_exists('stream_socket_enable_crypto')) {
|
||||||
|
$this->markTestSkipped('TLS not supported on really old platforms (HHVM < 3.8)');
|
||||||
|
}
|
||||||
|
|
||||||
|
$secure = new SecureConnector($this->dnsConnector, $this->loop);
|
||||||
|
$proxy = new ProxyConnector('https://google.com:443', $secure);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$this->setExpectedException('RuntimeException', '405 (Method Not Allowed)', SOCKET_ECONNREFUSED);
|
||||||
|
Block\await($promise, $this->loop, 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSecureGoogleDoesNotAcceptPlainStream()
|
||||||
|
{
|
||||||
|
$proxy = new ProxyConnector('google.com:443', $this->dnsConnector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$this->setExpectedException('RuntimeException', 'Connection to proxy lost', SOCKET_ECONNRESET);
|
||||||
|
Block\await($promise, $this->loop, 3.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
333
instafeed/vendor/clue/http-proxy-react/tests/ProxyConnectorTest.php
vendored
Executable file
333
instafeed/vendor/clue/http-proxy-react/tests/ProxyConnectorTest.php
vendored
Executable file
@@ -0,0 +1,333 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Clue\React\HttpProxy;
|
||||||
|
|
||||||
|
use Clue\React\HttpProxy\ProxyConnector;
|
||||||
|
use React\Promise\Promise;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
class ProxyConnectorTest extends AbstractTestCase
|
||||||
|
{
|
||||||
|
private $connector;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testInvalidProxy()
|
||||||
|
{
|
||||||
|
new ProxyConnector('///', $this->connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testInvalidProxyScheme()
|
||||||
|
{
|
||||||
|
new ProxyConnector('ftp://example.com', $this->connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testInvalidHttpsUnixScheme()
|
||||||
|
{
|
||||||
|
new ProxyConnector('https+unix:///tmp/proxy.sock', $this->connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesConnectionToHttpPort()
|
||||||
|
{
|
||||||
|
$promise = new Promise(function () { });
|
||||||
|
$this->connector->expects($this->once())->method('connect')->with('tcp://proxy.example.com:80?hostname=google.com')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesConnectionToHttpPortAndPassesThroughUriComponents()
|
||||||
|
{
|
||||||
|
$promise = new Promise(function () { });
|
||||||
|
$this->connector->expects($this->once())->method('connect')->with('tcp://proxy.example.com:80/path?foo=bar&hostname=google.com#segment')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80/path?foo=bar#segment');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesConnectionToHttpPortAndObeysExplicitHostname()
|
||||||
|
{
|
||||||
|
$promise = new Promise(function () { });
|
||||||
|
$this->connector->expects($this->once())->method('connect')->with('tcp://proxy.example.com:80?hostname=www.google.com')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80?hostname=www.google.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesConnectionToHttpsPort()
|
||||||
|
{
|
||||||
|
$promise = new Promise(function () { });
|
||||||
|
$this->connector->expects($this->once())->method('connect')->with('tls://proxy.example.com:443?hostname=google.com')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('https://proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreatesConnectionToUnixPath()
|
||||||
|
{
|
||||||
|
$promise = new Promise(function () { });
|
||||||
|
$this->connector->expects($this->once())->method('connect')->with('unix:///tmp/proxy.sock')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('http+unix:///tmp/proxy.sock', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCancelPromiseWillCancelPendingConnection()
|
||||||
|
{
|
||||||
|
$promise = new Promise(function () { }, $this->expectCallableOnce());
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$this->assertInstanceOf('React\Promise\CancellablePromiseInterface', $promise);
|
||||||
|
|
||||||
|
$promise->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWillWriteToOpenConnection()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\n\r\n");
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWillProxyAuthorizationHeaderIfProxyUriContainsAuthentication()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nProxy-Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('user:pass@proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWillProxyAuthorizationHeaderIfProxyUriContainsOnlyUsernameWithoutPassword()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nProxy-Authorization: Basic dXNlcjo=\r\n\r\n");
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('user@proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWillProxyAuthorizationHeaderIfProxyUriContainsAuthenticationWithPercentEncoding()
|
||||||
|
{
|
||||||
|
$user = 'h@llÖ';
|
||||||
|
$pass = '%secret?';
|
||||||
|
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nProxy-Authorization: Basic " . base64_encode($user . ':' . $pass) . "\r\n\r\n");
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector(rawurlencode($user) . ':' . rawurlencode($pass) . '@proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWillProxyAuthorizationHeaderIfUnixProxyUriContainsAuthentication()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
$stream->expects($this->once())->method('write')->with("CONNECT google.com:80 HTTP/1.1\r\nHost: google.com:80\r\nProxy-Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->with('unix:///tmp/proxy.sock')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('http+unix://user:pass@/tmp/proxy.sock', $this->connector);
|
||||||
|
|
||||||
|
$proxy->connect('google.com:80');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsInvalidUri()
|
||||||
|
{
|
||||||
|
$this->connector->expects($this->never())->method('connect');
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('///');
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnce());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsUriWithNonTcpScheme()
|
||||||
|
{
|
||||||
|
$this->connector->expects($this->never())->method('connect');
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('tls://google.com:80');
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnce());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsIfConnectorRejects()
|
||||||
|
{
|
||||||
|
$promise = \React\Promise\reject(new \RuntimeException());
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnce());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsAndClosesIfStreamWritesNonHttp()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$stream->expects($this->once())->method('close');
|
||||||
|
$stream->emit('data', array("invalid\r\n\r\n"));
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_EBADMSG));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsAndClosesIfStreamWritesTooMuchData()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$stream->expects($this->once())->method('close');
|
||||||
|
$stream->emit('data', array(str_repeat('*', 100000)));
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_EMSGSIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsAndClosesIfStreamReturnsProyAuthenticationRequired()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$stream->expects($this->once())->method('close');
|
||||||
|
$stream->emit('data', array("HTTP/1.1 407 Proxy Authentication Required\r\n\r\n"));
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_EACCES));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRejectsAndClosesIfStreamReturnsNonSuccess()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$stream->expects($this->once())->method('close');
|
||||||
|
$stream->emit('data', array("HTTP/1.1 403 Not allowed\r\n\r\n"));
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_ECONNREFUSED));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResolvesIfStreamReturnsSuccess()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$promise->then($this->expectCallableOnce('React\Stream\Stream'));
|
||||||
|
$never = $this->expectCallableNever();
|
||||||
|
$promise->then(function (ConnectionInterface $stream) use ($never) {
|
||||||
|
$stream->on('data', $never);
|
||||||
|
});
|
||||||
|
|
||||||
|
$stream->emit('data', array("HTTP/1.1 200 OK\r\n\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResolvesIfStreamReturnsSuccessAndEmitsExcessiveData()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$once = $this->expectCallableOnceWith('hello!');
|
||||||
|
$promise->then(function (ConnectionInterface $stream) use ($once) {
|
||||||
|
$stream->on('data', $once);
|
||||||
|
});
|
||||||
|
|
||||||
|
$stream->emit('data', array("HTTP/1.1 200 OK\r\n\r\nhello!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCancelPromiseWillCloseOpenConnectionAndReject()
|
||||||
|
{
|
||||||
|
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
|
||||||
|
$stream->expects($this->once())->method('close');
|
||||||
|
|
||||||
|
$promise = \React\Promise\resolve($stream);
|
||||||
|
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
|
||||||
|
|
||||||
|
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
|
||||||
|
|
||||||
|
$promise = $proxy->connect('google.com:80');
|
||||||
|
|
||||||
|
$this->assertInstanceOf('React\Promise\CancellablePromiseInterface', $promise);
|
||||||
|
|
||||||
|
$promise->cancel();
|
||||||
|
|
||||||
|
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_ECONNABORTED));
|
||||||
|
}
|
||||||
|
}
|
||||||
2
instafeed/vendor/clue/socks-react/.gitignore
vendored
Executable file
2
instafeed/vendor/clue/socks-react/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
/vendor
|
||||||
|
/composer.lock
|
||||||
27
instafeed/vendor/clue/socks-react/.travis.yml
vendored
Executable file
27
instafeed/vendor/clue/socks-react/.travis.yml
vendored
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
# - 5.3 # requires old distro, see below
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7
|
||||||
|
- hhvm # ignore errors, see below
|
||||||
|
|
||||||
|
# lock distro so new future defaults will not break the build
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
dist: precise
|
||||||
|
allow_failures:
|
||||||
|
- php: hhvm
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
install:
|
||||||
|
- composer install --no-interaction
|
||||||
|
|
||||||
|
script:
|
||||||
|
- vendor/bin/phpunit --coverage-text
|
||||||
338
instafeed/vendor/clue/socks-react/CHANGELOG.md
vendored
Executable file
338
instafeed/vendor/clue/socks-react/CHANGELOG.md
vendored
Executable file
@@ -0,0 +1,338 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 0.8.7 (2017-12-17)
|
||||||
|
|
||||||
|
* Feature: Support SOCKS over TLS (`sockss://` URI scheme)
|
||||||
|
(#70 and #71 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// new: now supports SOCKS over TLS
|
||||||
|
$client = new Client('socks5s://localhost', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature: Support communication over Unix domain sockets (UDS)
|
||||||
|
(#69 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// new: now supports SOCKS over Unix domain sockets (UDS)
|
||||||
|
$client = new Client('socks5+unix:///tmp/proxy.sock', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Improve test suite by adding forward compatibility with PHPUnit 6
|
||||||
|
(#68 by @clue)
|
||||||
|
|
||||||
|
## 0.8.6 (2017-09-17)
|
||||||
|
|
||||||
|
* Feature: Forward compatibility with Evenement v3.0
|
||||||
|
(#67 by @WyriHaximus)
|
||||||
|
|
||||||
|
## 0.8.5 (2017-09-01)
|
||||||
|
|
||||||
|
* Feature: Use socket error codes for connection rejections
|
||||||
|
(#63 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$promise = $proxy->connect('imap.example.com:143');
|
||||||
|
$promise->then(null, function (Exeption $e) {
|
||||||
|
if ($e->getCode() === SOCKET_EACCES) {
|
||||||
|
echo 'Failed to authenticate with proxy!';
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature: Report matching SOCKS5 error codes for server side connection errors
|
||||||
|
(#62 by @clue)
|
||||||
|
|
||||||
|
* Fix: Fix SOCKS5 client receiving destination hostnames and
|
||||||
|
fix IPv6 addresses as hostnames for TLS certificates
|
||||||
|
(#64 and #65 by @clue)
|
||||||
|
|
||||||
|
* Improve test suite by locking Travis distro so new defaults will not break the build and
|
||||||
|
optionally exclude tests that rely on working internet connection
|
||||||
|
(#61 and #66 by @clue)
|
||||||
|
|
||||||
|
## 0.8.4 (2017-07-27)
|
||||||
|
|
||||||
|
* Feature: Server now passes client source address to Connector
|
||||||
|
(#60 by @clue)
|
||||||
|
|
||||||
|
## 0.8.3 (2017-07-18)
|
||||||
|
|
||||||
|
* Feature: Pass full remote URI as parameter to authentication callback
|
||||||
|
(#58 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// new third parameter passed to authentication callback
|
||||||
|
$server->setAuth(function ($user, $pass, $remote) {
|
||||||
|
$ip = parse_url($remote, PHP_URL_HOST);
|
||||||
|
|
||||||
|
return ($ip === '127.0.0.1');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
* Fix: Fix connecting to IPv6 address via SOCKS5 server and validate target
|
||||||
|
URI so hostname can not contain excessive URI components
|
||||||
|
(#59 by @clue)
|
||||||
|
|
||||||
|
* Improve test suite by fixing HHVM build for now again and ignore future HHVM build errors
|
||||||
|
(#57 by @clue)
|
||||||
|
|
||||||
|
## 0.8.2 (2017-05-09)
|
||||||
|
|
||||||
|
* Feature: Forward compatibility with upcoming Socket v1.0 and v0.8
|
||||||
|
(#56 by @clue)
|
||||||
|
|
||||||
|
## 0.8.1 (2017-04-21)
|
||||||
|
|
||||||
|
* Update examples to use URIs with default port 1080 and accept proxy URI arguments
|
||||||
|
(#54 by @clue)
|
||||||
|
|
||||||
|
* Remove now unneeded dependency on `react/stream`
|
||||||
|
(#55 by @clue)
|
||||||
|
|
||||||
|
## 0.8.0 (2017-04-18)
|
||||||
|
|
||||||
|
* Feature: Merge `Server` class from clue/socks-server
|
||||||
|
(#52 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$socket = new React\Socket\Server(1080, $loop);
|
||||||
|
$server = new Clue\React\Socks\Server($loop, $socket);
|
||||||
|
```
|
||||||
|
|
||||||
|
> Upgrading from [clue/socks-server](https://github.com/clue/php-socks-server)?
|
||||||
|
The classes have been moved as-is, so you can simply start using the new
|
||||||
|
class name `Clue\React\Socks\Server` with no other changes required.
|
||||||
|
|
||||||
|
## 0.7.0 (2017-04-14)
|
||||||
|
|
||||||
|
* Feature / BC break: Replace depreacted SocketClient with Socket v0.7 and
|
||||||
|
use `connect($uri)` instead of `create($host, $port)`
|
||||||
|
(#51 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old
|
||||||
|
$connector = new React\SocketClient\TcpConnector($loop);
|
||||||
|
$client = new Client(1080, $connector);
|
||||||
|
$client->create('google.com', 80)->then(function (Stream $conn) {
|
||||||
|
$conn->write("…");
|
||||||
|
});
|
||||||
|
|
||||||
|
// new
|
||||||
|
$connector = new React\Socket\TcpConnector($loop);
|
||||||
|
$client = new Client(1080, $connector);
|
||||||
|
$client->connect('google.com:80')->then(function (ConnectionInterface $conn) {
|
||||||
|
$conn->write("…");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
* Improve test suite by adding PHPUnit to require-dev
|
||||||
|
(#50 by @clue)
|
||||||
|
|
||||||
|
## 0.6.0 (2016-11-29)
|
||||||
|
|
||||||
|
* Feature / BC break: Pass connector into `Client` instead of loop, remove unneeded deps
|
||||||
|
(#49 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old (connector is create implicitly)
|
||||||
|
$client = new Client('127.0.0.1', $loop);
|
||||||
|
|
||||||
|
// old (connector can optionally be passed)
|
||||||
|
$client = new Client('127.0.0.1', $loop, $connector);
|
||||||
|
|
||||||
|
// new (connector is now mandatory)
|
||||||
|
$connector = new React\SocketClient\TcpConnector($loop);
|
||||||
|
$client = new Client('127.0.0.1', $connector);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature / BC break: `Client` now implements `ConnectorInterface`, remove `Connector` adapter
|
||||||
|
(#47 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old (explicit connector functions as an adapter)
|
||||||
|
$connector = $client->createConnector();
|
||||||
|
$promise = $connector->create('google.com', 80);
|
||||||
|
|
||||||
|
// new (client can be used as connector right away)
|
||||||
|
$promise = $client->create('google.com', 80);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature / BC break: Remove `createSecureConnector()`, use `SecureConnector` instead
|
||||||
|
(#47 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old (tight coupling and hidden dependency)
|
||||||
|
$tls = $client->createSecureConnector();
|
||||||
|
$promise = $tls->create('google.com', 443);
|
||||||
|
|
||||||
|
// new (more explicit, loose coupling)
|
||||||
|
$tls = new React\SocketClient\SecureConnector($client, $loop);
|
||||||
|
$promise = $tls->create('google.com', 443);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature / BC break: Remove `setResolveLocal()` and local DNS resolution and default to remote DNS resolution, use `DnsConnector` instead
|
||||||
|
(#44 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old (implicitly defaults to true, can be disabled)
|
||||||
|
$client->setResolveLocal(false);
|
||||||
|
$tcp = $client->createConnector();
|
||||||
|
$promise = $tcp->create('google.com', 80);
|
||||||
|
|
||||||
|
// new (always disabled, can be re-enabled like this)
|
||||||
|
$factory = new React\Dns\Resolver\Factory();
|
||||||
|
$resolver = $factory->createCached('8.8.8.8', $loop);
|
||||||
|
$tcp = new React\SocketClient\DnsConnector($client, $resolver);
|
||||||
|
$promise = $tcp->create('google.com', 80);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature / BC break: Remove `setTimeout()`, use `TimeoutConnector` instead
|
||||||
|
(#45 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old (timeout only applies to TCP/IP connection)
|
||||||
|
$client = new Client('127.0.0.1', …);
|
||||||
|
$client->setTimeout(3.0);
|
||||||
|
$tcp = $client->createConnector();
|
||||||
|
$promise = $tcp->create('google.com', 80);
|
||||||
|
|
||||||
|
// new (timeout can be added to any layer)
|
||||||
|
$client = new Client('127.0.0.1', …);
|
||||||
|
$tcp = new React\SocketClient\TimeoutConnector($client, 3.0, $loop);
|
||||||
|
$promise = $tcp->create('google.com', 80);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature / BC break: Remove `setProtocolVersion()` and `setAuth()` mutators, only support SOCKS URI for protocol version and authentication (immutable API)
|
||||||
|
(#46 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old (state can be mutated after instantiation)
|
||||||
|
$client = new Client('127.0.0.1', …);
|
||||||
|
$client->setProtocolVersion('5');
|
||||||
|
$client->setAuth('user', 'pass');
|
||||||
|
|
||||||
|
// new (immutable after construction, already supported as of v0.5.2 - now mandatory)
|
||||||
|
$client = new Client('socks5://user:pass@127.0.0.1', …);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 0.5.2 (2016-11-25)
|
||||||
|
|
||||||
|
* Feature: Apply protocol version and username/password auth from SOCKS URI
|
||||||
|
(#43 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
// explicitly use SOCKS5
|
||||||
|
$client = new Client('socks5://127.0.0.1', $loop);
|
||||||
|
|
||||||
|
// use authentication (automatically SOCKS5)
|
||||||
|
$client = new Client('user:pass@127.0.0.1', $loop);
|
||||||
|
```
|
||||||
|
|
||||||
|
* More explicit client examples, including proxy chaining
|
||||||
|
(#42 by @clue)
|
||||||
|
|
||||||
|
## 0.5.1 (2016-11-21)
|
||||||
|
|
||||||
|
* Feature: Support Promise cancellation
|
||||||
|
(#39 by @clue)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$promise = $connector->create($host, $port);
|
||||||
|
|
||||||
|
$promise->cancel();
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature: Timeout now cancels pending connection attempt
|
||||||
|
(#39, #22 by @clue)
|
||||||
|
|
||||||
|
## 0.5.0 (2016-11-07)
|
||||||
|
|
||||||
|
* Remove / BC break: Split off Server to clue/socks-server
|
||||||
|
(#35 by @clue)
|
||||||
|
|
||||||
|
> Upgrading? Check [clue/socks-server](https://github.com/clue/php-socks-server) for details.
|
||||||
|
|
||||||
|
* Improve documentation and project structure
|
||||||
|
|
||||||
|
## 0.4.0 (2016-03-19)
|
||||||
|
|
||||||
|
* Feature: Support proper SSL/TLS connections with additional SSL context options
|
||||||
|
(#31, #33 by @clue)
|
||||||
|
|
||||||
|
* Documentation for advanced Connector setups (bindto, multihop)
|
||||||
|
(#32 by @clue)
|
||||||
|
|
||||||
|
## 0.3.0 (2015-06-20)
|
||||||
|
|
||||||
|
* BC break / Feature: Client ctor now accepts a SOCKS server URI
|
||||||
|
([#24](https://github.com/clue/php-socks-react/pull/24))
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old
|
||||||
|
$client = new Client($loop, 'localhost', 9050);
|
||||||
|
|
||||||
|
// new
|
||||||
|
$client = new Client('localhost:9050', $loop);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Feature: Automatically assume default SOCKS port (1080) if not given explicitly
|
||||||
|
([#26](https://github.com/clue/php-socks-react/pull/26))
|
||||||
|
|
||||||
|
* Improve documentation and test suite
|
||||||
|
|
||||||
|
## 0.2.1 (2014-11-13)
|
||||||
|
|
||||||
|
* Support React PHP v0.4 (while preserving BC with React PHP v0.3)
|
||||||
|
([#16](https://github.com/clue/php-socks-react/pull/16))
|
||||||
|
|
||||||
|
* Improve examples and add first class support for HHVM
|
||||||
|
([#15](https://github.com/clue/php-socks-react/pull/15) and [#17](https://github.com/clue/php-socks-react/pull/17))
|
||||||
|
|
||||||
|
## 0.2.0 (2014-09-27)
|
||||||
|
|
||||||
|
* BC break / Feature: Simplify constructors by making parameters optional.
|
||||||
|
([#10](https://github.com/clue/php-socks-react/pull/10))
|
||||||
|
|
||||||
|
The `Factory` has been removed, you can now create instances of the `Client`
|
||||||
|
and `Server` yourself:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// old
|
||||||
|
$factory = new Factory($loop, $dns);
|
||||||
|
$client = $factory->createClient('localhost', 9050);
|
||||||
|
$server = $factory->createSever($socket);
|
||||||
|
|
||||||
|
// new
|
||||||
|
$client = new Client($loop, 'localhost', 9050);
|
||||||
|
$server = new Server($loop, $socket);
|
||||||
|
```
|
||||||
|
|
||||||
|
* BC break: Remove HTTP support and link to [clue/buzz-react](https://github.com/clue/php-buzz-react) instead.
|
||||||
|
([#9](https://github.com/clue/php-socks-react/pull/9))
|
||||||
|
|
||||||
|
HTTP operates on a different layer than this low-level SOCKS library.
|
||||||
|
Removing this reduces the footprint of this library.
|
||||||
|
|
||||||
|
> Upgrading? Check the [README](https://github.com/clue/php-socks-react#http-requests) for details.
|
||||||
|
|
||||||
|
* Fix: Refactored to support other, faster loops (libev/libevent)
|
||||||
|
([#12](https://github.com/clue/php-socks-react/pull/12))
|
||||||
|
|
||||||
|
* Explicitly list dependencies, clean up examples and extend test suite significantly
|
||||||
|
|
||||||
|
## 0.1.0 (2014-05-19)
|
||||||
|
|
||||||
|
* First stable release
|
||||||
|
* Async SOCKS `Client` and `Server` implementation
|
||||||
|
* Project was originally part of [clue/socks](https://github.com/clue/php-socks)
|
||||||
|
and was split off from its latest releave v0.4.0
|
||||||
|
([#1](https://github.com/clue/reactphp-socks/issues/1))
|
||||||
|
|
||||||
|
> Upgrading from clue/socks v0.4.0? Use namespace `Clue\React\Socks` instead of `Socks` and you're ready to go!
|
||||||
|
|
||||||
|
## 0.0.0 (2011-04-26)
|
||||||
|
|
||||||
|
* Initial concept, originally tracked as part of
|
||||||
|
[clue/socks](https://github.com/clue/php-socks)
|
||||||
21
instafeed/vendor/clue/socks-react/LICENSE
vendored
Executable file
21
instafeed/vendor/clue/socks-react/LICENSE
vendored
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2011 Christian Lück
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
1017
instafeed/vendor/clue/socks-react/README.md
vendored
Executable file
1017
instafeed/vendor/clue/socks-react/README.md
vendored
Executable file
File diff suppressed because it is too large
Load Diff
28
instafeed/vendor/clue/socks-react/composer.json
vendored
Executable file
28
instafeed/vendor/clue/socks-react/composer.json
vendored
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "clue/socks-react",
|
||||||
|
"description": "Async SOCKS4, SOCKS4a and SOCKS5 proxy client and server implementation, built on top of ReactPHP",
|
||||||
|
"keywords": ["socks client", "socks server", "proxy", "tcp tunnel", "socks protocol", "async", "ReactPHP"],
|
||||||
|
"homepage": "https://github.com/clue/php-socks-react",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Christian Lück",
|
||||||
|
"email": "christian@lueck.tv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {"Clue\\React\\Socks\\": "src/"}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3",
|
||||||
|
"react/socket": "^1.0 || ^0.8.6",
|
||||||
|
"react/promise": "^2.1 || ^1.2",
|
||||||
|
"evenement/evenement": "~3.0|~1.0|~2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.0 || ^5.7 || ^4.8.35",
|
||||||
|
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
|
||||||
|
"clue/connection-manager-extra": "^1.0 || ^0.7",
|
||||||
|
"clue/block-react": "^1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
instafeed/vendor/clue/socks-react/examples/01-http.php
vendored
Executable file
30
instafeed/vendor/clue/socks-react/examples/01-http.php
vendored
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Clue\React\Socks\Client;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$proxy = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$client = new Client($proxy, new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $client,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
echo 'Demo SOCKS client connecting to SOCKS server ' . $proxy . PHP_EOL;
|
||||||
|
|
||||||
|
$connector->connect('tcp://www.google.com:80')->then(function (ConnectionInterface $stream) {
|
||||||
|
echo 'connected' . PHP_EOL;
|
||||||
|
$stream->write("GET / HTTP/1.0\r\n\r\n");
|
||||||
|
$stream->on('data', function ($data) {
|
||||||
|
echo $data;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
30
instafeed/vendor/clue/socks-react/examples/02-https.php
vendored
Executable file
30
instafeed/vendor/clue/socks-react/examples/02-https.php
vendored
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Clue\React\Socks\Client;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$proxy = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
$client = new Client($proxy, new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $client,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
echo 'Demo SOCKS client connecting to SOCKS server ' . $proxy . PHP_EOL;
|
||||||
|
|
||||||
|
$connector->connect('tls://www.google.com:443')->then(function (ConnectionInterface $stream) {
|
||||||
|
echo 'connected' . PHP_EOL;
|
||||||
|
$stream->write("GET / HTTP/1.0\r\n\r\n");
|
||||||
|
$stream->on('data', function ($data) {
|
||||||
|
echo $data;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
46
instafeed/vendor/clue/socks-react/examples/03-proxy-chaining.php
vendored
Executable file
46
instafeed/vendor/clue/socks-react/examples/03-proxy-chaining.php
vendored
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Clue\React\Socks\Client;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
if (!isset($argv[1])) {
|
||||||
|
echo 'No arguments given! Run with <proxy1> [<proxyN>...]' . PHP_EOL;
|
||||||
|
echo 'You can add 1..n proxies in the path' . PHP_EOL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = array_slice($argv, 1);
|
||||||
|
|
||||||
|
// Alternatively, you can also hard-code this value like this:
|
||||||
|
//$path = array('127.0.0.1:9051', '127.0.0.1:9052', '127.0.0.1:9053');
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
// set next SOCKS server chain via p1 -> p2 -> p3 -> destination
|
||||||
|
$connector = new Connector($loop);
|
||||||
|
foreach ($path as $proxy) {
|
||||||
|
$connector = new Client($proxy, $connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// please note how the client uses p3 (not p1!), which in turn then uses the complete chain
|
||||||
|
// this creates a TCP/IP connection to p1, which then connects to p2, then to p3, which then connects to the target
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $connector,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
echo 'Demo SOCKS client connecting to SOCKS proxy server chain ' . implode(' -> ', $path) . PHP_EOL;
|
||||||
|
|
||||||
|
$connector->connect('tls://www.google.com:443')->then(function (ConnectionInterface $stream) {
|
||||||
|
echo 'connected' . PHP_EOL;
|
||||||
|
$stream->write("GET / HTTP/1.0\r\n\r\n");
|
||||||
|
$stream->on('data', function ($data) {
|
||||||
|
echo $data;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
31
instafeed/vendor/clue/socks-react/examples/04-local-dns.php
vendored
Executable file
31
instafeed/vendor/clue/socks-react/examples/04-local-dns.php
vendored
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Clue\React\Socks\Client;
|
||||||
|
use React\Socket\Connector;
|
||||||
|
use React\Socket\ConnectionInterface;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$proxy = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
// set up DNS server to use (Google's public DNS)
|
||||||
|
$client = new Client($proxy, new Connector($loop));
|
||||||
|
$connector = new Connector($loop, array(
|
||||||
|
'tcp' => $client,
|
||||||
|
'timeout' => 3.0,
|
||||||
|
'dns' => '8.8.8.8'
|
||||||
|
));
|
||||||
|
|
||||||
|
echo 'Demo SOCKS client connecting to SOCKS server ' . $proxy . PHP_EOL;
|
||||||
|
|
||||||
|
$connector->connect('tls://www.google.com:443')->then(function (ConnectionInterface $stream) {
|
||||||
|
echo 'connected' . PHP_EOL;
|
||||||
|
$stream->write("GET / HTTP/1.0\r\n\r\n");
|
||||||
|
$stream->on('data', function ($data) {
|
||||||
|
echo $data;
|
||||||
|
});
|
||||||
|
}, 'printf');
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
19
instafeed/vendor/clue/socks-react/examples/11-server.php
vendored
Executable file
19
instafeed/vendor/clue/socks-react/examples/11-server.php
vendored
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Clue\React\Socks\Server;
|
||||||
|
use React\Socket\Server as Socket;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
// listen on 127.0.0.1:1080 or first argument
|
||||||
|
$listen = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080';
|
||||||
|
$socket = new Socket($listen, $loop);
|
||||||
|
|
||||||
|
// start a new server listening for incoming connection on the given socket
|
||||||
|
$server = new Server($loop, $socket);
|
||||||
|
|
||||||
|
echo 'SOCKS server listening on ' . $socket->getAddress() . PHP_EOL;
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
24
instafeed/vendor/clue/socks-react/examples/12-server-with-password.php
vendored
Executable file
24
instafeed/vendor/clue/socks-react/examples/12-server-with-password.php
vendored
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Clue\React\Socks\Server;
|
||||||
|
use React\Socket\Server as Socket;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
$loop = React\EventLoop\Factory::create();
|
||||||
|
|
||||||
|
// listen on 127.0.0.1:1080 or first argument
|
||||||
|
$listen = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080';
|
||||||
|
$socket = new Socket($listen, $loop);
|
||||||
|
|
||||||
|
// start a new server listening for incoming connection on the given socket
|
||||||
|
// require authentication and hence make this a SOCKS5-only server
|
||||||
|
$server = new Server($loop, $socket);
|
||||||
|
$server->setAuthArray(array(
|
||||||
|
'tom' => 'god',
|
||||||
|
'user' => 'p@ssw0rd'
|
||||||
|
));
|
||||||
|
|
||||||
|
echo 'SOCKS5 server requiring authentication listening on ' . $socket->getAddress() . PHP_EOL;
|
||||||
|
|
||||||
|
$loop->run();
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user