منبع اصلی نوشتار زیر در این لینک قرار دارد

از یک دانلود ساده تا یک خود درگیری بزرگ!

یکی از مشکلاتی که لینوکسی همیشه میبینم دربارش بحث میکنن یه دانلودر خوب برای دانلود شبانه‌است. به عبارتی دانلودری که زمان‌بندی هم داشته باشه. البته هستن یه چند تای، ولی هیچکدوم همه شرایط لازم رو همزمان ندارن. ولی خوب، میشه گفت این مشکل خیلی ساده حل میشه.
دانلودرهای خط‌فرمانی خوبی توی لینوکس وجود داره و من،‌به شخصه، شدیدا طرفدار aria2 هستم. بعضیا ممکنه axel رو دوست داشته باشن. ولی خوب برای زمان بندی اینها چه کاری میشه کرد؟ سادست :) cron اینجا به دادتون میرسه.
من برای دانلود از یه mini2440 استفاده میکنم. علتشم اینه که مصرفش خیلی کمه، و از همه مهمتر سر و صدا نداره و مجبور نیستم یه کامپیوتر یا لپ تاب رو بیخود روشن بذارم. روش خیلی ساده aria2 رو کامپایل کردم و الان مدتهاست مثل ساعت داره کار میکنه :)) خوب حالا چطور این کار رو انجام دادم؟
مینی ۲۴۴۰ یکی از تفریحات من :)

توی یه پوشه به خصوص، جایی که میخواید دانلودها اونجا ریخته بشن، یه فایل متنی ساده درست کنید. من اسمشو گذاشتم dl.lst و توی پوشه /mnt/sd این فایل رو قرار دادم. توی هر خط این فایل یه لینک میذارم که قراره دانلود بشه و یه اسکریپت خیلی ساده هم به این صورت مینویسم :

#!/bin/bash

cd /mnt/sd/
aria2c -i /mnt/sd/dl.lst -m 10 -j 2

اینکه آرگومانها چه کاری میکنن، با خودتون :) فقط آرگومان -i رو حواستون بهش باشه که آدرس فایل لیستی که بالاتر درست کردید باید بعدش بیاد.
و نهایتا میرسه نوبت به cron .
اگه ویرایشگر خاصی مدنظرتونه (مثلا nano یا vim یا هرچی ) اینطوری عمل کنید :

EDITOR=nano crontab -e

اینجوری ویرایشگر مورد علاقتون باز میشه و اگه قبلا cron داشته باشید این فایل که باز شده خالی نیست. ولی ممکنه خالی باشه :)‌اونوقت باید یه چیزی شبیه این توش نوشته بشه :

0  2  *  *  *  /bin/aria.sh
0  8  *  *  *  /usr/bin/killall aria2c

ساعت ۲ و ۸ به ترتیب شروع و پایان دانلود رایگان منه. اگه از قبل چیزی در اون فایل بود، فقط اینو به انتهاش اضافه کنید.
فرض بر اینه که اسم اسکریپتی که بالاتر نوشتم، aria.sh باشه توی پوشه bin باشه (شما جای دیگه بذارید من توی mini یه کم محدودیت داشتم :)) )و اجرایی هم شده باشه به این صورت :

chmod a+x /bin/aria.sh

دستور killall هم معمولا تو همین آدرسه ولی اگه خواستید مطمئن بشید بزنید :

which killall

همین :)) فقط کافیه لیست فایلهایی که میخواید دانلود کنید رو بذارید تو فایل dl.lst که اول ساختید.

خود درگیری به سبک یک گیک!!!


خوب خیلیها تا همین‌جا براشون کافیه، برای من نبود.من میخوام دو تا سیستم رو هم به روز نگه دارم. یکی سیستم خودم که آرچه و یکی دیگه هم سیستم بیتا، که مینته. در حقیقت میخوام آپدیتها توی دانلود شبانه گنجونده بشه، و در نهایت بگیرمشون و روی سیستم خودم داشته باشمشون. و اینکار خیلی ساده انجام بشه. یعنی هی نخوام فایلها رو از رو اون سیستم بیارم اینور کپی کنم و فلان. خوب اینجا دیگه حقیقتا حس bash نوشتن نداشتم این شد که رفتم سراغ PHP .
خوب برای اینکار sftp بهترین گزینست. روی دو سیستم اصلی openssh نصبه و روی مینی هم یه نسخه ساده کامپایل کردم از قبل. خوب برای انتقال فایل از sftp میشه این دستورات رو استفاده کرد :

cd /target/dir/on/local
sftp user@server <<EOF
cd /target/dir/on/remote
put /file/address/in/local
get /file/address/in/remote
quit
EOF

خوب زیاد هم سخت نیست. فرض کنید بخواید یه فایل از اون سرور انتقال بدید این طرف، یه فایل از این طرف بفرستید اون طرف :) اول تو سیستم خودتون وارد پوشه مقصد میشید. دستور sftp رو اجرا میکنید بعد توی sftp با کمک دستور cd (که اونجا هم دقیقا مثل اصلش کار میکنه) وارد پوشه مقصد میشید. با دستور put که بعدش باید آدرس فایل روی ماشین خودتون باشه، فایل فرستاده میشه تو پوشه‌ای که بهش cd کردید تو ماشین دوم (سرور) و با دستور get یه فایل رو میتونید از اونجا بگیرید و توی پوشه‌ای که توی ماشین خودتون قبل از دستور sftp داخلش شدید قرار میگیره. و بعد هم quit که خارج میشه .
اون EOF هم یه چیزی مثل Heredoc ها توی PHP رو برای bash پیاده سازی میکنه و میگه از اینجا تا زمانی که به EOF برسی، یه دستوره و چند خط پیاپی و بی ربط نیست.
تنها دستور دیگه که لازمه rm ـه که توی sftp هم دقیقا مثل rm اصلی عمل میکنه (sftp هم چیزی جدای از ssh نیست :) )
خوب قدم به قدم.
اول نیاز دارم بدونم که چه فایلهایی باید برای آپدیت دانلود شن:

#!/usr/bin/php
&lt;?php
echo &quot;Get update list from pacman...\n&quot;;

$updlist = <code>sudo pacman -Syup | egrep -o -e &quot;(ht|f)tp://[^\']+&quot;</code>;
$updlist = explode(&quot;\n&quot;, $updlist );

$updPkg = <code>sudo pacman -Sup --print-format %n</code>;
$updPkg = explode(&quot;\n&quot;, $updPkg );

while (substr($updPkg[0] , 0 , 2) == '::')
    array_shift($updPkg);

$neededPkg = array ();
foreach ($updlist as $indx =&gt; $pkg)
{
    if (!empty($pkg))
    {
        $neededPkg[$updPkg[$indx]] = $pkg;
	}
}
echo &quot;List updates : &quot;;
print_r($neededPkg);

اول pacman رو اجرا میکنیم با سوییچ p و لیست دانلودها رو میگیریم. منتها من بدم نمیومد که اسم پکیجها رو هم داشته باشم. اجرای دوباره pacman برای گرفتن اسم پکیجهاست. بعد این آدرسها رو توی آرایه neededPkg گذاشتم.
حالا وقت اینه که بررسی کنم ببینم آیا قبلا، هیچکدوم از این فایلها دانلود شدن یا نه؟ اونم به این صورت انجام دادم :

define ('server','[email protected]' );
echo &quot;Get downloaded list... \n&quot;;

$cmnd  = &quot;sftp &quot; . server . &quot; &lt;&lt; EOF
ls /mnt/sd
quit
EOF&quot;;

$files =explode (&quot;\n&quot;,<code>$cmnd</code>);

$results = array( );

foreach ( $files as $fi )
{
	$f = trim($fi);
    if ( substr($f , 0 , strlen( &quot;/mnt/sd/&quot; ) ) == '/mnt/sd/')
        $results[ basename($f)] = $f;
}

echo &quot;This is the list of files available on sd card : \n&quot;;
print_r($results);

خیلی ساده :) sftp رو اجرا میکنم، دستور ls رو اجرا میکنم، بعد خروجی رو میگیرم. نتیجه توی آرایه results ریخته شده.
گام سوم ببینم آیا فایلی از فایلهایی که میخوام تو لیست هست یا نه. aria2 وقتی دانلود هنوز تموم نشده باشه یه فایل کنار فایل اصلی میسازه به اسم همون فایل فقط آخرش یه .aria2 میچسبونه. وجود این فایل میتونه نشون بده که فایل کامل دانلود نشده :


$downloaded = array();
$newList = array();
foreach ($neededPkg as $pkg => $addreess)
{
    $x = basename($addreess);
    if (isset($results[$x] ) && !isset( $results[$x . ".aria2"]))
    {
       $downloaded[$pkg] = $x;
       echo $x . " is done. \n";
    }
    else
    {
        $newList[] = $addreess;
        echo $x . " is NOT done. \n";
    }
}

$newList = implode("\n", $newList );
file_put_contents("/tmp/upd.lst" , $newList);

اگه دقت کنید یه فایل لیست ایجاد شده (/tmp/upd.lst ) حاوی فایلهایی که لازمن ولی هنوز دانلودشون تموم نشده. آرایه downloaded هم لیست فایلهاییه که دانلود شدن. خوب حالا قدم نهایی گرفتن این فایلهاست از سرور و آوردنشون روی سیستم محلیه.
من میخوام اونها رو بریزم توی پوشه‌ای به نام .upd توی home خودم. برای همین لازمه که اول وارد این پوشه بشم :


chdir (&quot;/home/f0rud/.upd&quot;);

$newCmnd = 'sftp ' . server . &quot; &lt;&lt;EOF
cd /mnt/sd/
rm /mnt/sd/upd.lst
put /tmp/upd.lst
&quot;;

$pacman = 'sudo pacman -S --noconfirm ';
$updateIsAvailable = false;
foreach ($downloaded as $p =&gt; $x)
{
    $newCmnd .= &quot;\nget \&quot;/mnt/sd/$x\&quot;&quot;;
    $newCmnd .= &quot;\nrm \&quot;/mnt/sd/$x\&quot;&quot;;
    $pacman .= &quot; $p &quot;;
    $updateIsAvailable = true;
}

$newCmnd .= &quot;\nquit
EOF
&quot;;

echo $newCmnd;

<code>$newCmnd</code>;

یه متغیر newCmnd درست میشه که توی این دستور، فایل upd.lst که دفعه قبل ساخته شد، فرستاده میشه به طرف سرور، فایلهایی که در مرحله قبل فهمیدیم دانلودشون تموم شدن، یکی یکی از سرور گرفته میشن، بعد از روی سرور حذف میشن، و همزمان یه دستوری هم ساخته میشه که باید در مرحله آخر برای آپدیت فایلهای دانلود شده اون دستور اجرا بشه. (منظورم متغیر pacman توی کده. ) خوب، وقتشه newCmnd اجرا میشه (یادم رفت بگم که اپراتور بک تیک توی PHP ، دستور رو داخل شل اجرا میکنه :)) ) محض احتیاط، دستور ایجاد شده رو هم چاپ میکنیم که ببینیم چه خبره :)
و حالا گام آخر، وقتشه که پکمن اجرا بشه.


if ($updateIsAvailable)
{
	$str = &quot;sudo mv /home/f0rud/.upd/* /var/cache/pacman/pkg/&quot;;
	</code>$str<code>;

	echo $pacman;

	</code>$pacman<code>;
}else
	echo &quot;No update for now.&quot;;

اگه آپدیتی باشه، فایلها به پوشه کش پکمن منتقل میشن، و بعد پکمن اجرا میشه.
خوب حالا یه مشکلی هست، این فایل upd.lst که الان اون طرف هست، چطور باید به لیست دانلود اضافه بشه؟ خیلی ساده! اسکریپت بالایی رو که هنوز یادتون هست؟ همونی که aria2 رو اجرا میکرد و اسمش aria.sh بود . تغییرش دادم به این :

#!/bin/bash

cd /mnt/sd/
cat /mnt/sd/upd.lst > /mnt/sd/dl
echo " " >> /mnt/sd/dl
cat /mnt/sd/dl.lst >> /mnt/sd/dl

aria2c -i /mnt/sd/dl -m 10 -j 2

همین :)) حالا کافیه که فایل php رو اجرایی کنم، و بعد هم خیلی ساده اونو اجراش کنم و تمام! خودش همه کارها رو انجام میده. فقط یه مشکل :) این sftp رمز میخواد. sudo هم به همچنین :) حالا sudo قابل تحمله،‌ چون یه بار که میپرسه تا یه مدتی بیخیال میشه :) ولی sftp چی؟ خیلی سادست :))

توجه کنید لطفا! اگر قبلا برای مثلا github یا هر جای دیگه یا هر دلیل دیگه کلید خودتون رو درست کردید، گام اول رو انجام ندید وگرنه کلید قبلی از بین میره!!!!

~  ᐅ ssh-keygen   
Generating public/private rsa key pair.
Enter file in which to save the key (/home/f0rud/.ssh/id_rsa): 
Created directory '/home/f0rud/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/f0rud/.ssh/id_rsa.
Your public key has been saved in /home/f0rud/.ssh/id_rsa.pub.
The key fingerprint is:
29:90:f2:bc:3b:61:4a:d1:32:85:03:f0:70:4f:d3:a3 f0rud@elbit
The key's randomart image is:
+--[ RSA 2048]----+
|=...o.           |
| +oo.oo          |
|  o++. .         |
|  ++E.   .       |
|   +o . S        |
|  . o. .         |
| . o..           |
|  . ..           |
|    ..           |
+-----------------+

با دستور ssh-keygen یه کلید جدید درست کنید. هر چی پرسید فقط Enter بزنید. یعد در گام دوم، با دستور ssh-copy-id این کلید رو منتقل کنید به ماشین مقصد :

ssh-copy-id [email protected] 

اینجا رمز ماشین رو میپرسه، بعد کلید رو منتقل میکنه. حالا سعی کنید به ماشین مقصد ssh کنید. اگه همه چی درست باشه دیگه رمز ازتون نمیپرسه. خوب همه چی حله!!!!
اینم کل اسکریپت بالایی به صورت یک جا :

#!/usr/bin/php
&lt;?php
define ('server','[email protected]' );

echo &quot;Get update list from pacman...\n&quot;;

$updlist = </code>sudo pacman -Syup | egrep -o -e &quot;(ht|f)tp://[^\']+&quot;<code>;
$updlist = explode(&quot;\n&quot;, $updlist );

$updPkg = </code>sudo pacman -Sup --print-format %n<code>;
$updPkg = explode(&quot;\n&quot;, $updPkg );

while (substr($updPkg[0] , 0 , 2) == '::')
    array_shift($updPkg);

$neededPkg = array ();
foreach ($updlist as $indx =&gt; $pkg)
{
    if (!empty($pkg))
    {
        $neededPkg[$updPkg[$indx]] = $pkg;
	}
}
echo &quot;List updates : &quot;;
print_r($neededPkg);

echo &quot;Get downloaded list... \n&quot;;

$cmnd  = &quot;sftp &quot; . server . &quot; &lt;&lt; EOF
ls /mnt/sd
quit
EOF&quot;;

$files =explode (&quot;\n&quot;,</code>$cmnd<code>);

$results = array( );

foreach ( $files as $fi )
{
	$f = trim($fi);
    if ( substr($f , 0 , strlen( &quot;/mnt/sd/&quot; ) ) == '/mnt/sd/')
        $results[ basename($f)] = $f;
}

echo &quot;This is the list of files available on sd card : \n&quot;;
print_r($results);

$downloaded = array();
$newList = array();
foreach ($neededPkg as $pkg =&gt; $addreess)
{
    $x = basename($addreess);
    if (isset($results[$x] ) &amp;&amp; !isset( $results[$x . &quot;.aria2&quot;]))
    {
       $downloaded[$pkg] = $x;
       echo $x . &quot; is done. \n&quot;;
    }
    else
    {
        $newList[] = $addreess;
        echo $x . &quot; is NOT done. \n&quot;;
    }
}

$newList = implode(&quot;\n&quot;, $newList );
file_put_contents(&quot;/tmp/upd.lst&quot; , $newList);

chdir (&quot;/home/f0rud/.upd&quot;);

$newCmnd = 'sftp ' . server . &quot; &lt;&lt;EOF
cd /mnt/sd/
rm /mnt/sd/upd.lst
put /tmp/upd.lst
&quot;;

$pacman = 'sudo pacman -S --noconfirm ';
$updateIsAvailable = false;
foreach ($downloaded as $p =&gt; $x)
{
    $newCmnd .= &quot;\nget \&quot;/mnt/sd/$x\&quot;&quot;;
    $newCmnd .= &quot;\nrm \&quot;/mnt/sd/$x\&quot;&quot;;
    $pacman .= &quot; $p &quot;;
    $updateIsAvailable = true;
}

$newCmnd .= &quot;\nquit
EOF
&quot;;

echo $newCmnd;

</code>$newCmnd<code>;

if ($updateIsAvailable)
{
	$str = &quot;sudo mv /home/f0rud/.upd/* /var/cache/pacman/pkg/&quot;;
	</code>$str<code>;

	echo $pacman;

	</code>$pacman`;
}else
	echo &quot;No update for now.&quot;;

چقدر نوشتم!!!!!



برچسب ها : , , , , , , ,