Bagaimana saya membuat sistem penerimaan pembayaran Minecraft menggunakan PowerShell murni


Pada artikel ini, kami akan mengacaukan donat tak bertuhan itu ke server vanilla Minecraft menggunakan Powershell. Keuntungan dari metode ini adalah bahwa minecraft hanyalah kasus khusus dari penerapan pembayaran otomatis menggunakan perintah konsol. Kami hanya mendengarkan apa yang dikirim sistem pembayaran kepada kami dan membungkusnya dalam sebuah tim. Dan yang paling penting - tidak ada plugin.
Dan kami akan menerima pembayaran melalui PayPal. Yang paling penting, untuk mulai menerima pembayaran yang Anda tidak perlu mengubah kode, PayPal akan mengirimkan kepada kami semua yang Anda butuhkan. Kami akan menggunakan tombol di situs, sehingga situs dapat melakukannya dengan HTML murni. Kami abstrak dari seluk-beluk sistem pembayaran itu sendiri dan hanya berkonsentrasi pada poin utama dalam kode.

Ngomong-ngomong, penulis akan sangat senang jika Anda melihat semua modulnya dan menemukan kesalahan anak-anak di dalamnya yang Anda tunjuk atau koreksi. Berikut ini tautan ke proyek github .

Beberapa kata tentang IPN


IPN


Kami akan menerima pembayaran melalui tombol. Tombol tidak memerlukan backend dari Anda, mereka bekerja dalam HTML murni, dan mereka juga memiliki bidangnya sendiri.

Tombol memicu IPN - Pemberitahuan Pembayaran Instan, di mana data dikirim ke WebListener kami. Kami akan mempertimbangkan struktur IPN di bawah ini.

Selain itu, siapa pun yang memiliki akun PayPal dapat membuat tombol sendiri.
IPN tidak memiliki API REST PayPal lengkap, tetapi fungsionalitas dasar dapat diimplementasikan di atasnya. Faktanya, IPN yang kami pertimbangkan bukanlah REST API dalam arti penuh hanya karena PayPal sendiri tidak mengharapkan apa pun dari kami kecuali kode 200.

Angkat WebListener


PayPal, untuk alasan keamanan, tidak mengirim permintaan melalui HTTP, jadi kami perlu mengeluarkan sertifikat untuk memulai. 

Penulis menggunakan WinAcme . Anda dapat mengeluarkan sertifikat ke domain apa pun, dan Anda harus meletakkan sertifikat di toko sertifikat lokal. Omong-omong, WinAcme terletak di root disk pada gambar.

#     
Get-ChildItem -Path Cert:\LocalMachine\My 
 
#      443 .
netsh http add sslcert ipport=0.0.0.0:443 certhash=D106F5676534794B6767D1FB75B58D5E33906710 "appid={00112233-4455-6677-8899-AABBCCDDEEFF}"

Powershell dapat menggunakan kelas dari .net, yang membuatnya hampir sama dengan .net. Pertama, menggunakan kelas HttpListener, naikkan server Web.

#   .net
$http = [System.Net.HttpListener]::new() 
 
#   
$http.Prefixes.Add("http://donate.to/")
$http.Prefixes.Add("https://donate.to/")
 
# 
$http.Start()

Untuk memverifikasi bahwa semuanya dilakukan dengan baik, jalankan netstat.



Jika skrip kami mulai mendengarkan port 443 dalam daftar, itu berarti Anda melakukan semuanya dengan benar, dan kami dapat melanjutkan untuk menerima pemrosesan permintaan. Hanya saja, jangan lupa tentang firewall.

Menerima permintaan


Dengan menggunakan Simulator IPN, kami dapat mengirimkan sendiri permintaan POST uji untuk melihat apa itu. Tetapi Anda tidak dapat memasukkan bidang Anda sendiri di dalamnya, jadi penulis merekomendasikan untuk membuat tombol dan segera membeli sesuatu dari diri Anda. IPN History akan menampilkan permintaan normal dari tombol yang akan Anda gunakan. Penulis melakukan hal itu dengan membeli satu batubara untuk satu rubel.

Kami akan menerima menggunakan loop Sementara. Saat server web sedang berjalan, kita dapat membaca aliran data yang masuk.

while ($http.IsListening) {
 
  $context = $http.GetContext()
 
  if ($context.Request.HttpMethod -eq 'POST' -and $context.Request.RawUrl -eq '/') {
 
    #  POST 
    $Reader = [System.IO.StreamReader]::new($context.Request.InputStream).ReadToEnd()
    
    #  .
    $DecodedContent = [System.Web.HttpUtility]::UrlDecode($Reader)
 
    #   .
    $Payment | Format-Table
 
    #  200 OK   .
    $context.Response.Headers.Add("Content-Type", "text/plain")
    $context.Response.StatusCode = 200
    $ResponseBuffer = [System.Text.Encoding]::UTF8.GetBytes("")
    $context.Response.ContentLength64 = $ResponseBuffer.Length
    $context.Response.OutputStream.Write($ResponseBuffer, 0, $ResponseBuffer.Length)
    $context.Response.Close()
  }
}

Jika Anda mendapatkan bihun seperti ini, maka terapkan:

$Payment = $DecodedContent -split "&" | ConvertFrom-StringData



Setelah itu, Anda akhirnya akan menerima objek normal, di mana semua Value adalah String.



Anda dapat berhenti membaca di sini jika Anda tidak ingin masuk lebih jauh ke dalam kode, tetapi hanya ingin menerima permintaan dari API seseorang.

Berikut adalah kode yang berfungsi langsung di luar kotak, salin dan gunakan:

# 
$http = [System.Net.HttpListener]::new() 
 
# ,   
$http.Prefixes.Add("http://localhost/")
$http.Prefixes.Add("https://localhost/")
 
$http.Start()
 
while ($http.IsListening) {
 
  $context = $http.GetContext()
 
  if ($context.Request.HttpMethod -eq 'POST' -and $context.Request.RawUrl -eq '/') {
 
    #  POST 
    $Reader = [System.IO.StreamReader]::new($context.Request.InputStream).ReadToEnd()
    
    #  .
    $DecodedContent = [System.Web.HttpUtility]::UrlDecode($Reader)
          
    #  IPN   
    $Payment = $DecodedContent -split "&" | ConvertFrom-StringData
 
    #   .
    $Payment | Format-Table
 
    #  200 OK   .
    $context.Response.Headers.Add("Content-Type", "text/plain")
    $context.Response.StatusCode = 200
    $ResponseBuffer = [System.Text.Encoding]::UTF8.GetBytes("")
    $context.Response.ContentLength64 = $ResponseBuffer.Length
    $context.Response.OutputStream.Write($ResponseBuffer, 0, $ResponseBuffer.Length)
    $context.Response.Close()
  }
}

Nuansa Minecraft


Jadi, kami mengetahui bagaimana kami dapat menerima pemberitahuan tentang pembayaran, sekarang kami dapat mengkreditnya. Tapi di sini juga tidak sesederhana itu. Masalahnya adalah permainan tidak memberikan item atau mengubah status pemain yang tidak ada di server. Artinya, kita harus menunggu sampai seseorang masuk ke server untuk memberikan apa yang dia bayar.

Karena itu, perhatian Anda disajikan pada konsep umum perokok, untuk mengkredit pembayaran.



Pembayaran diterima melalui Pendengar di atas, hanya satu baris yang ditambahkan untuk menulis objek ke file. Pembayaran Lengkap (Prosesor) melihat nama panggilan dan mencocokkannya dengan nama file. Jika ia menemukan file, kompilasi perintah untuk rcon dan jalankan.

Mulai-minecrafttentang yang penulis tulis dalam artikel sebelumnya sedikit dimodifikasi. Sekarang dia mendengarkan kesimpulannya, melihat nama panggilan para pemain dan menyerahkannya ke pemroses pembayaran.

Membuat panggilan balik nyata


Tanpa menggunakan plugin, kami akan membuat panggilan balik yang benar. Untuk ini, Start-Minecraft telah dimodifikasi. Sekarang dia tidak hanya tahu cara menambahkan StdOut ke file, tetapi juga berjalan di sepanjang setiap baris dengan jadwal reguler. Untungnya, minecraft meninggalkan pesan yang sangat spesifik ketika seorang pemain memasuki server.

[04:20:00 INFO]: UUID of player XXPROHUNTERXX is 23e93d2e-r34d-7h15 -5h17-a9192cd70b48

Sangat mudah untuk memilih nama panggilan dari baris ini. Ini semua kode yang kita butuhkan untuk mendapatkan data dari string Stdout.

$Regex = [Regex]::new("of player ([^ ]+)")
 
powershell.exe -file ".\Start-MinecraftHandler.ps1" -type $type -MinecraftPath $MinecraftPath | Tee-Object $LogFile -Append | ForEach-Object {
 
     Write-host $_
        
    $Player = $Regex.Matches($_).value -replace "of player "
        
    if ($true -eq $Regex.Matches($_).Success) {
        #   
    }
}


Baris baru dimasukkan ke dalam pipeline $ _, kami menulisnya di jendela konsol dan menjalaninya secara teratur. Biasa itu sendiri memberi tahu kita ketika itu bekerja, yang sangat nyaman.

Dari sini kita dapat memanggil kode apa saja. Misalnya, menggunakan RCON yang sama, kita dapat menyapa pemain di PM, menggunakan bot di perselisihan untuk memberi tahu bahwa seseorang telah masuk ke server, melarang skakmat, dan sebagainya.

Melakukan pembayaran


Karena kami mulai memproses pembayaran, kami ingin memiliki setidaknya data yang cukup lengkap tentang operasi dan sejarah operasi yang dilakukan, karena kami berbicara tentang angka dengan dua nol, sehingga untuk berbicara.

Penulis ingin meninggalkan semuanya dengan sangat sederhana dan belum mensimulasikan basis. Mari kita lihat pendekatan NoSQL. Mari kita buat kelas kita sendiri, yang akan mengimpor semua pembayaran yang diterima ke folder / payment / dalam file Json.

    class Payment {
        #  .
        [datetime]$Date = [datetime]::ParseExact($i.payment_date, "HH:mm:ss MMM dd, yyyy PDT", [System.Globalization.CultureInfo]::InvariantCulture)
        # 
        [string]$Item = $i.item_name
        # 
        [UInt16]$Quantity = $i.Quantity
        #    
        [UInt16]$AmountPaid = $AmountPaid -as [UInt16]
        #     
        [string]$Currency = $i.mc_currency
        # ,   
        [string]$Player = $i.option_selection1
    
        [bool]$Completed = $false
        [UInt16]$ItemId = $i.item_number
    }
/source>

    , , ,          .

 ,    <b>option_selection1</b> โ€“   .      input,   ,     .
     <b>option_selection1</b>,<b>option_selection2</b>   .

      ,     ,      .

<source lang="powershell"> #     Payment,        .
    $Payment = [Payment]::new()
    $Payment | Format-Table
    #  ,   ----
    $FileName = $Payment.Player + "-" + $Payment.date.Hour + "-" + $Payment.date.Minute + "-" + $Payment.date.Day + "-" + $Payment.date.Month + "-" + $Payment.date.Year + ".json"
 
# ,      
    $JsonPath = Join-Path $MinecraftPath \payments\Pending $FileName
    
    #   
    $Payment | ConvertTo-Json | Out-File $JsonPath

Hanya itu yang diperlukan dari pendengar kami. Terima data dari PayPal dan tulis ke file.

Kami melakukan pemrosesan pembayaran


Pawang akan disebut yang biasa yang ditulis sebelumnya. Kami mentransfer julukan pemain ke modul dan hanya itu. Selanjutnya, skrip baru diluncurkan, yang mencari file, dan jika ada file, itu memberi pemain item yang ditulis dalam file.

powershell.exe -file "C:\mc.fern\Start-MinecraftHandler.ps1" -type $type -MinecraftPath $MinecraftPath | Tee-Object $LogFile -Append | ForEach-Object {
       
        #     ,      .
        Write-host $_   
 
        # Regex     
        if ($true -eq $Regex.Matches($_).Success) {
            
            #       
            $Player = $Regex.Matches($_).value -replace "of player "
            
            #  ,       
            Complete-Payment -Player $Player
        }
    }

Ketika keteraturan dipicu, modul diluncurkan yang menyelesaikan pembayaran, yaitu memberikan item kepada pemain. Untuk melakukan ini, di folder / Pembayaran / Menunggu /, skrip mencari file yang berisi nama panggilan pemain yang memasuki permainan dan membaca isinya.

Sekarang Anda perlu mengumpulkan perintah untuk server dan mengirimkannya ke sana. Itu akan dikumpulkan dari file. Kami tahu nama panggilan pemain, nama item dan ID-nya dicatat, berapa banyak potongan juga dicatat, tetap hanya mengirim perintah ke server game. Untuk ini kita akan menggunakan mcrcon .

#    
    $JsonPath = Join-Path $MinecraftPath\payments\Pending -ChildPath $Player*
    $i = $JsonPath | Get-Item | Where-Object { !$_.PSIsContainer } | Get-Content | ConvertFrom-Json -ErrorVariable Errored
 
    #      
    if ($null -ne $i) {
 
        #  
        $Command = '"' + "give " + $i.Player + " " + $i.Item + " " + $i.Quantity + '"'
        Write-host $Command -ForegroundColor Green
    
        #   
        Start-Process -FilePath mcrcon.exe -ArgumentList "-H localhost -p 123 -w 5 $Command"
    
        # ,      
        $JsonPath = Join-Path $MinecraftPath\payments\Pending -ChildPath $FileName
        
        #   
        $i | ConvertTo-Json | Out-File $JsonPath
    
        #     
        Move-Item  -Path $JsonPath -Destination $MinecraftPath\payments\Completed
    }

Kami membuat semuanya dalam modul yang nyaman


Proses Java dan proses WebListener memerlukan utas yang berbeda, tetapi penulis tidak puas dengan kebutuhan untuk menjalankan WebListener secara terpisah dan server secara terpisah. Penulis ingin semuanya sekaligus dengan satu tim.

Oleh karena itu, menggunakan Powershell 7, kami akan meluncurkan ini dan itu. Dan itu akan membantu kita:

ForEach-Object -Parallel {}

Cmdlet bekerja dengan inputObject, jadi kami memberinya array yang tidak rumit, dan berbagi stream menggunakan switch.

"A", "B" | ForEach-Object -Parallel {
 
    Import-Module ".\Start-Minecraft.ps1"
 
    Import-Module ".\Start-WebListener.ps1"
 
    switch ($_) {
        "A" {
            Start-WebListener -Path "C:\mc\"
        }
        "B" {
            Start-Minecraft -Type Vanilla -LogFile ".\stdout.txt" -MinecraftPath "C:\mc\"
        }
        
    }
}

Jadi secara kruk, kami memulai dua proses berbeda dari satu terminal dan bahkan tidak kehilangan input. Tapi ada masalah lain. WebListener mengunci konsol setelah server shutdown reguler dan tidak ingin pergi ke mana pun.

Agar tidak me-restart terminal setiap kali, kunci acak ditambahkan ke Start-MinecraftHandler.ps1 dan Start-WebListener.ps1, yang akan menghentikan server melalui POST di WebListener.

Start-MinecraftHandler.ps1, ketika mencatat penyelesaian yang sukses, jalankan perintah:

Invoke-WebRequest -Method Post -Uri localhost -Body $StopToken | Out-Null

$ StopToken berisi nilai numerik acak yang dipra-pass oleh skrip startup ke Listener dan Handler. Pendengar melihat apa yang diterimanya dalam permintaan dan mati jika badan permintaan cocok dengan $ StopToken.

if ($DecodedContent -eq $StopToken) {
        Write-Host "Stopping WebListener"
        $context.Response.Headers.Add("Content-Type", "text/plain")
        $context.Response.StatusCode = 200
        $ResponseBuffer = [System.Text.Encoding]::UTF8.GetBytes("")
        $context.Response.ContentLength64 = $ResponseBuffer.Length
        $context.Response.OutputStream.Write($ResponseBuffer, 0, $ResponseBuffer.Length)
        $context.Response.Close()
        $http.Close()
        break
      }

Cukup aman, hanya RAM yang tahu tentang token dan tidak ada orang lain. Semua modul diluncurkan dari bawah PowerShell 7, dan jalur ke modul untuk PowerShell 7 berbeda dari jalur di Windows Powershell. Semuanya ditumpuk di sini. Ingatlah saat menulis milik Anda sendiri.

C:\Program Files\PowerShell\7\Modules

Kami membuat file konfigurasi


Agar semua aib ini dapat digunakan tanpa sakit kepala parah, Anda harus membuat file konfigurasi normal. File akan berisi variabel dan tidak lebih. Konfigurasi melekat menggunakan standar:

Import-Module $MinecraftPath\config.ps1 -Force

Kita perlu menunjukkan hal yang paling penting. Domain yang disadap adalah domain reguler yang mencari nama panggilan pemain, untuk output mungkin bervariasi dari versi ke versi, dan kata sandi dari rcon.

Ini terlihat seperti ini:

#,    
$DomainName = "localhost"
 
# ,      
# ,  
$RegExp = "of player ([^ ]+)"
#    ,   ,  .
$RegExpCut = "of player "
 
#  rcon,     server.properties
$rconPassword = "123"

Sangat diinginkan untuk menempatkan konfigurasi di folder server, karena skrip mencarinya di root-MinecraftPath

Bagaimana cara menggunakan semua ini?


Pertama-tama, skrip ini diinstal dan siap digunakan di pasar Ruvds , tetapi jika Anda belum memiliki klien atau belum mencoba gambarnya, berikut adalah tautan ke semua file di repositori , jangan ragu untuk melakukan. 

  1. Unduh dan pasang PowerShell 7
  2. Unduh dan unzip arsip modul


Sekarang semua modul dan perintah yang diperlukan telah muncul. Apa yang mereka lakukan?

Mulai-minecraft


Pilihan:

-Tipe
Forge atau Vanilla. Mulai server baik dari Server.Jar atau Forge, memilih versi terbaru yang ada di folder. Poin

-MinecraftPath
ke folder dari mana server akan diluncurkan.

-LogFile
Cara alternatif untuk mengumpulkan log. Mengindikasikan file di mana segala sesuatu yang muncul di konsol akan ditulis.

-StartPaymentListener
Seiring dengan server, ia mulai dan menerima pembayaran. Penerimaan pembayaran itu sendiri tersedia sebagai modul terpisah. Mengganti cmdlet Start-Weblistener

Mulai-weblistener


Mulai modul penerimaan pembayaran. Poin

-MinecraftPath
ke folder dengan file konfigurasi.

-StopToken
Menentukan Permintaan HTTP POST -Tubuh untuk menghentikan WebListener'a.

Kesimpulan:


Nah, keajaiban memang terjadi.


All Articles