Skip to content

Commit

Permalink
Merge pull request #29 from lnpay/async_lnurlpay
Browse files Browse the repository at this point in the history
Async lnurlpay processing
  • Loading branch information
tkthundr authored Nov 20, 2023
2 parents bf7b9da + cd60805 commit 40e2de0
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 91 deletions.
82 changes: 82 additions & 0 deletions src/jobs/LnWalletLnurlPayFormJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
namespace lnpay\jobs;

use lnpay\behaviors\UserAccessKeyBehavior;
use lnpay\components\AnalyticsComponent;
use lnpay\components\HelperComponent;
use lnpay\wallet\exceptions\UnableToPayLnurlpayException;
use lnpay\wallet\models\LnWalletLnurlpayPayForm;
use lnpay\wallet\models\LnWalletWithdrawForm;
use lnpay\wallet\models\Wallet;
use lnpay\wallet\models\WalletTransactionType;
use yii\helpers\Json;
use yii\web\BadRequestHttpException;
use Yii;

class LnWalletLnurlPayFormJob extends \yii\base\BaseObject implements \yii\queue\RetryableJobInterface
{
public $access_key;
public $wallet_id;
public $bodyParams = [];

public function execute($queue)
{
$wallet = Wallet::findOne($this->wallet_id);
$form = new LnWalletLnurlpayPayForm();
$form->load($this->bodyParams,'');
$form->probe_json = LnWalletLnurlpayPayForm::probe($form->lnurlpay_encoded??$form->ln_address);


$array = [];
$bp = \LNPay::$app->getRequest()->getBodyParams();
if ($passThru = @$bp['passThru']) {
if (is_array($passThru)) {
$array = $passThru;
} else {
try {
$array = Json::decode($passThru);
} catch (\Throwable $t) {
throw new BadRequestHttpException('passThru data must be valid json');
}
}
}
if ($form->ln_address) {
$array['target_ln_address'] = $form->ln_address;
}
if ($form->lnurlpay_encoded) {
$array['target_lnurlp_encoded'] = $form->lnurlpay_encoded;
}
$form->passThru = $array;

if ($form->validate()) {
$invoice = $form->requestRemoteInvoice();

$model = new LnWalletWithdrawForm();
$model->payment_request = $invoice;
$model->wallet_id = $wallet->id;
$model->passThru = $form->passThru;
$model->target_msat = $form->amt_msat;
$model->wtx_type_id = WalletTransactionType::LN_LNURL_PAY_OUTBOUND;

$wtx = $model->processWithdrawal(['method'=>'lnurlpay','lnurlp_comment'=>$form->comment]);
return $wtx->id;

} else {
throw new UnableToPayLnurlpayException(HelperComponent::getFirstErrorFromFailedValidation($form));
}
}

public function getTtr()
{
return 20;
}

public function canRetry($attempt, $error)
{
if (($attempt < 50) && ($error instanceof \lnpay\exceptions\WalletBusyException)) {
return true;
} else {
return false;
}
}
}
4 changes: 2 additions & 2 deletions src/views/funnel/plans.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</div>
<?php } else { ?>
<div class="d-grid text-center">
<a href="<?php if (YII_ENV_DEV) echo 'https://buy.stripe.com/test_00gbLUfkt1Ai2li144'; else echo 'https://buy.stripe.com/aEU4htcr91DO2He4gr';?>" class="btn btn-primary text-uppercase">Upgrade to Pro</a>
<a href="<?php if (YII_ENV_DEV) echo 'https://buy.stripe.com/test_00gbLUfkt1Ai2li144'; else echo 'https://buy.stripe.com/bIY5lxbn52HS2He8wF';?>" class="btn btn-primary text-uppercase">Upgrade to Pro</a>
</div>
<?php } ?>
</div>
Expand Down Expand Up @@ -74,7 +74,7 @@
</div>
<?php } else { ?>
<div class="d-grid text-center">
<a href="<?php if (YII_ENV_DEV) echo 'https://buy.stripe.com/test_00gbLUfkt1Ai2li144'; else echo 'https://buy.stripe.com/aEU4htcr91DO2He4gr';?>" class="btn btn-primary text-uppercase">Upgrade to Growth</a>
<a href="<?php if (YII_ENV_DEV) echo 'https://buy.stripe.com/test_00gbLUfkt1Ai2li144'; else echo 'https://buy.stripe.com/4gw4ht0IrfuE95CfZ6';?>" class="btn btn-primary text-uppercase">Upgrade to Growth</a>
</div>
<?php } ?>
</div>
Expand Down
110 changes: 21 additions & 89 deletions src/wallet/controllers/api/v1/LnurlpayController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use lnpay\behaviors\UserAccessKeyBehavior;
use lnpay\components\HelperComponent;
use lnpay\jobs\LnWalletLnurlPayFormJob;
use lnpay\models\CustyDomain;
use lnpay\wallet\exceptions\InvalidLnurlpayLinkException;
use lnpay\wallet\exceptions\UnableToCreateLnurlpayException;
Expand All @@ -13,6 +14,7 @@
use lnpay\wallet\models\LnWalletWithdrawForm;
use lnpay\wallet\models\WalletLnurlpay;
use lnpay\base\ApiController;
use lnpay\wallet\models\WalletTransaction;
use lnpay\wallet\models\WalletTransactionType;
use yii\helpers\Json;
use yii\helpers\VarDumper;
Expand Down Expand Up @@ -225,104 +227,34 @@ public function actionLnurlProcess($access_key,$wallet_lnurlpay_id,$amount=null,
}
}

public function actionProbe($lnurlpayEncodedOrLnAddress)
{
try {
if (stripos($lnurlpayEncodedOrLnAddress,'@')!==FALSE) {
$url = static::getUrlFromLnAddress($lnurlpayEncodedOrLnAddress);
} else if ($lnurlp = \tkijewski\lnurl\decodeUrl($lnurlpayEncodedOrLnAddress)) {
if (@$lnurlp['url']) {
$url = $lnurlp['url'];
} else {
throw new InvalidLnurlpayLinkException('invalid lnurlpay link');
}
} else {
throw new \Exception('lnurlpay_encoded or ln_address must be specified');
}

$client = new \GuzzleHttp\Client([
'curl'=> [],
'http_errors'=>true,
'headers' => ['SERVICE'=>'LNPAY-PROBE'],
'debug'=>false
]);

$r = null;
$response = $client->request('GET', $url);
$r = $response->getBody()->getContents();

} catch (\Throwable $t) {
throw new InvalidLnurlpayLinkException($t->getMessage());
}

$json = json_decode($r,TRUE);
if (@$json['metadata'])
$json['metadata'] = json_decode($json['metadata'],TRUE);

return $json;

}

public function actionPay($access_key)
{
$wallet = $this->findByKey($access_key);
$this->checkAccessKey(UserAccessKeyBehavior::PERM_WALLET_WITHDRAW);

$form = new LnWalletLnurlpayPayForm();
$form->load(\LNPay::$app->getRequest()->getBodyParams(),'');
$form->probe_json = $this->actionProbe($form->lnurlpay_encoded??$form->ln_address);


$array = [];
$bp = \LNPay::$app->getRequest()->getBodyParams();
if ($passThru = @$bp['passThru']) {
if (is_array($passThru)) {
$array = $passThru;
} else {
try {
$array = Json::decode($passThru);
} catch (\Throwable $t) {
throw new BadRequestHttpException('passThru data must be valid json');
}
}
}
if ($form->ln_address) {
$array['target_ln_address'] = $form->ln_address;
}
if ($form->lnurlpay_encoded) {
$array['target_lnurlp_encoded'] = $form->lnurlpay_encoded;
}
$form->passThru = $array;

if ($form->validate()) {
$invoice = $form->requestRemoteInvoice();

$model = new LnWalletWithdrawForm();
$model->payment_request = $invoice;
$model->wallet_id = $wallet->id;
$model->passThru = $form->passThru;
$model->target_msat = $form->amt_msat;
$model->wtx_type_id = WalletTransactionType::LN_LNURL_PAY_OUTBOUND;

return $model->processWithdrawal(['method'=>'lnurlpay','lnurlp_comment'=>$form->comment]);

$bodyParams = \LNPay::$app->getRequest()->getBodyParams();

if ($this->isAsync) {
$id = \LNPay::$app->queue->push(new LnWalletLnurlPayFormJob([
'access_key' => $access_key,
'wallet_id' => $wallet->id,
'bodyParams'=>$bodyParams
]));
return ['success'=>1,'id'=>$id];
} else {
throw new UnableToPayLnurlpayException(HelperComponent::getFirstErrorFromFailedValidation($form));
$job = new LnWalletLnurlPayFormJob([
'access_key' => $access_key,
'wallet_id' => $wallet->id,
'bodyParams'=>$bodyParams
]);
$wtx_id = $job->execute(\LNPay::$app->queue);
\LNPay::$app->response->statusCode = 201;
return WalletTransaction::findOne($wtx_id);
}


}

public static function getUrlFromLnAddress($lnAddress)
public function actionProbe($lnurlpayEncodedOrLnAddress)
{
$username = explode('@',$lnAddress)[0];
$domain = explode('@',$lnAddress)[1];
if (YII_ENV_TEST)
$url = 'http://localhost/index-test.php/.well-known/lnurlp/'.$username;
else
$url = 'https://'.$domain.'/.well-known/lnurlp/'.$username;

return $url;
return LnWalletLnurlpayPayForm::probe($lnurlpayEncodedOrLnAddress);
}


Expand Down
51 changes: 51 additions & 0 deletions src/wallet/models/LnWalletLnurlpayPayForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
use lnpay\components\HelperComponent;
use lnpay\models\BalanceWithdraw;
use lnpay\models\LnTx;
use lnpay\wallet\controllers\api\v1\LnurlpayController;
use lnpay\wallet\exceptions\InvalidLnurlpayLinkException;
use lnpay\wallet\exceptions\UnableToPayLnurlpayException;
use lnpay\wallet\models\WalletTransaction;
use yii\base\Model;
Expand Down Expand Up @@ -115,4 +117,53 @@ public function requestRemoteInvoice()

throw new UnableToPayLnurlpayException('Could not retrieve pr from '.$url);
}

public static function probe($lnurlpayEncodedOrLnAddress)
{
try {
if (stripos($lnurlpayEncodedOrLnAddress,'@')!==FALSE) {
$url = static::getUrlFromLnAddress($lnurlpayEncodedOrLnAddress);
} else if ($lnurlp = \tkijewski\lnurl\decodeUrl($lnurlpayEncodedOrLnAddress)) {
if (@$lnurlp['url']) {
$url = $lnurlp['url'];
} else {
throw new InvalidLnurlpayLinkException('invalid lnurlpay link');
}
} else {
throw new \Exception('lnurlpay_encoded or ln_address must be specified');
}

$client = new \GuzzleHttp\Client([
'curl'=> [],
'http_errors'=>true,
'headers' => ['SERVICE'=>'LNPAY-PROBE'],
'debug'=>false
]);

$r = null;
$response = $client->request('GET', $url);
$r = $response->getBody()->getContents();

} catch (\Throwable $t) {
throw new InvalidLnurlpayLinkException('Invalid Address / LNURL');
}

$json = json_decode($r,TRUE);
if (@$json['metadata'])
$json['metadata'] = json_decode($json['metadata'],TRUE);

return $json;
}

public static function getUrlFromLnAddress($lnAddress)
{
$username = explode('@',$lnAddress)[0];
$domain = explode('@',$lnAddress)[1];
if (YII_ENV_TEST)
$url = 'http://localhost/index-test.php/.well-known/lnurlp/'.$username;
else
$url = 'https://'.$domain.'/.well-known/lnurlp/'.$username;

return $url;
}
}

0 comments on commit 40e2de0

Please sign in to comment.