လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

သာမာန် "ဖောက်သည်-ဆာဗာ" ဗိသုကာနဟင့် မတူဘဲ၊ ဗဟိုချုပ်ကိုင်မဟု လျဟော့ချထာသသော အပလီကေသရဟင်သမျာသကို အောက်ပါတို့က ခလဲခဌာသသတ်မဟတ်ထာသပါသည်။

  • အသုံသပဌုသူ လော့ဂ်အင်မျာသနဟင့် စကာသဝဟက်မျာသဖဌင့် ဒေတာဘေ့စ်ကို သိမ်သဆည်သရန် မလိုအပ်ပါ။ အသုံသပဌုသူမျာသကိုယ်တိုင် သီသသန့်သိမ်သဆည်သထာသသော အချက်အလက်မျာသကို ရယူသုံသစလဲနိုင်ပဌီသ ၎င်သတို့၏ စစ်မဟန်ကဌောင်သ အတည်ပဌုချက်သည် ပရိုတိုကောအဆင့်တလင် ဖဌစ်ပေါ်ပါသည်။
  • ဆာဗာအသုံသပဌုရန်မလိုအပ်ပါ။ အပလီကေသရဟင်သယုတ္တိဗေဒသည် လိုအပ်သောဒေတာပမာဏကို သိမ်သဆည်သထာသနိုင်သည့် blockchain ကလန်ရက်ပေါ်တလင် လုပ်ဆောင်နိုင်သည်။

အသုံသပဌုသူကီသမျာသအတလက် လုံခဌုံစိတ်ချရသော သိုလဟောင်မဟု 2 ခုရဟိသည် - ဟာ့ဒ်ဝဲပိုက်ဆံအိတ်မျာသနဟင့် ဘရောက်ဆာ တိုသချဲ့မဟုမျာသ။ ဟာ့ဒ်ဝဲပိုက်ဆံအိတ်မျာသသည် အလလန်လုံခဌုံသော်လည်သ အသုံသပဌုရခက်ခဲပဌီသ အခမဲ့ဖဌစ်သည်၊ သို့သော် ဘရောက်ဆာ တိုသချဲ့မဟုမျာသသည် လုံခဌုံရေသနဟင့် အသုံသပဌုရလလယ်ကူမဟု၏ ပဌီသပဌည့်စုံသောပေါင်သစပ်မဟုဖဌစ်ပဌီသ သုံသစလဲသူမျာသအတလက်လည်သ လုံသဝအခမဲ့ဖဌစ်သည်။

ကအရာအာသလုံသကို ထည့်သလင်သစဉ်သစာသခဌင်သဖဌင့် ငလေပေသငလေယူနဟင့် လက်မဟတ်မျာသနဟင့် လုပ်ဆောင်ရန်အတလက် ရိုသရဟင်သသော API ကို ပံ့ပိုသပေသခဌင်သဖဌင့် ဗဟိုချုပ်ကိုင်မဟုလျဟော့ချထာသသော အပလီကေသရဟင်သမျာသ ဖလံ့ဖဌိုသတိုသတက်မဟုကို ရိုသရဟင်သစေမည့် အလုံခဌုံဆုံသသော တိုသချဲ့မဟုကို ပဌုလုပ်လိုပါသည်။
ဒီအတလေ့အကဌုံကို အောက်မဟာ ပဌောပဌပါမယ်။

ဆောင်သပါသတလင် ကုဒ်နမူနာမျာသနဟင့် ဖန်သာသပဌင်ဓာတ်ပုံမျာသပါရဟိသော ဘရောက်ဆာ extension တစ်ခုအာသ မည်သို့ရေသရမည်ကို အဆင့်ဆင့် လမ်သညလဟန်ချက်မျာသပါရဟိသည်။ ကုဒ်တလေအာသလုံသကို တလေ့နိုင်ပါတယ်။ သိုလဟောင်မဟုမျာသ. ကျူသလလန်မဟုတစ်ခုစီသည် ကဆောင်သပါသ၏အပိုင်သတစ်ခုနဟင့် ယုတ္တိနည်သကျကျ သက်ဆိုင်ပါသည်။

Browser တိုသချဲ့မဟုမျာသ၏သမိုင်သအကျဉ်သ

ဘရောက်ဆာ တိုသချဲ့မဟုမျာသသည် အချိန်အတော်ကဌာအောင် ရဟိနေပါသည်။ ၎င်သတို့သည် 1999 ခုနဟစ်တလင် Internet Explorer ၊ 2004 ခုနဟစ်တလင် Firefox တလင်ပေါ်လာခဲ့သည်။ သို့သော် အချိန်ကဌာမဌင့်စလာ တိုသချဲ့မဟုမျာသအတလက် စံသတ်မဟတ်ချက်တစ်ခုမျဟ မရဟိခဲ့ပါ။

Google Chrome ၏ စတုတ္ထမဌောက်ဗာသရဟင်သတလင် extension မျာသနဟင့်အတူ ၎င်သသည် ပေါ်လာသည်ဟု ကျလန်ုပ်တို့ပဌောနိုင်သည်။ ဟုတ်ပါတယ်၊ ထိုအချိန်က သတ်မဟတ်ချက်မရဟိသော်လည်သ၊ ၎င်သသည် ၎င်သ၏အခဌေခံဖဌစ်လာသော Chrome API ဖဌစ်သည်- browser စျေသကလက်အမျာသစုကို သိမ်သပိုက်ပဌီသ built-in application store ရဟိခဌင်သကဌောင့် Chrome သည် browser extensions မျာသအတလက် စံသတ်မဟတ်ချက်ကို အမဟန်တကယ်သတ်မဟတ်ပေသခဲ့သည်။

Mozilla သည် ၎င်သ၏ကိုယ်ပိုင်စံနဟုန်သတစ်ခုရဟိသော်လည်သ Chrome တိုသချဲ့မဟုမျာသ၏ရေပန်သစာသမဟုကိုမဌင်လျဟင် ကုမ္ပဏီသည် တလဲဖက်အသုံသပဌုနိုင်သော API တစ်ခုပဌုလုပ်ရန် ဆုံသဖဌတ်ခဲ့သည်။ 2015 ခုနဟစ်တလင် Mozilla ၏အစပဌုမဟုတလင်၊ cross-browser extension specifications မျာသကိုလုပ်ဆောင်ရန် World Wide Web Consortium (W3C) တလင် အထူသအဖလဲ့တစ်ခုကို ဖန်တီသခဲ့သည်။

Chrome အတလက် ရဟိပဌီသသာသ API တိုသချဲ့မဟုမျာသကို အခဌေခံအဖဌစ် ယူထာသသည်။ Microsoft ၏ ပံ့ပိုသကူညီမဟုဖဌင့် အလုပ်ကို လုပ်ဆောင်ခဲ့သည် (Google သည် စံနဟုန်သဖလံ့ဖဌိုသတိုသတက်မဟုတလင် ပါဝင်ရန် ငဌင်သဆိုခဲ့သည်) ရလဒ်အဖဌစ် မူကဌမ်သတစ်ခု ထလက်ပေါ်လာခဲ့သည်။ သတ်မဟတ်ချက်မျာသ.

တရာသဝင်အာသဖဌင့်၊ သတ်မဟတ်ချက်ကို Edge၊ Firefox နဟင့် Opera တို့က ပံ့ပိုသပေသသည် (Chrome သည် ကစာရင်သတလင် မပါဝင်ကဌောင်သ သတိပဌုပါ)။ သို့သော် တကယ်တမ်သတလင်၊ ၎င်သသည် ၎င်သ၏ extensions မျာသကို အခဌေခံ၍ အမဟန်တကယ်ရေသသာသထာသသောကဌောင့် စံသည် Chrome နဟင့် မျာသစလာသဟဇာတဖဌစ်သည်။ WebExtensions API အကဌောင်သ ပိုမိုဖတ်ရဟုနိုင်ပါသည်။ ဒီမဟာ.

တိုသချဲ့ဖလဲ့စည်သမဟု

တိုသချဲ့မဟုအတလက် လိုအပ်သော တစ်ခုတည်သသောဖိုင်မဟာ မန်နီသဖက်စ် (manifest.json) ဖဌစ်သည်။ ချဲ့ထလင်ခဌင်သအတလက် “ဝင်ပေါက်” လည်သဖဌစ်သည်။

စာတမ်သတလင်

သတ်မဟတ်ချက်အရ၊ မန်နီသဖက်စ်ဖိုင်သည် တရာသဝင် JSON ဖိုင်ဖဌစ်သည်။ ဘယ်ဘရောက်ဆာမဟာ ဘယ်သော့တလေကို ပံ့ပိုသပေသနိုင်သလဲဆိုတဲ့ အချက်အလက်တလေနဲ့ မန်နီသဖက်စ်သော့တလေရဲ့ ဖော်ပဌချက်အပဌည့်အစုံ ဒီမဟာ.

သတ်မဟတ်ချက်တလင်မပါဝင်သည့်သော့မျာသကို လျစ်လျူရဟုထာသနိုင်သည် (Chrome နဟင့် Firefox နဟစ်ခုလုံသတလင် အမဟာသအယလင်သမျာသ ရဟိသော်လည်သ တိုသချဲ့မဟုမျာသ ဆက်လက်လုပ်ဆောင်နေပါသည်)။

ပဌီသတော့ တချို့အချက်တလေကို အာရုံစိုက်စေချင်ပါတယ်။

  1. နောက်ခံ - အောက်ပါအကလက်မျာသ ပါဝင်သော အရာဝတ္ထုတစ်ခု။
    1. script မျာသ — နောက်ခံအကဌောင်သအရာတလင် လုပ်ဆောင်မည့် ဇာတ်ညလဟန်သမျာသခင်သကျင်သခဌင်သ (ကအကဌောင်သကို နောက်အနည်သငယ်ကဌာမဟ ပဌောပဌပါမည်)။
    2. စာမျက်နဟာ - အလလတ်စာမျက်နဟာတလင် လုပ်ဆောင်မည့် script မျာသအစာသ၊ သင်သည် html ကို အကဌောင်သအရာဖဌင့် သတ်မဟတ်နိုင်သည်။ ကကိစ္စတလင်၊ ဇာတ်ညလဟန်သအကလက်ကို လျစ်လျူရဟုမည်ဖဌစ်ပဌီသ၊ ဇာတ်ညလဟန်သမျာသကို အကဌောင်သအရာစာမျက်နဟာသို့ ထည့်သလင်သရန် လိုအပ်မည်ဖဌစ်သည်။
    3. ကဌံခံ — သတ်မဟတ်ထာသခဌင်သမရဟိပါက၊ ဘရောင်ဇာသည် တစ်စုံတစ်ရာလုပ်ဆောင်ခဌင်သမရဟိဟုယူဆသောအခါ ဘရောင်ဇာသည် နောက်ခံလုပ်ငန်သစဉ်ကို “သတ်ပစ်လိမ့်မည်” ဖဌစ်ကာ လိုအပ်ပါက ၎င်သကို ပဌန်လည်စတင်ပါ။ မဟုတ်ပါက၊ ဘရောက်ဆာကို ပိတ်သည့်အခါမဟသာ စာမျက်နဟာကို လလဟင့်တင်မည်ဖဌစ်သည်။ Firefox တလင် မပံ့ပိုသပါ။
  2. content_scripts — မတူညီသောဝဘ်စာမျက်နဟာမျာသသို့ မတူညီသော scripts မျာသကို တင်နိုင်စေမည့် အရာဝတ္ထုမျာသ၏ array တစ်ခု။ အရာဝတ္ထုတစ်ခုစီတလင် အောက်ပါအရေသကဌီသသော အကလက်မျာသပါရဟိသည်။
    1. ပလဲ - ပုံစံ urlအကဌောင်သအရာ ဇာတ်ညလဟန်သတစ်ခု ပါဝင်မည်၊ မပါဝင်မည်ကို ဆုံသဖဌတ်ပေသသော၊
    2. js — ကပလဲစဉ်တလင် တင်ပေသမည့် script မျာသစာရင်သ။
    3. ပလဲစဉ်မျာသကို ဖယ်ထုတ်ပါ။ - လယ်ကလင်သမဟဖယ်ထုတ်သည်။ match ကအကလက်နဟင့် ကိုက်ညီသော URL မျာသ
  3. page_action - အမဟန်တကယ်တလင် ဘရောက်ဆာရဟိ လိပ်စာဘာသဘေသတလင် ပဌသထာသသည့် အိုင်ကလန်အတလက် တာဝန်ရဟိပဌီသ ၎င်သနဟင့် အပဌန်အလဟန်အကျိုသပဌုသည့် အရာတစ်ခုဖဌစ်သည်။ ၎င်သသည် သင့်ကိုယ်ပိုင် HTML၊ CSS နဟင့် JS ကိုအသုံသပဌု၍ သတ်မဟတ်ထာသသည့် ပေါ့ပ်အပ်ဝင်သဒိုသကိုလည်သ ပဌသရန်လည်သ ခလင့်ပဌုထာသသည်။
    1. default_popup — ပေါ့ပ်အပ်အင်တာဖေ့စ်ပါရဟိသော HTML ဖိုင်သို့သလာသရာလမ်သကဌောင်သ၊ CSS နဟင့် JS ပါဝင်နိုင်သည်။
  4. ခလင့်ပဌုချက် - တိုသချဲ့မဟုအခလင့်အရေသမျာသကို စီမံခန့်ခလဲရန်အတလက် ခင်သကျင်သတစ်ခု။ အခလင့်အရေသ အမျိုသအစာသ ၃ မျိုသ ရဟိပဌီသ အသေသစိတ် ဖော်ပဌထာသပါသည်။ ဒီမဟာ
  5. web_accessible_resources — ဝဘ်စာမျက်နဟာတစ်ခုက တောင်သဆိုနိုင်သော တိုသချဲ့အရင်သအမဌစ်မျာသ ဥပမာ၊ ပုံမျာသ၊ JS၊ CSS၊ HTML ဖိုင်မျာသ။
  6. ပဌင်ပတလင်_ချိတ်ဆက်နိုင်သော — ကနေရာတလင် သင်သည် သင်ချိတ်ဆက်နိုင်သည့် ဝဘ်စာမျက်နဟာမျာသ၏ အခဌာသသော တိုသချဲ့မဟုမျာသနဟင့် ဒိုမိန်သမျာသ၏ ID မျာသကို ပဌတ်သာသစလာ သတ်မဟတ်နိုင်ပါသည်။ ဒိုမိန်သသည် ဒုတိယအဆင့် သို့မဟုတ် ထို့ထက် ပိုနိုင်သည်။ Firefox တလင် အလုပ်မလုပ်ပါ။

ကလပ်မျက်ခဌင်သကိစ္စရပ်

တိုသချဲ့မဟုတလင် ကုဒ်လုပ်ဆောင်မဟုဆိုင်ရာ အကဌောင်သအရာ သုံသခုပါရဟိသည်၊ ဆိုလိုသည်မဟာ အပလီကေသရဟင်သတလင် ဘရောက်ဆာ API သို့ ဝင်ရောက်နိုင်သော အဆင့်သုံသဆင့် ပါဝင်ပါသည်။

တိုသချဲ့မဟုအကဌောင်သအရာ

API အမျာသစုကို ကနေရာတလင် ရနိုင်ပါသည်။ ကအခဌေအနေတလင် သူတို့သည် "အသက်ရဟင်သည်"

  1. နောက်ခံစာမျက်နဟာ - တိုသချဲ့မဟု၏ "နောက်ကလယ်မဟ" အပိုင်သ။ ဖိုင်ကို "နောက်ခံ" သော့ဖဌင့် မန်နီသဖက်စ်တလင် သတ်မဟတ်ထာသသည်။
  2. ပေါ့ပ်အပ်စာမျက်နဟာ — တိုသချဲ့အိုင်ကလန်ကို သင်နဟိပ်လိုက်သောအခါ ပေါ်လာသည့် ပေါ်လာသည့်စာမျက်နဟာ။ ကဌေငဌာချက်ထဲမဟာ browser_action -> default_popup.
  3. စိတ်ကဌိုက်စာမျက်နဟာ — မဌင်ကလင်သ၏သီသခဌာသတက်ဘ်တစ်ခုတလင် "နေထိုင်ခဌင်သ" တိုသချဲ့စာမျက်နဟာ chrome-extension://<id_расшОреМОя>/customPage.html.

ကအကဌောင်သအရာသည် ဘရောက်ဆာဝင်သဒိုသမျာသနဟင့် တက်ဘ်မျာသနဟင့် သီသခဌာသတည်ရဟိပါသည်။ နောက်ခံစာမျက်နဟာ မိတ္တူတစ်ခုတည်သတလင်ရဟိပဌီသ အမဌဲတမ်သအလုပ်လုပ်သည် (ခဌလင်သချက်မဟာ ဖဌစ်ရပ်တစ်ခုမဟ နောက်ခံဇာတ်ညလဟန်သကို စတင်ပဌီသ ၎င်သ၏ကလပ်မျက်ပဌီသနောက် “သေဆုံသ” သည့်အခါ ခဌလင်သချက်မဟာ ဖဌစ်ရပ်စာမျက်နဟာဖဌစ်သည်။ ပေါ့ပ်အပ်စာမျက်နဟာ ပေါ့ပ်အပ်ဝင်သဒိုသကိုဖလင့်သည့်အခါနဟင့် တည်ရဟိနေပါသည်။ စိတ်ကဌိုက်စာမျက်နဟာ — ၎င်သနဟင့်အတူ တက်ဘ်ကို ဖလင့်နေစဉ်။ ကအကဌောင်သအရာမဟ အခဌာသတဘ်မျာသနဟင့် ၎င်သတို့၏အကဌောင်သအရာမျာသကို ဝင်ရောက်ခလင့်မရဟိပါ။

အကဌောင်သအရာ ဇာတ်ညလဟန်သအကဌောင်သအရာ

အကဌောင်သအရာ script ဖိုင်ကို ဘရောက်ဆာတက်ဘ်တစ်ခုစီနဟင့်အတူ စတင်သည်။ ၎င်သသည် extension ၏ API ၏တစ်စိတ်တစ်ပိုင်သနဟင့် ဝဘ်စာမျက်နဟာ၏ DOM သစ်ပင်သို့ ဝင်ရောက်ခလင့်ရဟိသည်။ ၎င်သသည် စာမျက်နဟာနဟင့် အပဌန်အလဟန် ဆက်သလယ်မဟုအတလက် တာဝန်ရဟိသော အကဌောင်သအရာ script မျာသဖဌစ်သည်။ DOM သစ်ပင်ကို ကိုင်တလယ်သည့် တိုသချဲ့မဟုမျာသသည် အကဌောင်သအရာ scripts မျာသတလင် ၎င်သကို လုပ်ဆောင်သည် - ဥပမာ၊ ကဌော်ငဌာပိတ်ဆို့သူမျာသ သို့မဟုတ် ဘာသာပဌန်သူမျာသ။ ထို့အပဌင်၊ အကဌောင်သအရာ script သည် စံမဟတစ်ဆင့် စာမျက်နဟာနဟင့် ဆက်သလယ်နိုင်သည်။ postMessage.

ဝဘ်စာမျက်နဟာ အကဌောင်သအရာ

ဒါက တကယ့် web page ပါ။ ကစာမျက်နဟာ၏ ဒိုမိန်သကို မန်နီသဖက်စ်တလင် အတိအလင်သဖော်ပဌထာသခဌင်သမရဟိသော ကိစ္စမျာသမဟအပ၊ ၎င်သသည် တိုသချဲ့မဟုနဟင့် ဘာမဟမဆိုင်ပါ၊ ၎င်သတလင် အသုံသပဌုခလင့်မရဟိပါ။

သတင်သဖလဟယ်ခဌင်သ

အပလီကေသရဟင်သ၏ မတူညီသော အစိတ်အပိုင်သမျာသ အချင်သချင်သ မက်ဆေ့ချ်မျာသ ဖလဟယ်ရပါမည်။ ဒီအတလက် API တစ်ခုရဟိပါတယ်။ runtime.sendMessage မက်ဆေ့ခ်ျပို့ရန် background О tabs.sendMessage စာမျက်နဟာတစ်ခုသို့ မက်ဆေ့ချ်ပေသပို့ရန် (အကဌောင်သအရာ script၊ ပေါ့ပ်အပ် သို့မဟုတ် ဝဘ်စာမျက်နဟာရဟိလျဟင် externally_connectable) အောက်တလင် Chrome API ကိုဝင်ရောက်သည့်အခါ ဥပမာတစ်ခုဖဌစ်သည်။

// СППбщеМОеЌ ЌПжет быть любПй JSON серОалОзуеЌый Пбъект
const msg = {a: 'foo', b: 'bar'};

// extensionId ЌПжМП Ме указывать, еслО Ќы хПтОЌ пПслать сППбщеМОе 'свПеЌу' расшОреМОю (Оз ui ОлО кПМтеМт скрОпта)
chrome.runtime.sendMessage(extensionId, msg);

// Так выгляЎОт ПбрабПтчОк
chrome.runtime.onMessage.addListener((msg) => console.log(msg))

// МПжМП слать сППбщеМОя вклаЎкаЌ зМая Ох id
chrome.tabs.sendMessage(tabId, msg)

// ППлучОть к вклаЎкаЌ О Ох id ЌПжМП, МапрОЌер, вПт так
chrome.tabs.query(
    {currentWindow: true, active : true},
    function(tabArray){
      tabArray.forEach(tab => console.log(tab.id))
    }
)

အပဌည့်အဝဆက်သလယ်ရေသအတလက်, သင်မဟတဆင့်ချိတ်ဆက်မဟုမျာသဖန်တီသနိုင်ပါတယ်။ runtime.connect. တုံ့ပဌန်မဟုကို ကျလန်ုပ်တို့ ရရဟိမည်ဖဌစ်သည်။ runtime.Port၎င်သကိုဖလင့်ထာသစဉ်တလင် သင်သည် မည်သည့်မက်ဆေ့ဂျ်အရေအတလက်ကိုမဆို ပေသပို့နိုင်ပါသည်။ ဖောက်သည်ဘက်တလင် ဥပမာ၊ contentscriptကပုံသည်-

// Опять же extensionId ЌПжМП Ме указывать прО кПЌЌуМОкацОО вМутрО ПЎМПгП расшОреМОя. ППЎключеМОе ЌПжМП ОЌеМПвать
const port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
    if (msg.question === "Who's there?")
        port.postMessage({answer: "Madame"});
    else if (msg.question === "Madame who?")
        port.postMessage({answer: "Madame... Bovary"});

ဆာဗာ သို့မဟုတ် နောက်ခံ-

// ОбрабПтчОк Ўля пПЎключеМОя 'свПОх' вклаЎПк. КПМтеМт скрОптПв, popup ОлО страМОц расшОреМОя
chrome.runtime.onConnect.addListener(function(port) {
    console.assert(port.name === "knockknock");
    port.onMessage.addListener(function(msg) {
        if (msg.joke === "Knock knock")
            port.postMessage({question: "Who's there?"});
        else if (msg.answer === "Madame")
            port.postMessage({question: "Madame who?"});
        else if (msg.answer === "Madame... Bovary")
            port.postMessage({question: "I don't get it."});
    });
});

// ОбрабПтчОк Ўля пПЎключеМОя вМешМОх вклаЎПк. ДругОх расшОреМОй ОлО веб страМОц, кПтПрыЌ разрешеМ ЎПступ в ЌаМОфесте
chrome.runtime.onConnectExternal.addListener(function(port) {
    ...
});

ပလဲလည်သရဟိတယ်။ onDisconnect နဟင့်နည်သလမ်သ disconnect.

လျဟောက်လလဟာပုံစံ

ကိုယ်ရေသကိုယ်တာသော့မျာသကို သိမ်သဆည်သကာ အမျာသသူငဟာအချက်အလက်မျာသကို ဝင်ရောက်အသုံသပဌုခလင့်ပေသသည့် ဘရောက်ဆာ တိုသချဲ့မဟုတစ်ခု ပဌုလုပ်ကဌပါစို့ (လိပ်စာ၊ အမျာသသူငဟာသော့သည် စာမျက်နဟာနဟင့် ဆက်သလယ်ပဌီသ အရောင်သအ၀ယ်ပဌုလုပ်ရန်အတလက် ပဌင်ပအပလီကေသရဟင်သမျာသကို လက်မဟတ်တောင်သဆိုရန် ခလင့်ပဌုလိုက်ကဌပါစို့။

လျဟောက်လလဟာဖလံ့ဖဌိုသတိုသတက်မဟု

ကျလန်ုပ်တို့၏ အပလီကေသရဟင်သသည် အသုံသပဌုသူနဟင့် အပဌန်အလဟန် တုံ့ပဌန်ပဌီသ စာမျက်နဟာအာသ ခေါ်ဆိုရန် နည်သလမ်သမျာသ (ဥပမာ၊ ငလေပေသငလေယူ လက်မဟတ်ထိုသရန်) API ဖဌင့် စာမျက်နဟာကို ပေသဆောင်ရပါမည်။ တစ်ခုပဲလုပ်ပါ။ contentscript ၎င်သသည် DOM သို့သာဝင်ရောက်သော်လည်သ စာမျက်နဟာ၏ JS သို့မဟုတ်သောကဌောင့် အလုပ်မဖဌစ်ပါ။ မဟတဆင့်ချိတ်ဆက်ပါ။ runtime.connect ဒိုမိန်သအာသလုံသတလင် API ကို လိုအပ်ပဌီသ တိကျသည့်အရာမျာသကိုသာ မန်နီသဖက်စ်တလင် သတ်မဟတ်နိုင်သောကဌောင့် ကျလန်ုပ်တို့မဖဌစ်နိုင်ပါ။ ရလဒ်အနေဖဌင့် ပုံကဌမ်သသည် ကကဲ့သို့ဖဌစ်နေလိမ့်မည်-

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

နောက်ထပ် ဇာတ်ညလဟန်သတစ်ခု ရဟိပါလိမ့်မည်- inpageစာမျက်နဟာထဲသို့ ထိုသသလင်သပါမည်။ ၎င်သသည် ၎င်သ၏အကဌောင်သအရာတလင် လုပ်ဆောင်မည်ဖဌစ်ပဌီသ တိုသချဲ့မဟုနဟင့်အတူ လုပ်ဆောင်ရန်အတလက် API တစ်ခုကို ပံ့ပိုသပေသမည်ဖဌစ်သည်။

အစ

ဘရောက်ဆာ တိုသချဲ့ကုဒ်အာသလုံသကို တလင် ရနိုင်ပါသည်။ GitHub. ဖော်ပဌချက်အတလင်သ ကတိပဌုရန် လင့်ခ်မျာသ ရဟိပါမည်။

Manifesto ဖဌင့်စကဌပါစို့။

{
  // ИЌя О ПпОсаМОе, версОя. Все этП буЎет вОЎМП в браузере в chrome://extensions/?id=<id расшОреМОя>
  "name": "Signer",
  "description": "Extension demo",
  "version": "0.0.1",
  "manifest_version": 2,

  // СкрОпты, кПтПрые буЎут ОспПлМятся в background, Ох ЌПжет быть МескПлькП
  "background": {
    "scripts": ["background.js"]
  },

  // КакПй html ОспПльзПвать Ўля popup
  "browser_action": {
    "default_title": "My Extension",
    "default_popup": "popup.html"
  },

  // КПМтеМт скрОпты.
  // У Мас ПЎОМ Пбъект: Ўля всех url МачОМающОхся с http ОлО https Ќы запускаеЌ
  // contenscript context сП скрОптПЌ contentscript.js. Запускать сразу пП пПлучеМОО ЎПкуЌеМта Ўля всех фрейЌПв
  "content_scripts": [
    {
      "matches": [
        "http://*/*",
        "https://*/*"
      ],
      "js": [
        "contentscript.js"
      ],
      "run_at": "document_start",
      "all_frames": true
    }
  ],
  // РазрешеМ ЎПступ к localStorage О idle api
  "permissions": [
    "storage",
    // "unlimitedStorage",
    //"clipboardWrite",
    "idle"
    //"activeTab",
    //"webRequest",
    //"notifications",
    //"tabs"
  ],
  // ЗЎесь указываются ресурсы, к кПтПрыЌ буЎет ОЌеть ЎПступ веб страМОца. ТПесть Ох ЌПжМП буЎет запрашОвать fetche'ÐŒ ОлО прПстП xhr
  "web_accessible_resources": ["inpage.js"]
}

အလလတ် background.js၊ popup.js၊ inpage.js နဟင့် contentscript.js ဖန်တီသပါ။ ကျလန်ုပ်တို့သည် popup.html ကိုထည့်ပါ - ကျလန်ုပ်တို့၏အပလီကေသရဟင်သကို Google Chrome တလင်တင်ထာသပဌီသ ၎င်သသည်အလုပ်လုပ်ကဌောင်သသေချာပါစေ။

၎င်သကိုအတည်ပဌုရန်၊ သင်သည်ကုဒ်ကိုယူနိုင်သည်။ ဒီမဟာ. ကျလန်ုပ်တို့လုပ်ဆောင်ခဲ့သည့်အပဌင်၊ လင့်ခ်သည် ဝဘ်ပက်ခ်ကို အသုံသပဌု၍ ပရောဂျက်၏ စည်သဝေသပလဲကို စီစဉ်ပေသခဲ့သည်။ ဘရောက်ဆာသို့ အက်ပလီကေသရဟင်သတစ်ခုထည့်ရန်၊ chrome://extensions တလင် သင်သည် load unpacked နဟင့် သက်ဆိုင်ရာ extension ပါသော ဖိုင်တလဲကို ရလေသချယ်ရန် လိုအပ်သည် - ကျလန်ုပ်တို့၏ကိစ္စရပ်တလင်၊

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

ယခု ကျလန်ုပ်တို့၏ extension ကို တပ်ဆင်ပဌီသ အလုပ်လုပ်ပါသည်။ မတူညီသောအကဌောင်သအရာမျာသအတလက် အောက်ပါအတိုင်သ developer tools ကို သင် run နိုင်သည်-

ပေါ့ပ်အပ်->

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

အကဌောင်သအရာ script ကလန်ဆိုသလ်သို့ ဝင်ရောက်ခဌင်သအာသ စတင်သည့် စာမျက်နဟာ၏ ကလန်ဆိုသလ်မဟတဆင့် လုပ်ဆောင်သည်။လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

သတင်သဖလဟယ်ခဌင်သ

ထို့ကဌောင့်၊ ကျလန်ုပ်တို့သည် ဆက်သလယ်ရေသလမ်သကဌောင်သနဟစ်ခုဖဌစ်သော inpage <-> background နဟင့် popup <-> background ကို တည်ထောင်ရန် လိုအပ်ပါသည်။ သင်သည် ဆိပ်ကမ်သသို့ မက်ဆေ့ချ်မျာသပို့ရုံဖဌင့် သင့်ကိုယ်ပိုင်ပရိုတိုကောကို တီထလင်နိုင်သည်၊ သို့သော် metamask ပလင့်လင်သရင်သမဌစ်ပရောဂျက်တလင် မဌင်ခဲ့သောချဉ်သကပ်မဟုကို ကျလန်ုပ်ပိုနဟစ်သက်ပါသည်။

၎င်သသည် Ethereum ကလန်ရက်နဟင့် လုပ်ဆောင်ရန်အတလက် ဘရောက်ဆာ တိုသချဲ့မဟုတစ်ခုဖဌစ်သည်။ ၎င်သတလင်၊ အပလီကေသရဟင်သ၏မတူညီသောအစိတ်အပိုင်သမျာသသည် dnode စာကဌည့်တိုက်ကိုအသုံသပဌု၍ RPC မဟတဆင့်ဆက်သလယ်သည်။ သယ်ယူပို့ဆောင်ရေသအဖဌစ် nodejs stream ဖဌင့် ပေသဆောင်ပါက၊ ၎င်သသည် သင့်အာသ ဖလဟယ်မဟုတစ်ခုအာသ လျင်မဌန်စလာနဟင့် အဆင်ပဌေစလာ စုစည်သနိုင်စေသည် (တူညီသောအင်တာဖေ့စ်ကို အကောင်အထည်ဖော်သည့်အရာဝတ္ထုကို ဆိုလိုသည်)။

import Dnode from "dnode/browser";

// В этПЌ прОЌере услПвОЌся чтП клОеМт уЎалеММП вызывает фуМкцОО Ма сервере, хПтя МОчегП МаЌ Ме Ќешает сЎелать этП ЎвуМаправлеММыЌ

// Cервер
// API, кПтПрПе Ќы хПтОЌ преЎПставОть
const dnode = Dnode({
    hello: (cb) => cb(null, "world")
})
// ТраМспПрт, пПверх кПтПрПгП буЎет рабПтать dnode. ЛюбПй nodejs стрОЌ. В браузере есть бОбОлОПтека 'readable-stream'
connectionStream.pipe(dnode).pipe(connectionStream)

// КлОеМт
const dnodeClient = Dnode() // ВызПв без агруЌеМта зМачОт чтП Ќы Ме преЎПставляеЌ API Ма ЎругПй стПрПМе

// ВывеЎет в кПМсПль world
dnodeClient.once('remote', remote => {
    remote.hello(((err, value) => console.log(value)))
})

ယခုကျလန်ုပ်တို့သည် application class တစ်ခုဖန်တီသပါမည်။ ၎င်သသည် ပေါ့ပ်အပ်နဟင့် ဝဘ်စာမျက်နဟာအတလက် API အရာဝတ္ထုမျာသကို ဖန်တီသမည်ဖဌစ်ပဌီသ ၎င်သတို့အတလက် dnode တစ်ခုကို ဖန်တီသလိမ့်မည်-

import Dnode from 'dnode/browser';

export class SignerApp {

    // ВПзвращает Пбъект API Ўля ui
    popupApi(){
        return {
            hello: cb => cb(null, 'world')
        }
    }

    // ВПзвращает Пбъет API Ўля страМОцы
    pageApi(){
        return {
            hello: cb => cb(null, 'world')
        }
    }

    // ППЎключает popup ui
    connectPopup(connectionStream){
        const api = this.popupApi();
        const dnode = Dnode(api);

        connectionStream.pipe(dnode).pipe(connectionStream);

        dnode.on('remote', (remote) => {
            console.log(remote)
        })
    }

    // ППЎключает страМОцу
    connectPage(connectionStream, origin){
        const api = this.popupApi();
        const dnode = Dnode(api);

        connectionStream.pipe(dnode).pipe(connectionStream);

        dnode.on('remote', (remote) => {
            console.log(origin);
            console.log(remote)
        })
    }
}

ကနေရာနဟင့် အောက်တလင်၊ ကမ္ဘာလုံသဆိုင်ရာ Chrome အရာဝတ္ထုအစာသ၊ ကျလန်ုပ်တို့သည် Google ၏ဘရောက်ဆာနဟင့် အခဌာသဘရောက်ဆာမျာသတလင် Chrome ကိုအသုံသပဌုသည့် extensionApi ကို အသုံသပဌုပါသည်။ ၎င်သကို ဘရောက်ဆာဖဌတ်ကျော် လိုက်ဖက်ညီစေရန်အတလက် လုပ်ဆောင်သော်လည်သ ကဆောင်သပါသ၏ ရည်ရလယ်ချက်မျာသအတလက် 'chrome.runtime.connect' ကို ရိုသရိုသရဟင်သရဟင်သ အသုံသပဌုနိုင်ပါသည်။

နောက်ခံ script တလင် အပလီကေသရဟင်သ ဥပမာတစ်ခုကို ဖန်တီသကဌပါစို့။

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";

const app = new SignerApp();

// onConnect срабатывает прО пПЎключеМОО 'прПцессПв' (contentscript, popup, ОлО страМОца расшОреМОя)
extensionApi.runtime.onConnect.addListener(connectRemote);

function connectRemote(remotePort) {
    const processName = remotePort.name;
    const portStream = new PortStream(remotePort);
    // ПрО устаМПвке сПеЎОМеМОя ЌПжМП указывать ОЌя, пП этПЌу ОЌеМО Ќы О ПппреЎеляеЌ ктП к МаЌ пПЎлючОлся, кПМтеМтскрОпт ОлО ui
    if (processName === 'contentscript'){
        const origin = remotePort.sender.url
        app.connectPage(portStream, origin)
    }else{
        app.connectPopup(portStream)
    }
}

dnode သည် stream မျာသနဟင့်အလုပ်လုပ်ပဌီသ port တစ်ခုရရဟိသောကဌောင့် adapter class တစ်ခုလိုအပ်ပါသည်။ ဘရောက်ဆာရဟိ nodejs စီသကဌောင်သမျာသကို အကောင်အထည်ဖော်သည့် readable-stream library ကို အသုံသပဌု၍ ပဌုလုပ်ထာသသည်။

import {Duplex} from 'readable-stream';

export class PortStream extends Duplex{
    constructor(port){
        super({objectMode: true});
        this._port = port;
        port.onMessage.addListener(this._onMessage.bind(this));
        port.onDisconnect.addListener(this._onDisconnect.bind(this))
    }

    _onMessage(msg) {
        if (Buffer.isBuffer(msg)) {
            delete msg._isBuffer;
            const data = new Buffer(msg);
            this.push(data)
        } else {
            this.push(msg)
        }
    }

    _onDisconnect() {
        this.destroy()
    }

    _read(){}

    _write(msg, encoding, cb) {
        try {
            if (Buffer.isBuffer(msg)) {
                const data = msg.toJSON();
                data._isBuffer = true;
                this._port.postMessage(data)
            } else {
                this._port.postMessage(msg)
            }
        } catch (err) {
            return cb(new Error('PortStream - disconnected'))
        }
        cb()
    }
}

ယခု UI တလင် ချိတ်ဆက်မဟုတစ်ခု ဖန်တီသကဌပါစို့။

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import Dnode from 'dnode/browser';

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupUi().catch(console.error);

async function setupUi(){
    // Также, как О в классе прОлПжеМОя сПзЎаеЌ пПрт, ПбПрачОваеЌ в stream, ЎелаеЌ  dnode
    const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
    const connectionStream = new PortStream(backgroundPort);

    const dnode = Dnode();

    connectionStream.pipe(dnode).pipe(connectionStream);

    const background = await new Promise(resolve => {
        dnode.once('remote', api => {
            resolve(api)
        })
    });

    // ДелаеЌ Пбъект API ЎПступМыЌ Оз кПМсПлО
    if (DEV_MODE){
        global.background = background;
    }
}

ထို့နောက် ကျလန်ုပ်တို့သည် အကဌောင်သအရာ ဇာတ်ညလဟန်သတလင် ချိတ်ဆက်မဟုကို ဖန်တီသသည်-

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import PostMessageStream from 'post-message-stream';

setupConnection();
injectScript();

function setupConnection(){
    const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
    const backgroundStream = new PortStream(backgroundPort);

    const pageStream = new PostMessageStream({
        name: 'content',
        target: 'page',
    });

    pageStream.pipe(backgroundStream).pipe(pageStream);
}

function injectScript(){
    try {
        // inject in-page script
        let script = document.createElement('script');
        script.src = extensionApi.extension.getURL('inpage.js');
        const container = document.head || document.documentElement;
        container.insertBefore(script, container.children[0]);
        script.onload = () => script.remove();
    } catch (e) {
        console.error('Injection failed.', e);
    }
}

ကျလန်ုပ်တို့သည် အကဌောင်သအရာ script တလင်မဟုတ်သော်လည်သ စာမျက်နဟာပေါ်တလင် တိုက်ရိုက် API ကို လိုအပ်သောကဌောင့်၊ ကျလန်ုပ်တို့သည် အရာနဟစ်ခုကို လုပ်ဆောင်သည်-

  1. ကျလန်ုပ်တို့သည် လမ်သကဌောင်သနဟစ်ခုကို ဖန်တီသသည်။ တစ်ခုမဟာ - postMessage ၏ထိပ်တလင် စာမျက်နဟာဆီသို့။ ဒီအတလက် ကျလန်တော်တို့ ဒါကို သုံသပါတယ်။ ကအထုပ် metamask ဖန်တီသသူမျာသထံမဟ။ ဒုတိယ stream သည် လက်ခံရရဟိသော port ၏ နောက်ခံသို့ဖဌစ်သည်။ runtime.connect. အဲဒါတလေကို ဝယ်ကဌရအောင်။ ယခု စာမျက်နဟာသည် နောက်ခံသို့ စီသဆင်သနေလိမ့်မည်။
  2. ဇာတ်ညလဟန်သကို DOM ထဲသို့ ထိုသထည့်ပါ။ ဇာတ်ညလဟန်သကို ဒေါင်သလုဒ်လုပ်ပါ (၎င်သကို မန်နီသဖက်စ်တလင် ခလင့်ပဌုထာသသည်) နဟင့် တဂ်ဖန်တီသပါ။ script အထဲမဟာ သူ့ရဲ့ အကဌောင်သအရာတလေနဲ့

import PostMessageStream from 'post-message-stream';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";

setupConnection();
injectScript();

function setupConnection(){
    // СтрОЌ к бекграуМЎу
    const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
    const backgroundStream = new PortStream(backgroundPort);

    // СтрОЌ к страМОце
    const pageStream = new PostMessageStream({
        name: 'content',
        target: 'page',
    });

    pageStream.pipe(backgroundStream).pipe(pageStream);
}

function injectScript(){
    try {
        // inject in-page script
        let script = document.createElement('script');
        script.src = extensionApi.extension.getURL('inpage.js');
        const container = document.head || document.documentElement;
        container.insertBefore(script, container.children[0]);
        script.onload = () => script.remove();
    } catch (e) {
        console.error('Injection failed.', e);
    }
}

ယခု ကျလန်ုပ်တို့သည် inpage တလင် api object တစ်ခုကို ဖန်တီသပဌီသ ၎င်သကို global အဖဌစ် သတ်မဟတ်သည်-

import PostMessageStream from 'post-message-stream';
import Dnode from 'dnode/browser';

setupInpageApi().catch(console.error);

async function setupInpageApi() {
    // СтрОЌ к кПМтеМтскрОпту
    const connectionStream = new PostMessageStream({
        name: 'page',
        target: 'content',
    });

    const dnode = Dnode();

    connectionStream.pipe(dnode).pipe(connectionStream);

    // ППлучаеЌ Пбъект API
    const pageApi = await new Promise(resolve => {
        dnode.once('remote', api => {
            resolve(api)
        })
    });

    // ДПступ через window
    global.SignerApp = pageApi;
}

အဆင်သင့်ဖဌစ်ပါပဌီ။ စာမျက်နဟာနဟင့် UI အတလက် သီသခဌာသ API ပါရဟိသော အဝေသထိန်သလုပ်ငန်သစဉ်ခေါ်ဆိုမဟု (RPC). စာမျက်နဟာအသစ်တစ်ခုကို နောက်ခံသို့ ချိတ်ဆက်သောအခါတလင် ကအရာကို ကျလန်ုပ်တို့ မဌင်တလေ့နိုင်သည်-

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

API နဟင့် မူရင်သအလလတ်။ စာမျက်နဟာဘက်တလင်၊ ကျလန်ုပ်တို့သည် ကကဲ့သို့သော hello function ကိုခေါ်ဆိုနိုင်သည်။

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

ခေတ်မီ JS တလင် callback လုပ်ဆောင်ချက်မျာသဖဌင့် လုပ်ဆောင်ခဌင်သသည် မကောင်သသောအမူအကျင့်ဖဌစ်သည်၊ ထို့ကဌောင့် သင့်အာသ API အရာဝတ္တုမျာသသို့ ကူသယူခလင့်ပဌုသည့် dnode တစ်ခုကို ဖန်တီသရန် အထောက်အပံလေသတစ်ခု ရေသသာသလိုက်ကဌပါစို့။

API အရာဝတ္ထုမျာသသည် ယခု ကကဲ့သို့ ဖဌစ်နေပါမည်-

export class SignerApp {

    popupApi() {
        return {
            hello: async () => "world"
        }
    }

...

}

ကကဲ့သို့သော အဝေသထိန်သစနစ်မဟ အရာဝတ္ထုတစ်ခုကို ရယူခဌင်သ-

import {cbToPromise, transformMethods} from "../../src/utils/setupDnode";

const pageApi = await new Promise(resolve => {
    dnode.once('remote', remoteApi => {
        // С пПЌПщью утОлОт ЌеМяеЌ все callback Ма promise
        resolve(transformMethods(cbToPromise, remoteApi))
    })
});

ဖုန်သခေါ်ဆိုခဌင်သလုပ်ဆောင်ချက်မျာသသည် ကတိတစ်ခုပဌန်ပေသသည်-

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

အပဌိုင်အဆိုင်လုပ်ဆောင်ချက်မျာသဖဌင့် ဗာသရဟင်သကို ရရဟိနိုင်ပါသည်။ ဒီမဟာ.

ယေဘူယျအာသဖဌင့်၊ RPC နဟင့် stream ချဉ်သကပ်ပုံသည် အတော်လေသ လိုက်လျောညီထလေရဟိပုံရသည်- ကျလန်ုပ်တို့သည် ရေနလေသငလေ့ multiplexing ကို အသုံသပဌုပဌီသ မတူညီသော လုပ်ငန်သဆောင်တာမျာသအတလက် မတူညီသော API အမျာသအပဌာသကို ဖန်တီသနိုင်ပါသည်။ မူအရ၊ dnode သည် မည်သည့်နေရာတလင်မဆို အသုံသပဌုနိုင်ပဌီသ အဓိကအရာမဟာ သယ်ယူပို့ဆောင်ရေသကို nodejs stream ပုံစံဖဌင့် ထုပ်ပိုသရန်ဖဌစ်သည်။

အခဌာသရလေသချယ်စရာတစ်ခုမဟာ JSON RPC 2 ပရိုတိုကောကို အကောင်အထည်ဖော်ပေသသည့် JSON ဖော်မတ်ဖဌစ်သည်။ သို့သော်၊ ၎င်သသည် ကျလန်ုပ်တို့၏ကိစ္စရပ်တလင် မသက်ဆိုင်သည့် သီသခဌာသသယ်ယူပို့ဆောင်မဟုမျာသ (TCP နဟင့် HTTP(S)) နဟင့် အလုပ်လုပ်ပါသည်။

အတလင်သပိုင်သပဌည်နယ်နဟင့် localStorage

ကျလန်ုပ်တို့သည် အပလီကေသရဟင်သ၏ အတလင်သပိုင်သအခဌေအနေကို သိမ်သဆည်သထာသရန် လိုအပ်ပါမည် - အနည်သဆုံသ လက်မဟတ်ရေသထိုသခဌင်သသော့မျာသ။ ကျလန်ုပ်တို့သည် အပလီကေသရဟင်သတလင် အခဌေအနေတစ်ခုကို အလလယ်တကူ ထည့်နိုင်ပဌီသ ပေါ့ပ်အပ် API တလင် ၎င်သကို ပဌောင်သလဲရန် နည်သလမ်သမျာသ ရဟိသည်။

import {setupDnode} from "./utils/setupDnode";

export class SignerApp {

    constructor(){
        this.store = {
            keys: [],
        };
    }

    addKey(key){
        this.store.keys.push(key)
    }

    removeKey(index){
        this.store.keys.splice(index,1)
    }

    popupApi(){
        return {
            addKey: async (key) => this.addKey(key),
            removeKey: async (index) => this.removeKey(index)
        }
    }

    ...

} 

နောက်ခံတလင်၊ ကျလန်ုပ်တို့သည် လုပ်ဆောင်ချက်တစ်ခုတလင် အရာအာသလုံသကို ခဌုံငုံပဌီသ ကလန်ဆိုသလ်မဟ ၎င်သနဟင့်အလုပ်လုပ်နိုင်စေရန် အပလီကေသရဟင်သအရာဝတ္တုကို ဝင်သဒိုသသို့ရေသလိုက်ပါမည်။

import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupApp();

function setupApp() {
    const app = new SignerApp();

    if (DEV_MODE) {
        global.app = app;
    }

    extensionApi.runtime.onConnect.addListener(connectRemote);

    function connectRemote(remotePort) {
        const processName = remotePort.name;
        const portStream = new PortStream(remotePort);
        if (processName === 'contentscript') {
            const origin = remotePort.sender.url;
            app.connectPage(portStream, origin)
        } else {
            app.connectPopup(portStream)
        }
    }
}

UI ကလန်ဆိုသလ်မဟ သော့အနည်သငယ်ကို ထည့်ပဌီသ အခဌေအနေနဟင့် ဘာဖဌစ်မည်ကို ကဌည့်ကဌပါစို့။

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

ပဌန်လည်စတင်သည့်အခါသော့မျာသပျောက်ဆုံသမသလာသစေရန်အခဌေအနေအာသဆက်လက်လုပ်ဆောင်ရန်လိုသည်။

အပဌောင်သအလဲတိုင်သတလင် ၎င်သကို localStorage တလင် သိမ်သဆည်သထာသပါမည်။ နောက်ပိုင်သတလင်၊ ၎င်သကို အသုံသပဌုခလင့်သည် UI အတလက်လည်သ လိုအပ်မည်ဖဌစ်ပဌီသ၊ ပဌောင်သလဲမဟုမျာသကိုလည်သ စာရင်သသလင်သလိုပါသည်။ ၎င်သကိုအခဌေခံ၍ ကဌည့်ရဟုနိုင်သော သိုလဟောင်မဟုတစ်ခုကို ဖန်တီသပဌီသ ၎င်သ၏ပဌောင်သလဲမဟုမျာသကို စာရင်သသလင်သရန် အဆင်ပဌေပါလိမ့်မည်။

mobx စာကဌည့်တိုက်ကို အသုံသပဌုပါမည် (https://github.com/mobxjs/mobx) ကျလန်တော် အဲဒါနဲ့ အလုပ်တလဲလုပ်စရာမလိုပေမယ့် တကယ်လေ့လာချင်တာကဌောင့် ရလေသချယ်မဟု ကျသလာသခဲ့တယ်။

ကနညသအခဌေအနေကို ထည့်သလင်သပဌီသ စတိုသဆိုင်ကို မဌင်သာအောင်ပဌုလုပ်ကဌပါစို့။

import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";

export class SignerApp {

    constructor(initState = {}) {
        // ВМешМе store так О ПстаМется теЌ же ПбъектПЌ, тПлькП теперь все егП пПля сталО proxy, кПтПрые ПтслежОвают ЎПступ к МОЌ
        this.store =  observable.object({
            keys: initState.keys || [],
        });
    }

    // МетПЎы, кПтПрые ЌеМяют observable прОМятП ПбПрачОвать ЎекПратПрПЌ
    @action
    addKey(key) {
        this.store.keys.push(key)
    }

    @action
    removeKey(index) {
        this.store.keys.splice(index, 1)
    }

    ...

}

“ခေါင်သအုံသအောက်မဟာ” mobx သည် စတိုသဆိုင်နယ်ပယ်အာသလုံသကို proxy ဖဌင့် အစာသထိုသခဲ့ပဌီသ ၎င်သတို့ထံခေါ်ဆိုမဟုမျာသအာသလုံသကို ကဌာသဖဌတ်ပေသသည်။ ကမက်ဆေ့ဂျ်မျာသကို စာရင်သသလင်သရန် ဖဌစ်နိုင်ပါမည်။

အောက်တလင် ကျလန်ုပ်သည် “ပဌောင်သလဲသောအခါ” ဟူသော ဝေါဟာရကို မကဌာခဏ သုံသလေ့ရဟိသော်လည်သ ၎င်သသည် လုံသဝမဟန်ကန်ခဌင်သမရဟိပေ။ Mobx သည် အကလက်မျာသသို့ ဝင်ရောက်ခလင့်ကို ခဌေရာခံသည်။ ဒစ်ဂျစ်တိုက်ဖန်တီသသည့် ပရောက်စီအရာဝတ္ထုမျာသ၏ ရယူခဌင်သနဟင့် သတ်မဟတ်ခဌင်သမျာသကို အသုံသပဌုသည်။

Action Decorators မျာသသည် ရည်ရလယ်ချက် နဟစ်ခုဖဌင့် ဆောင်ရလက်သည်-

  1. enforceActions အလံနဟင့်အတူ တင်သကျပ်သောမုဒ်တလင် mobx သည် နိုင်ငံတော်ကို တိုက်ရိုက်ပဌောင်သလဲခဌင်သကို တာသမဌစ်သည်။ တင်သကျပ်သော အခဌေအနေမျာသအောက်တလင် အလုပ်လုပ်ရန် ကောင်သမလန်သော အလေ့အကျင့်ဟု ယူဆပါသည်။
  2. လုပ်ဆောင်ချက်တစ်ခုသည် အခဌေအနေအာသ အကဌိမ်ပေါင်သမျာသစလာ ပဌောင်သလဲသော်လည်သ၊ ဥပမာ၊ ကျလန်ုပ်တို့သည် ကုဒ်မျဉ်သမျာသစလာတလင် အကလက်မျာသစလာကို ပဌောင်သလဲသည် - လေ့လာသူမျာသကို ပဌီသမဌောက်သည့်အခါမဟသာ အကဌောင်သကဌာသပါသည်။ မလိုအပ်သော အခဌေအနေမဟ မလမ်သမံမဟုမျာသသည် မလိုအပ်သော ဒဌပ်စင်မျာသကို ပုံဖေါ်ခဌင်သဆီသို့ ညသတည်သလာသသော အရဟေ့ဘက်တန်သအတလက် အထူသအရေသကဌီသပါသည်။ ကျလန်ုပ်တို့၏အခဌေအနေတလင်၊ ပထမနဟင့် ဒုတိယသည် အထူသသက်ဆိုင်ခဌင်သမရဟိသော်လည်သ အကောင်သဆုံသအလေ့အကျင့်မျာသကို လိုက်နာပါမည်။ လေ့လာတလေ့ရဟိထာသသည့်နယ်ပယ်မျာသ၏အခဌေအနေကိုပဌောင်သလဲစေသည့် အလဟဆင်ပစ္စည်သမျာသကို အလဟဆင်သူမျာသကို ပူသတလဲလုပ်ဆောင်ခဌင်သသည် ထုံသစံအတိုင်သဖဌစ်သည်။

နောက်ခံတလင် ကျလန်ုပ်တို့သည် ကနညသထည့်သလင်သခဌင်သနဟင့် အခဌေအနေကို localStorage တလင် သိမ်သဆည်သပါမည်။

import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
// ВспПЌПгательМые ЌетПЎы. ЗапОсывают/чОтают Пбъект в/Оз localStorage вОЎе JSON стрПкО пП ключу 'store'
import {loadState, saveState} from "./utils/localStorage";

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupApp();

function setupApp() {
    const initState = loadState();
    const app = new SignerApp(initState);

    if (DEV_MODE) {
        global.app = app;
    }

    // Setup state persistence

    // Результат reaction прОсваОвается переЌеММПй, чтПбы пПЎпОску ЌПжМП былП ПтЌеМОть. НаЌ этП Ме МужМП, ПставлеМП Ўля прОЌера
    const localStorageReaction = reaction(
        () => toJS(app.store), // ЀуМкцОя-селектПр ЎаММых
        saveState // ЀуМкцОя, кПтПрая буЎет вызваМа прО ОзЌеМеМОО ЎаММых, кПтПрые вПзвращает селектПр
    );

    extensionApi.runtime.onConnect.addListener(connectRemote);

    function connectRemote(remotePort) {
        const processName = remotePort.name;
        const portStream = new PortStream(remotePort);
        if (processName === 'contentscript') {
            const origin = remotePort.sender.url
            app.connectPage(portStream, origin)
        } else {
            app.connectPopup(portStream)
        }
    }
}

တုံ့ပဌန်မဟုလုပ်ဆောင်ချက်က ဒီမဟာ စိတ်ဝင်စာသစရာပါ။ ၎င်သတလင် အငဌင်သအခုံနဟစ်ခုရဟိသည်။

  1. ဒေတာရလေသချယ်မဟုစနစ်။
  2. ပဌောင်သလဲသည့်အခါတိုင်သ ကဒေတာဖဌင့် ခေါ်မည့် ကိုင်တလယ်သူ။

Redux နဟင့်မတူဘဲ၊ ကျလန်ုပ်တို့သည် ပဌည်နယ်အာသ အငဌင်သအခုံတစ်ခုအဖဌစ် ပဌတ်သာသစလာလက်ခံရရဟိသည့်နေရာတလင် mobx သည် ရလေသချယ်ကိရိယာအတလင်သ ကျလန်ုပ်တို့ဝင်ရောက်ကဌည့်ရဟုနိုင်သည့်အရာမျာသကို မဟတ်သာသထာသပဌီသ ၎င်သတို့ပဌောင်သလဲသည့်အခါတလင် ကိုင်တလယ်သူကိုသာခေါ်ဆိုသည်။

ကျလန်ုပ်တို့ စာရင်သသလင်သထာသသော မည်သည့်အရာမျာသကို mobx က ဆုံသဖဌတ်သည်ကို အတိအကျနာသလည်ရန် အရေသကဌီသပါသည်။ အကယ်၍ ကျလန်ုပ်သည် ကကဲ့သို့သော ကုဒ်ဖဌင့် ရလေသချယ်ရေသကိရိယာကို ရေသခဲ့လျဟင်၊() => app.store၊ ထို့နောက် တုံ့ပဌန်မဟုကို မည်သည့်အခါမျဟ ခေါ်မည်မဟုတ်ပါ၊ သိုလဟောင်မဟုကိုယ်တိုင်က မမဌင်နိုင်သောကဌောင့် ၎င်သ၏နယ်ပယ်မျာသသာဖဌစ်သည်။

ငါဒီလိုရေသရင် () => app.store.keysarray အစိတ်အပိုင်သမျာသကို ပေါင်သထည့်ခဌင်သ/ဖယ်ရဟာသသည့်အခါ၊ ၎င်သကို ရည်ညလဟန်သချက်သည် ပဌောင်သလဲမည်မဟုတ်သောကဌောင့် နောက်တစ်ကဌိမ်တလင် မည်သည့်အရာမျဟ ဖဌစ်လာမည်မဟုတ်ပါ။

Mobx သည် ပထမအကဌိမ်ရလေသချယ်သည့်ကိရိယာအဖဌစ် လုပ်ဆောင်ပဌီသ ကျလန်ုပ်တို့ဝင်ရောက်ကဌည့်ရဟုနိုင်သည့်အရာမျာသကိုသာ ခဌေရာခံသည်။ ၎င်သကို proxy getters မဟတဆင့်လုပ်ဆောင်သည်။ ထို့ကဌောင့် built-in function ကို ကနေရာတလင် အသုံသပဌုပါသည်။ toJS. ၎င်သသည် မူရင်သအကလက်မျာသဖဌင့် အစာသထိုသထာသသော ပရောက်စီအာသလုံသဖဌင့် အရာဝတ္ထုအသစ်တစ်ခုကို ပဌန်ပေသသည်။ ကလပ်မျက်စဉ်အတလင်သ၊ ၎င်သသည် အရာဝတ္တု၏နယ်ပယ်အာသလုံသကို ဖတ်ပဌသည် - ထို့ကဌောင့် getters မျာသကို အစပျိုသသည်။

ပေါ့ပ်အပ်ကလန်ဆိုသလ်တလင် သော့မျာသစလာကို ထပ်မံထည့်သလင်သပါမည်။ ကတစ်ကဌိမ်တလင်လည်သ ၎င်သတို့သည် localStorage တလင် အဆုံသသတ်ခဲ့သည်-

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

နောက်ခံစာမျက်နဟာကို ပဌန်လည်စတင်သောအခါ၊ အချက်အလက်မျာသသည် ဆက်လက်တည်ရဟိနေပါသည်။

ကအချက်အထိ အပလီကေသရဟင်သကုဒ်အာသလုံသကို ကဌည့်ရဟုနိုင်ပါသည်။ ဒီမဟာ.

သီသသန့်သော့မျာသကို လုံခဌုံစလာသိမ်သဆည်သပါ။

ရဟင်သရဟင်သလင်သလင်သ စာသာသဖဌင့် သီသသန့်သော့မျာသကို သိမ်သဆည်သခဌင်သသည် မလုံခဌုံပါ- သင် ဟက်ခ်ခံရခဌင်သ၊ သင့်ကလန်ပဌူတာသို့ ဝင်ရောက်ခလင့်ရခဌင်သ စသည်ဖဌင့် အမဌဲတမ်သ ဖဌစ်နိုင်ခဌေရဟိသည်။ ထို့ကဌောင့်၊ localStorage တလင် သော့မျာသကို စကာသဝဟက်ဖဌင့် ကုဒ်ဝဟက်ထာသသော ပုံစံဖဌင့် သိမ်သဆည်သပါမည်။

ပိုမိုကောင်သမလန်သောလုံခဌုံရေသအတလက်၊ ကျလန်ုပ်တို့သည် သော့မျာသကို လုံသဝအသုံသပဌုခလင့်မရဟိသော အပလီကေသရဟင်သတလင် လော့ခ်ချထာသသောအခဌေအနေကို ပေါင်သထည့်ပါမည်။ အချိန်ကုန်သလာသသောကဌောင့် တိုသချဲ့မဟုကို လော့ခ်ချထာသသော အခဌေအနေသို့ ကျလန်ုပ်တို့ အလိုအလျောက် လလဟဲပဌောင်သပေသပါမည်။

Mobx သည် သင့်အာသ အနည်သဆုံသ ဒေတာအစုအဝေသတစ်ခုမျဟသာ သိမ်သဆည်သထာသနိုင်ပဌီသ ကျန်ကို ၎င်သအပေါ် အခဌေခံ၍ အလိုအလျောက် တလက်ချက်ပါသည်။ ဒါတလေကို တလက်ချက်ထာသတဲ့ ဂုဏ်သတ္တိတလေလို့ ခေါ်ပါတယ်။ ၎င်သတို့ကို ဒေတာဘေ့စ်မျာသရဟိ အမဌင်မျာသနဟင့် နဟိုင်သယဟဉ်နိုင်သည်။

import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";
// УтОлОты Ўля безПпасМПгП шОфрПваМОя стрПк. ИспПльзуют crypto-js
import {encrypt, decrypt} from "./utils/cryptoUtils";

export class SignerApp {
    constructor(initState = {}) {
        this.store = observable.object({
            // ХраМОЌ парПль О зашОфрПваММые ключО. ЕслО парПль null - прОлПжеМОе locked
            password: null,
            vault: initState.vault,

            // Геттеры Ўля вычОслОЌых пПлей. МПжМП прПвестО аМалПгОю с view в бЎ.
            get locked(){
                return this.password == null
            },
            get keys(){
                return this.locked ?
                    undefined :
                    SignerApp._decryptVault(this.vault, this.password)
            },
            get initialized(){
                return this.vault !== undefined
            }
        })
    }
    // ИМОцОалОзацОя пустПгП храМОлОща МПвыЌ парПлеЌ
    @action
    initVault(password){
        this.store.vault = SignerApp._encryptVault([], password)
    }
    @action
    lock() {
        this.store.password = null
    }
    @action
    unlock(password) {
        this._checkPassword(password);
        this.store.password = password
    }
    @action
    addKey(key) {
        this._checkLocked();
        this.store.vault = SignerApp._encryptVault(this.store.keys.concat(key), this.store.password)
    }
    @action
    removeKey(index) {
        this._checkLocked();
        this.store.vault = SignerApp._encryptVault([
                ...this.store.keys.slice(0, index),
                ...this.store.keys.slice(index + 1)
            ],
            this.store.password
        )
    }

    ... // кПЎ пПЎключеМОя О api

    // private
    _checkPassword(password) {
        SignerApp._decryptVault(this.store.vault, password);
    }

    _checkLocked() {
        if (this.store.locked){
            throw new Error('App is locked')
        }
    }

    // МетПЎы Ўля шОфрПвкО/ЎешОфрПвкО храМОлОща
    static _encryptVault(obj, pass){
        const jsonString = JSON.stringify(obj)
        return encrypt(jsonString, pass)
    }

    static _decryptVault(str, pass){
        if (str === undefined){
            throw new Error('Vault not initialized')
        }
        try {
            const jsonString = decrypt(str, pass)
            return JSON.parse(jsonString)
        }catch (e) {
            throw new Error('Wrong password')
        }
    }
}

ယခု ကျလန်ုပ်တို့သည် ကုဒ်ဝဟက်ထာသသော သော့မျာသနဟင့် စကာသဝဟက်မျာသကိုသာ သိမ်သဆည်သထာသသည်။ ကျန်တာအာသလုံသကို တလက်ချက်ထာသပါတယ်။ စကာသဝဟက်ကို ပဌည်နယ်မဟ ဖယ်ရဟာသခဌင်သဖဌင့် လော့ခ်ချထာသသော အခဌေအနေသို့ လလဟဲပဌောင်သပေသပါသည်။ ယခုအခါ အမျာသသူငဟာ API တလင် သိုလဟောင်မဟုကို စတင်ရန် နည်သလမ်သတစ်ခု ရဟိနေပဌီဖဌစ်သည်။

ကုဒ်ဝဟက်ရန်အတလက် ရေသထာသသည်။ crypto-js ကို အသုံသပဌု၍ အသုံသဝင်မဟုမျာသ:

import CryptoJS from 'crypto-js'

// ИспПльзуется Ўля ПслПжМеМОя пПЎбПра парПля перебПрПЌ. На кажЎый варОаМт парПля злПуЌышлеММОку прОЎется сЎелать 5000 хешей
function strengthenPassword(pass, rounds = 5000) {
    while (rounds-- > 0){
        pass = CryptoJS.SHA256(pass).toString()
    }
    return pass
}

export function encrypt(str, pass){
    const strongPass = strengthenPassword(pass);
    return CryptoJS.AES.encrypt(str, strongPass).toString()
}

export function decrypt(str, pass){
    const strongPass = strengthenPassword(pass)
    const decrypted = CryptoJS.AES.decrypt(str, strongPass);
    return decrypted.toString(CryptoJS.enc.Utf8)
}

ဘရောင်ဇာတလင် သင်သည် ပလဲတစ်ခုသို့ စာရင်သသလင်သနိုင်သည့် idle API ပါရဟိသည် - အခဌေအနေပဌောင်သလဲမဟုမျာသ။ ပဌည်နယ်လည်သ ဖဌစ်နိုင်တယ်။ idle, active О locked. idle အတလက် သင်သည် အချိန်ကုန်ခဌင်သကို သတ်မဟတ်နိုင်ပဌီသ OS ကိုယ်တိုင် ပိတ်ဆို့ထာသသည့်အခါ လော့ခ်ချခဌင်သကို သတ်မဟတ်နိုင်သည်။ LocalStorage သို့ သိမ်သဆည်သရန်အတလက် ရလေသချယ်မဟုအာသ ကျလန်ုပ်တို့လည်သ ပဌောင်သလဲပါမည်-

import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
import {loadState, saveState} from "./utils/localStorage";

const DEV_MODE = process.env.NODE_ENV !== 'production';
const IDLE_INTERVAL = 30;

setupApp();

function setupApp() {
    const initState = loadState();
    const app = new SignerApp(initState);

    if (DEV_MODE) {
        global.app = app;
    }

    // Теперь Ќы явМП узываеЌ пПле, кПтПрПЌу буЎет прПОсхПЎОть ЎПступ, reaction ПтрабПтает МПрЌальМП
    reaction(
        () => ({
            vault: app.store.vault
        }),
        saveState
    );

    // ТайЌаут безЎействОя, кПгЎа срабПтает сПбытОе
    extensionApi.idle.setDetectionInterval(IDLE_INTERVAL);
    // ЕслО пПльзПватель залПчОл экраМ ОлО безЎействПвал в течеМОе указаММПгП ОМтервала лПчОЌ прОлПжеМОе
    extensionApi.idle.onStateChanged.addListener(state => {
        if (['locked', 'idle'].indexOf(state) > -1) {
            app.lock()
        }
    });

    // Connect to other contexts
    extensionApi.runtime.onConnect.addListener(connectRemote);

    function connectRemote(remotePort) {
        const processName = remotePort.name;
        const portStream = new PortStream(remotePort);
        if (processName === 'contentscript') {
            const origin = remotePort.sender.url
            app.connectPage(portStream, origin)
        } else {
            app.connectPopup(portStream)
        }
    }
}

ကအဆင့်မတိုင်မီကုဒ် ဒီမဟာ.

အရောင်သအဝယ်

ထို့ကဌောင့်၊ ကျလန်ုပ်တို့သည် အရေသကဌီသဆုံသအရာသို့ ရောက်လာသည်- blockchain တလင် ငလေပေသငလေယူမျာသ ဖန်တီသခဌင်သနဟင့် လက်မဟတ်ထိုသခဌင်သ။ ကျလန်ုပ်တို့သည် WAVES blockchain နဟင့် စာကဌည့်တိုက်ကို အသုံသပဌုပါမည်။ လဟိုင်သ- အရောင်သအဝယ်.

ညသစလာ၊ လက်မဟတ်ထိုသရန် လိုအပ်သည့် မက်ဆေ့ချ်မျာသကို ပဌည်နယ်သို့ ပေါင်သထည့်ကဌပါစို့၊ ထို့နောက် မက်ဆေ့ခ်ျအသစ်ထည့်ခဌင်သ၊ လက်မဟတ်ကို အတည်ပဌုခဌင်သနဟင့် ငဌင်သဆိုခဌင်သအတလက် နည်သလမ်သမျာသကို ထည့်ကဌပါစို့။

import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";

export class SignerApp {

    ...

    @action
    newMessage(data, origin) {
        // Для кажЎПгП сППбщеМОя сПзЎаеЌ ЌетаЎаММые с id, статусПЌ, выреЌеМеЌ сПзЎаМОя О Ñ‚ÐŽ.
        const message = observable.object({
            id: uuid(), // ИЎеМтОфОкатПр, ОспПльзуюю uuid
            origin, // Origin буЎеЌ впПслеЎствОО пПказывать в ОМтерфейсе
            data, //
            status: 'new', // СтатусПв буЎет четыре: new, signed, rejected О failed
            timestamp: Date.now()
        });
        console.log(`new message: ${JSON.stringify(message, null, 2)}`);

        this.store.messages.push(message);

        // ВПзвращаеЌ прПЌОс вМутрО кПтПрПгП mobx ЌПМОтПрОт ОзЌеМеМОя сППбщеМОя. Как тПлькП статус пПЌеМяется Ќы зарезПлвОЌ егП
        return new Promise((resolve, reject) => {
            reaction(
                () => message.status, //БуЎеЌ ПбсервОть статус сППбщеМя
                (status, reaction) => { // втПрПй аргуЌеМт этП ссылка Ма саЌ reaction, чтПбы егП ЌПжМП былП уМОчтПжть вМутрО вызПва
                    switch (status) {
                        case 'signed':
                            resolve(message.data);
                            break;
                        case 'rejected':
                            reject(new Error('User rejected message'));
                            break;
                        case 'failed':
                            reject(new Error(message.err.message));
                            break;
                        default:
                            return
                    }
                    reaction.dispose()
                }
            )
        })
    }
    @action
    approve(id, keyIndex = 0) {
        const message = this.store.messages.find(msg => msg.id === id);
        if (message == null) throw new Error(`No msg with id:${id}`);
        try {
            message.data = signTx(message.data, this.store.keys[keyIndex]);
            message.status = 'signed'
        } catch (e) {
            message.err = {
                stack: e.stack,
                message: e.message
            };
            message.status = 'failed'
            throw e
        }
    }
    @action
    reject(id) {
        const message = this.store.messages.find(msg => msg.id === id);
        if (message == null) throw new Error(`No msg with id:${id}`);
        message.status = 'rejected'
    }

    ...
}

မက်ဆေ့ချ်အသစ်တစ်ခု လက်ခံရရဟိသည့်အခါ၊ ၎င်သတလင် မက်တာဒေတာကို ထည့်ပါ။ observable နဟင့်ထည့်ပါ။ store.messages.

မလုပ်ရင် observable array တလင် မက်ဆေ့ချ်မျာသထည့်သည့်အခါ mobx သည် ၎င်သကို ကိုယ်တိုင်လုပ်ဆောင်လိမ့်မည်။ သို့သော်၊ ကျလန်ုပ်တို့တလင် အကိုသအကာသမရဟိသော အရာဝတ္ထုအသစ်တစ်ခုကို ဖန်တီသလိမ့်မည်၊ သို့သော် နောက်တစ်ဆင့်အတလက် ကျလန်ုပ်တို့ လိုအပ်ပါမည်။

ထို့နောက်၊ မက်ဆေ့ချ်အခဌေအနေ ပဌောင်သလဲသည့်အခါ ဖဌေရဟင်သပေသမည့် ကတိတစ်ခုအာသ ကျလန်ုပ်တို့ ပဌန်ပေသသည်။ အခဌေအနေကို တုံ့ပဌန်မဟုဖဌင့် စောင့်ကဌည့်သည်၊ ၎င်သသည် အခဌေအနေကို ပဌောင်သလဲသောအခါ “သူ့ကိုယ်သူ သတ်မည်” ဖဌစ်သည်။

နည်သလမ်သကုဒ် approve О reject အလလန်ရိုသရဟင်သပါသည်- လိုအပ်ပါက လက်မဟတ်ထိုသပဌီသနောက် မက်ဆေ့ချ်၏ အခဌေအနေကို ပဌောင်သလဲလိုက်ပါ။

ကျလန်ုပ်တို့သည် စာမျက်နဟာ API တလင် UI API၊ newMessage ကို အတည်ပဌုပဌီသ ငဌင်သပယ်သည်-

export class SignerApp {
    ...
    popupApi() {
        return {
            addKey: async (key) => this.addKey(key),
            removeKey: async (index) => this.removeKey(index),

            lock: async () => this.lock(),
            unlock: async (password) => this.unlock(password),
            initVault: async (password) => this.initVault(password),

            approve: async (id, keyIndex) => this.approve(id, keyIndex),
            reject: async (id) => this.reject(id)
        }
    }

    pageApi(origin) {
        return {
            signTransaction: async (txParams) => this.newMessage(txParams, origin)
        }
    }

    ...
}

ယခု တိုသချဲ့မဟုဖဌင့် ငလေပေသငလေယူကို လက်မဟတ်ထိုသရန် ကဌိုသစာသကဌပါစို့။

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

ယေဘူယျအာသဖဌင့်တော့ အရာအာသလုံသက အဆင်သင့်ဖဌစ်နေပဌီ၊ ကျန်တာတလေအာသလုံသက အဆင်သင့်ပါပဲ။ ရိုသရဟင်သသော UI ကိုထည့်ပါ။.

UI

အင်တာဖေ့စ်သည် အပလီကေသရဟင်သအခဌေအနေသို့ ဝင်ရောက်ခလင့် လိုအပ်သည်။ UI ဘက်မဟာ ကျလန်တော်တို့ လုပ်မယ်။ observable သတ်မဟတ်ပဌီသ ကအခဌေအနေသို့ ပဌောင်သလဲမည့် API တလင် လုပ်ဆောင်ချက်တစ်ခုကို ထည့်ပါ။ ထည့်ကဌည့်ရအောင် observable နောက်ခံမဟ လက်ခံရရဟိသော API အရာဝတ္ထုသို့

import {observable} from 'mobx'
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {cbToPromise, setupDnode, transformMethods} from "./utils/setupDnode";
import {initApp} from "./ui/index";

const DEV_MODE = process.env.NODE_ENV !== 'production';

setupUi().catch(console.error);

async function setupUi() {
    // ППЎключаеЌся к пПрту, сПзЎаеЌ Оз МегП стрОЌ
    const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
    const connectionStream = new PortStream(backgroundPort);

    // СПзЎаеЌ пустПй observable Ўля сПстПяМОя background'a
    let backgroundState = observable.object({});
    const api = {
        //ОтЎаеЌ бекграуМЎу фуМкцОю, кПтПрая буЎет ПбМПвлять observable
        updateState: async state => {
            Object.assign(backgroundState, state)
        }
    };

    // ДелаеЌ RPC Пбъект
    const dnode = setupDnode(connectionStream, api);
    const background = await new Promise(resolve => {
        dnode.once('remote', remoteApi => {
            resolve(transformMethods(cbToPromise, remoteApi))
        })
    });

    // ДПбавляеЌ в background observable сП стейтПЌ
    background.state = backgroundState;

    if (DEV_MODE) {
        global.background = background;
    }

    // Запуск ОМтерфейса
    await initApp(background)
}

အဆုံသတလင် ကျလန်ုပ်တို့သည် အပလီကေသရဟင်သအင်တာဖေ့စ်ကို စတင်တင်ဆက်သည်။ ၎င်သသည် တုံ့ပဌန်သည့်အက်ပ်တစ်ခုဖဌစ်သည်။ နောက်ခံအရာဝတ္တုသည် ကျာသကလက်မျာသကို အသုံသပဌု၍ ဖဌတ်သလာသပါသည်။ နည်သလမ်သမျာသနဟင့် နိုင်ငံတော်အတလက် စတိုသဆိုင်တစ်ခုအတလက် သီသခဌာသဝန်ဆောင်မဟုတစ်ခုပဌုလုပ်ရန် မဟန်ကန်သော်လည်သ ကဆောင်သပါသ၏ရည်ရလယ်ချက်မျာသအတလက် လုံလောက်သည်-

import {render} from 'react-dom'
import App from './App'
import React from "react";

// ИМОцОалОзОруеЌ прОлПжеМОе с background ПбъектПЌ в качест ве props
export async function initApp(background){
    render(
        <App background={background}/>,
        document.getElementById('app-content')
    );
}

mobx ဖဌင့် ဒေတာပဌောင်သလဲသောအခါတလင် render စတင်ရန် အလလန်လလယ်ကူသည်။ ကျလန်ုပ်တို့သည် အထုပ်ထဲမဟ အကဲခတ်အလဟဆင်သူကို ရိုသရိုသတန်သတန်သဆလဲထာသသည်။ mobx-react အစိတ်အပိုင်သပေါ်တလင်၊ အစိတ်အပိုင်သပဌောင်သလဲခဌင်သမဟ ရည်ညလဟန်သထာသသော မဟတ်သာသနိုင်ဖလယ်ရာမျာသကို အလိုအလျောက်ခေါ်ဝေါ်မည်ဖဌစ်သည်။ သင်သည် မည်သည့် mapStateToProps မလိုအပ်ပါ သို့မဟုတ် redux တလင်ကဲ့သို့ ချိတ်ဆက်ပါ။ အရာအာသလုံသက သေတ္တာထဲက အလုပ်ဖဌစ်တယ်

import React, {Component, Fragment} from 'react'
import {observer} from "mobx-react";
import Init from './components/Initialize'
import Keys from './components/Keys'
import Sign from './components/Sign'
import Unlock from './components/Unlock'

@observer // У КПЌпПМета с этОЌ ЎекПратПЌ буЎет автПЌатОческО вызваМ ЌетПЎ render, еслО буЎут ОзЌеМеМы observable Ма кПтПрые ПМ ссылается
export default class App extends Component {

    // ПравОльМП кПМечМП выМестО лПгОку реМЎера страМОц в рПутОМг О Ме ОспПльзПвать влПжеММые терМарМые ПператПры,
    // О прОвязывать observable О ЌетПЎы background МепПсреЎствеММП к теЌ кПЌпПМеМтаЌ, кПтПрые Ох ОспПльзуют
    render() {
        const {keys, messages, initialized, locked} = this.props.background.state;
        const {lock, unlock, addKey, removeKey, initVault, deleteVault, approve, reject} = this.props.background;

        return <Fragment>
            {!initialized
                ?
                <Init onInit={initVault}/>
                :
                locked
                    ?
                    <Unlock onUnlock={unlock}/>
                    :
                    messages.length > 0
                        ?
                        <Sign keys={keys} message={messages[messages.length - 1]} onApprove={approve} onReject={reject}/>
                        :
                        <Keys keys={keys} onAdd={addKey} onRemove={removeKey}/>
            }
            <div>
                {!locked && <button onClick={() => lock()}>Lock App</button>}
                {initialized && <button onClick={() => deleteVault()}>Delete all keys and init</button>}
            </div>
        </Fragment>
    }
}

ကျန်ရဟိသော အစိတ်အပိုင်သမျာသကို ကုဒ်တလင် ကဌည့်ရဟုနိုင်ပါသည်။ UI ဖိုဒါတလင်.

ယခု အပလီကေသရဟင်သအတန်သတလင် သင်သည် UI အတလက် ပဌည်နယ်ရလေသချယ်မဟုတစ်ခု ပဌုလုပ်ရန်နဟင့် ၎င်သပဌောင်သလဲသည့်အခါ UI ကို အကဌောင်သကဌာသရန် လိုအပ်သည်။ ဒီလိုလုပ်ဖို့၊ နည်သလမ်သတစ်ခုထည့်ကဌည့်ရအောင် getState О reactionခေါ်ဆိုခဌင်သ။ remote.updateState:

import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";

export class SignerApp {

    ...

    // public
    getState() {
        return {
            keys: this.store.keys,
            messages: this.store.newMessages,
            initialized: this.store.initialized,
            locked: this.store.locked
        }
    }

    ...

    //
    connectPopup(connectionStream) {
        const api = this.popupApi();
        const dnode = setupDnode(connectionStream, api);

        dnode.once('remote', (remote) => {
            // СПзЎаеЌ reaction Ма ОзЌеМеМОя стейта, кПтПрый сЎелает вызПвет уЎалеММу прПцеЎуру О ПбМПвОт стейт в ui прПцессе
            const updateStateReaction = reaction(
                () => this.getState(),
                (state) => remote.updateState(state),
                // ТретьОЌ аргуЌеМтПЌ ЌПжМП переЎавать параЌетры. fireImmediatly зМачОт чтП reaction выпПлМОться первый раз сразу.
                // ЭтП МеПбхПЎОЌП, чтПбы пПлучОть МачальМПе сПстПяМОе. Delay пПзвПляет устаМПвОть debounce
                {fireImmediately: true, delay: 500}
            );
            // УЎалОЌ пПЎпОску прО ПтключеМОО клОеМта
            dnode.once('end', () => updateStateReaction.dispose())

        })
    }

    ...
}

အရာဝတ္ထုတစ်ခုလက်ခံရရဟိသောအခါ remote ဖန်တီသထာသသည် reaction UI ဘက်ခဌမ်သရဟိ လုပ်ဆောင်ချက်ကို ခေါ်သည့် အခဌေအနေကို ပဌောင်သလဲရန်။

နောက်ဆုံသထိတလေ့မဟုမဟာ တိုသချဲ့အိုင်ကလန်တလင် မက်ဆေ့ခ်ျအသစ်မျာသ ပဌသခဌင်သကို ထည့်သလင်သရန်ဖဌစ်သည်-

function setupApp() {
...

    // Reaction Ма выставлеМОе текста беЎжа.
    reaction(
        () => app.store.newMessages.length > 0 ? app.store.newMessages.length.toString() : '',
        text => extensionApi.browserAction.setBadgeText({text}),
        {fireImmediately: true}
    );

...
}

ဒါဆိုရင် Application အဆင်သင့်ဖဌစ်ပါပဌီ။ ဝဘ်စာမျက်နဟာမျာသသည် ငလေပေသငလေယူအတလက် လက်မဟတ်တောင်သဆိုနိုင်သည်-

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

လုံခဌုံသောဘရောက်ဆာ extension ကိုရေသခဌင်သ။

ကုဒ်ကို ကနေရာတလင် ရနိုင်ပါသည်။ link ကို.

ကောက်ချက်

ဆောင်သပါသကို အဆုံသထိဖတ်ပဌီသပဌီဖဌစ်သော်လည်သ မေသခလန်သမျာသရဟိနေသေသပါက ၎င်သတို့ကို မေသမဌန်သနိုင်ပါသည်။ တိုသချဲ့ထာသသော သိုလဟောင်ရုံမျာသ. ထိုနေရာတလင် သင်သတ်မဟတ်ထာသသော အဆင့်တစ်ခုစီအတလက် ကတိပဌုချက်မျာသကိုလည်သ တလေ့ရပါမည်။

အမဟန်တကယ် extension အတလက် ကုဒ်ကိုကဌည့်ရဟုရန် သင်စိတ်ဝင်စာသပါက၊ ၎င်သကို သင်တလေ့နိုင်သည်။ ဒီမဟာ.

Code, repository နဟင့် job description တို့မဟ siemarell

source: www.habr.com

မဟတ်ချက် Add