অ্যাপ ইঞ্জিন ব্লবস্টোর কীভাবে ব্যবহার করবেন (মডিউল 15)

১. সংক্ষিপ্ত বিবরণ

সার্ভারলেস মাইগ্রেশন স্টেশন সিরিজের কোডল্যাব (স্ব-গতিতে শেখার উপযোগী টিউটোরিয়াল) এবং সম্পর্কিত ভিডিওগুলোর লক্ষ্য হলো গুগল ক্লাউড সার্ভারলেস ডেভেলপারদের এক বা একাধিক মাইগ্রেশনের মাধ্যমে তাদের অ্যাপ্লিকেশনগুলোকে আধুনিক করে তুলতে সাহায্য করা, যার মূল উদ্দেশ্য হলো পুরোনো সার্ভিসগুলো থেকে সরে আসা। এটি আপনার অ্যাপগুলোকে আরও সহজে বহনযোগ্য করে তোলে এবং আপনাকে আরও বেশি বিকল্প ও নমনীয়তা দেয়, যার ফলে আপনি আরও বিস্তৃত পরিসরের ক্লাউড প্রোডাক্টের সাথে ইন্টিগ্রেট করতে ও সেগুলো ব্যবহার করতে পারেন এবং নতুন ল্যাঙ্গুয়েজ রিলিজে আরও সহজে আপগ্রেড করতে পারেন। যদিও প্রাথমিকভাবে এই সিরিজটি ক্লাউডের একেবারে প্রথম দিকের ব্যবহারকারী, অর্থাৎ অ্যাপ ইঞ্জিন (স্ট্যান্ডার্ড এনভায়রনমেন্ট) ডেভেলপারদের উপর দৃষ্টি নিবদ্ধ করে তৈরি, তবে এর পরিধি এতটাই বিস্তৃত যে এটি ক্লাউড ফাংশনস এবং ক্লাউড রান- এর মতো অন্যান্য সার্ভারলেস প্ল্যাটফর্ম বা প্রযোজ্য ক্ষেত্রে অন্য প্ল্যাটফর্মগুলোকেও অন্তর্ভুক্ত করতে পারে।

এই মডিউল ১৫ কোডল্যাবে ব্যাখ্যা করা হয়েছে, কীভাবে মডিউল ০-এর স্যাম্পল অ্যাপটিতে অ্যাপ ইঞ্জিন blobstore ব্যবহার যুক্ত করতে হয়। এরপর মডিউল ১৬-তে আপনি সেই ব্যবহারটি ক্লাউড স্টোরেজে মাইগ্রেট করার জন্য প্রস্তুত হয়ে যাবেন।

আপনি শিখবেন কিভাবে

  • অ্যাপ ইঞ্জিন ব্লবস্টোর এপিআই/লাইব্রেরির ব্যবহার যোগ করুন
  • blobstore পরিষেবাতে ব্যবহারকারীর আপলোডগুলি সংরক্ষণ করুন।
  • ক্লাউড স্টোরেজে স্থানান্তরের পরবর্তী পদক্ষেপের জন্য প্রস্তুতি নিন।

আপনার যা যা লাগবে

জরিপ

আপনি এই টিউটোরিয়ালটি কীভাবে ব্যবহার করবেন?

শুধু পুরোটা পড়ুন এটি পড়ুন এবং অনুশীলনগুলো সম্পূর্ণ করুন।

পাইথন নিয়ে আপনার অভিজ্ঞতাকে আপনি কীভাবে মূল্যায়ন করবেন?

শিক্ষানবিশ মধ্যবর্তী দক্ষ

গুগল ক্লাউড পরিষেবা ব্যবহারের অভিজ্ঞতাকে আপনি কীভাবে মূল্যায়ন করবেন?

শিক্ষানবিশ মধ্যবর্তী দক্ষ

২. পটভূমি

অ্যাপ ইঞ্জিন ব্লবস্টোর এপিআই থেকে মাইগ্রেট করার জন্য, মডিউল ০-এর বিদ্যমান বেসলাইন অ্যাপ ইঞ্জিন ndb অ্যাপে এর ব্যবহার যুক্ত করুন। নমুনা অ্যাপটি ব্যবহারকারীকে তার সাম্প্রতিকতম দশটি ভিজিট প্রদর্শন করে। আমরা অ্যাপটিকে এমনভাবে পরিবর্তন করছি যাতে এটি ব্যবহারকারীকে তার "ভিজিট"-এর সাথে সম্পর্কিত একটি আর্টিফ্যাক্ট (একটি ফাইল) আপলোড করার জন্য অনুরোধ করে। যদি ব্যবহারকারী তা করতে না চান, তবে একটি "স্কিপ" অপশন রয়েছে। ব্যবহারকারীর সিদ্ধান্ত যাই হোক না কেন, পরবর্তী পৃষ্ঠাটি মডিউল ০-এর অ্যাপের (এবং এই সিরিজের অন্যান্য অনেক মডিউলের) মতোই একই আউটপুট রেন্ডার করবে। এই অ্যাপ ইঞ্জিন blobstore ইন্টিগ্রেশনটি বাস্তবায়িত হয়ে গেলে, আমরা পরবর্তী (মডিউল ১৬) কোডল্যাবে এটিকে ক্লাউড স্টোরেজে মাইগ্রেট করতে পারব।

অ্যাপ ইঞ্জিন জ্যাঙ্গো এবং জিনজা২ টেমপ্লেটিং সিস্টেমে অ্যাক্সেস প্রদান করে, এবং এই উদাহরণটিকে যা আলাদা করে তোলে (ব্লবস্টোর অ্যাক্সেস যোগ করা ছাড়াও) তা হলো, এটি মডিউল ০-তে জ্যাঙ্গো ব্যবহার করা থেকে এখানে মডিউল ১৫-তে জিনজা২ ব্যবহারে পরিবর্তিত হয়েছে। অ্যাপ ইঞ্জিন অ্যাপগুলোকে আধুনিক করার একটি গুরুত্বপূর্ণ পদক্ষেপ হলো ওয়েব ফ্রেমওয়ার্কগুলোকে webapp2 থেকে ফ্লাস্কে মাইগ্রেট করা। ফ্লাস্ক তার ডিফল্ট টেমপ্লেটিং সিস্টেম হিসেবে জিনজা২ ব্যবহার করে, তাই আমরা ব্লবস্টোর অ্যাক্সেসের জন্য webapp2 থেকে জিনজা২ ইমপ্লিমেন্ট করার মাধ্যমে সেই দিকে এগোতে শুরু করি। যেহেতু ফ্লাস্ক ডিফল্টভাবে জিনজা২ ব্যবহার করে, এর মানে হলো মডিউল ১৬-তে টেমপ্লেটে আর কোনো পরিবর্তনের প্রয়োজন হবে না।

৩. প্রস্তুতি/পূর্বপ্রস্তুতি

টিউটোরিয়ালের মূল অংশে যাওয়ার আগে, আপনার প্রজেক্ট সেট আপ করুন, কোড সংগ্রহ করুন এবং কার্যকরী কোড দিয়ে কাজ শুরু করার জন্য বেসলাইন অ্যাপটি ডিপ্লয় করুন।

১. প্রকল্প স্থাপন করুন

আপনি যদি ইতিমধ্যেই মডিউল ০ অ্যাপটি ডেপ্লয় করে থাকেন, তাহলে আমরা একই প্রজেক্ট (এবং কোড) পুনরায় ব্যবহার করার পরামর্শ দিই। বিকল্পভাবে, আপনি একটি সম্পূর্ণ নতুন প্রজেক্ট তৈরি করতে পারেন অথবা অন্য কোনো বিদ্যমান প্রজেক্ট পুনরায় ব্যবহার করতে পারেন। নিশ্চিত করুন যে প্রজেক্টটিতে একটি সক্রিয় বিলিং অ্যাকাউন্ট আছে এবং অ্যাপ ইঞ্জিন চালু করা আছে।

২. বেসলাইন নমুনা অ্যাপটি নিন

এই কোডল্যাবটির একটি পূর্বশর্ত হলো একটি কার্যকর মডিউল ০ স্যাম্পল অ্যাপ থাকা। যদি আপনার কাছে এটি না থাকে, তবে আপনি মডিউল ০-এর "START" ফোল্ডার থেকে এটি সংগ্রহ করতে পারেন (লিঙ্ক নিচে দেওয়া আছে)। এই কোডল্যাবটি আপনাকে প্রতিটি ধাপের মধ্য দিয়ে নিয়ে যাবে এবং শেষে এমন কোড থাকবে যা মডিউল ১৫-এর "FINISH" ফোল্ডারের কোডের অনুরূপ।

মডিউল ০-এর প্রারম্ভিক ফাইলগুলোর ডিরেক্টরিটি দেখতে এইরকম হবে:

$ ls
README.md               index.html
app.yaml                main.py

৩. বেসলাইন অ্যাপ (পুনরায়) স্থাপন করুন

এখন আপনার বাকি প্রস্তুতিমূলক ধাপগুলো সম্পন্ন করতে হবে:

  1. gcloud কমান্ড-লাইন টুলটির সাথে পুনরায় পরিচিত হয়ে নিন।
  2. gcloud app deploy ব্যবহার করে নমুনা অ্যাপটি পুনরায় ডিপ্লয় করুন।
  3. অ্যাপটি অ্যাপ ইঞ্জিনে কোনো সমস্যা ছাড়াই চলে কিনা তা নিশ্চিত করুন।

একবার আপনি সফলভাবে ওই ধাপগুলো সম্পন্ন করে আপনার ওয়েব অ্যাপটিকে কাজ করতে দেখলে (নিচের মতো আউটপুট সহ), আপনি আপনার অ্যাপে ক্যাশিং ব্যবহার যোগ করার জন্য প্রস্তুত।

a7a9d2b80d706a2b.png

৪. কনফিগারেশন ফাইল আপডেট করুন

app.yaml

অ্যাপ্লিকেশন কনফিগারেশনে কোনো বড় ধরনের পরিবর্তন আনা হচ্ছে না, তবে পূর্বে যেমন উল্লেখ করা হয়েছে, আমরা ডিফল্ট হিসেবে থাকা জ্যাঙ্গো টেমপ্লেটিং (Django templating) থেকে জিনজা২ (Jinja2)-এ স্থানান্তরিত হচ্ছি। তাই, এই পরিবর্তনটি করার জন্য ব্যবহারকারীদের অ্যাপ ইঞ্জিন (App Engine) সার্ভারে উপলব্ধ জিনজা২-এর সর্বশেষ সংস্করণটি নির্দিষ্ট করতে হবে এবং এটি করার জন্য app.yaml ফাইলের বিল্ট-ইন থার্ড-পার্টি লাইব্রেরি (built-in 3rd-party libraries) বিভাগে ফাইলটি যুক্ত করতে হবে।

পূর্বে:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

আপনার app.yaml ফাইলটি সম্পাদনা করে এখানে দেখানো ছবির মতো একটি নতুন libraries সেকশন যোগ করুন:

পরে:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: jinja2
  version: latest

অন্য কোনো কনফিগারেশন ফাইল আপডেট করার প্রয়োজন নেই, তাই চলুন অ্যাপ্লিকেশন ফাইলগুলোর দিকে এগিয়ে যাই।

৫. অ্যাপ্লিকেশন ফাইলগুলি পরিবর্তন করুন

ইমপোর্ট এবং জিনজা২ সমর্থন

main.py এর প্রথম ধাপের পরিবর্তনগুলোর মধ্যে রয়েছে Blobstore API-এর ব্যবহার যুক্ত করা এবং Django টেমপ্লেটিং-এর পরিবর্তে Jinja2 ব্যবহার করা। নিচে যা যা পরিবর্তন করা হচ্ছে তা দেওয়া হলো:

  1. os মডিউলের উদ্দেশ্য হলো একটি Django টেমপ্লেটের জন্য একটি ফাইল পাথনেম তৈরি করা। যেহেতু আমরা Jinja2-তে স্থানান্তরিত হচ্ছি যেখানে এই কাজটি সম্পন্ন হয়, তাই os এর ব্যবহার এবং Django টেমপ্লেট রেন্ডারার google.appengine.ext.webapp.template এর আর প্রয়োজন নেই, ফলে এগুলো সরিয়ে ফেলা হচ্ছে।
  2. ব্লবস্টোর এপিআই ইম্পোর্ট করুন: google.appengine.ext.blobstore
  3. মূল webapp ফ্রেমওয়ার্কে থাকা ব্লবস্টোর হ্যান্ডলারগুলো ইম্পোর্ট করুন—এগুলো webapp2 এ পাওয়া যায় না: google.appengine.ext.webapp.blobstore_handlers
  4. webapp2_extras প্যাকেজ থেকে Jinja2 সাপোর্ট ইম্পোর্ট করুন

পূর্বে:

import os
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

main.py ফাইলের বর্তমান ইম্পোর্ট সেকশনটি নিচের কোড স্নিপেট দিয়ে প্রতিস্থাপন করে উপরের তালিকায় থাকা পরিবর্তনগুলো প্রয়োগ করুন।

পরে:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

ইম্পোর্টগুলোর পরে, webapp2_extras ডক্স- এ সংজ্ঞায়িত Jinja2-এর ব্যবহার সমর্থন করার জন্য কিছু বয়লারপ্লেট কোড যোগ করুন। নিম্নলিখিত কোড স্নিপেটটি স্ট্যান্ডার্ড webapp2 রিকোয়েস্ট হ্যান্ডলার ক্লাসকে Jinja2 কার্যকারিতা দিয়ে র‍্যাপ করে, তাই এই কোড ব্লকটি main.py তে ইম্পোর্টগুলোর ঠিক পরেই যোগ করুন:

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

ব্লবস্টোর সমর্থন যোগ করুন

এই সিরিজের অন্যান্য মাইগ্রেশনগুলোর মতো নয়, যেখানে আমরা ইউএক্স-এ (UX) (খুব বেশি) পরিবর্তন না করে স্যাম্পল অ্যাপের কার্যকারিতা বা আউটপুট হুবহু (বা প্রায় একই) রাখি, এই উদাহরণটি প্রচলিত নিয়ম থেকে আরও আমূল ভিন্ন। নতুন ভিজিট রেজিস্টার করে তারপর সাম্প্রতিকতম দশটি দেখানোর পরিবর্তে, আমরা অ্যাপটিকে এমনভাবে আপডেট করছি যাতে ব্যবহারকারীর ভিজিট রেজিস্টার করার জন্য একটি ফাইল আর্টিফ্যাক্ট চাওয়া হয়। এরপর ব্যবহারকারীরা হয় সংশ্লিষ্ট ফাইলটি আপলোড করতে পারেন অথবা কিছুই আপলোড না করার জন্য "স্কিপ" নির্বাচন করতে পারেন। এই ধাপটি সম্পন্ন হলে, "সাম্প্রতিকতম ভিজিট" পৃষ্ঠাটি প্রদর্শিত হয়।

এই পরিবর্তনের ফলে আমাদের অ্যাপটি ব্লবস্টোর পরিষেবা ব্যবহার করে সাম্প্রতিকতম ভিজিট পেজে সেই ছবি বা অন্য ধরনের ফাইল সংরক্ষণ (এবং সম্ভবত পরে রেন্ডার) করতে পারবে।

ডেটা মডেল আপডেট করুন এবং এর ব্যবহার বাস্তবায়ন করুন

আমরা আরও ডেটা সংরক্ষণ করছি, বিশেষ করে ডেটা মডেলটি আপডেট করে Blobstore-এ আপলোড করা ফাইলের আইডি (যাকে " BlobKey " বলা হয়) সংরক্ষণ করছি এবং store_visit() এ সেটি সেভ করার জন্য একটি রেফারেন্স যোগ করছি। যেহেতু এই অতিরিক্ত ডেটা কোয়েরি করার সময় অন্য সবকিছুর সাথে ফেরত আসে, তাই fetch_visits() অপরিবর্তিত থাকছে।

এখানে file_blob (একটি ndb.BlobKeyProperty সমন্বিত এই আপডেটগুলোর আগের ও পরের অবস্থা দেখানো হলো:

পূর্বে:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

পরে:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent),
            file_blob=upload_key).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

এ পর্যন্ত যে পরিবর্তনগুলো করা হয়েছে তার একটি চিত্ররূপ নিচে দেওয়া হলো:

2270783776759f7f.png

ফাইল আপলোড সমর্থন করুন

কার্যকারিতার ক্ষেত্রে সবচেয়ে গুরুত্বপূর্ণ পরিবর্তন হলো ফাইল আপলোড সমর্থন করা, যার মধ্যে ব্যবহারকারীর কাছে ফাইলের জন্য অনুরোধ করা, 'স্কিপ' বৈশিষ্ট্য সমর্থন করা, বা কোনো ভিজিটের সাথে সম্পর্কিত একটি ফাইল প্রদর্শন করা অন্তর্ভুক্ত। এই সবকিছুই একটি সামগ্রিক চিত্রের অংশ। ফাইল আপলোড সমর্থন করার জন্য নিম্নলিখিত পরিবর্তনগুলো প্রয়োজন:

  1. প্রধান হ্যান্ডলারের GET অনুরোধটি এখন আর প্রদর্শনের জন্য সাম্প্রতিকতম ভিজিটগুলো নিয়ে আসে না। এর পরিবর্তে, এটি ব্যবহারকারীকে একটি আপলোডের জন্য অনুরোধ করে।
  2. যখন কোনো ব্যবহারকারী আপলোড করার জন্য একটি ফাইল জমা দেন বা সেই প্রক্রিয়াটি এড়িয়ে যান, তখন ফর্ম থেকে একটি POST মাধ্যমে নিয়ন্ত্রণ নতুন UploadHandler কাছে চলে যায়, যা google.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler থেকে উদ্ভূত।
  3. UploadHandler এর POST মেথডটি আপলোড সম্পন্ন করে, ভিজিটটি রেজিস্টার করার জন্য store_visit() কল করে, এবং ব্যবহারকারীকে "/"-এ ফেরত পাঠানোর জন্য একটি HTTP 307 রিডাইরেক্ট ট্রিগার করে, যেখানে...
  4. প্রধান হ্যান্ডলারের POST মেথডটি ( fetch_visits() এর মাধ্যমে) সাম্প্রতিকতম ভিজিটগুলো কোয়েরি করে এবং প্রদর্শন করে। যদি ব্যবহারকারী 'skip' নির্বাচন করেন, তাহলে কোনো ফাইল আপলোড হয় না, কিন্তু ভিজিটটি নিবন্ধিত হয়ে যায় এবং একই রিডাইরেক্ট সম্পন্ন হয়।
  5. সাম্প্রতিক ভিজিটগুলো প্রদর্শনে ব্যবহারকারীর জন্য একটি নতুন ফিল্ড যুক্ত করা হয়েছে, যেখানে ফাইল আপলোড করার সুযোগ থাকলে একটি হাইপারলিঙ্কযুক্ত 'ভিউ' এবং অন্যথায় 'নন' দেখা যাবে। এই পরিবর্তনগুলো এইচটিএমএল টেমপ্লেটে বাস্তবায়ন করা হয়েছে এবং এর সাথে একটি আপলোড ফর্মও যুক্ত করা হয়েছে (এ বিষয়ে শীঘ্রই আরও বিস্তারিত জানানো হবে)।
  6. যদি কোনো ব্যবহারকারী আপলোড করা ভিডিও সহ কোনো ভিজিটের 'ভিউ' লিঙ্কে ক্লিক করেন, তবে এটি google.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler থেকে উদ্ভূত একটি নতুন ViewBlobHandler এ একটি GET রিকোয়েস্ট পাঠায়। এই রিকোয়েস্টটি ফাইলটিকে, যদি সেটি একটি ছবি হয়, রেন্ডার করে (সমর্থিত হলে ব্রাউজারে), তা না হলে ডাউনলোডের জন্য অনুরোধ জানায়, অথবা ফাইলটি খুঁজে না পেলে একটি HTTP 404 এরর রিটার্ন করে।
  7. নতুন একজোড়া হ্যান্ডলার ক্লাস এবং সেগুলোতে ট্র্যাফিক পাঠানোর জন্য নতুন একজোড়া রাউটের পাশাপাশি, উপরে বর্ণিত ৩০৭ রিডাইরেক্টটি গ্রহণ করার জন্য মূল হ্যান্ডলারটির একটি নতুন POST মেথড প্রয়োজন।

এই আপডেটগুলির আগে, মডিউল ০ অ্যাপটিতে শুধুমাত্র একটি GET মেথড ও একটিমাত্র রাউট সহ একটি প্রধান হ্যান্ডলার ছিল:

পূর্বে:

class MainHandler(webapp2.RequestHandler):
    'main application (GET) handler'
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10)
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

এই আপডেটগুলো প্রয়োগ করার পর, এখন তিনটি হ্যান্ডলার রয়েছে: ১) একটি POST মেথডসহ আপলোড হ্যান্ডলার, ২) একটি GET মেথডসহ "ভিউ ব্লব" ডাউনলোড হ্যান্ডলার, এবং ৩) GETPOST মেথডসহ মূল হ্যান্ডলার। এই পরিবর্তনগুলো করুন যাতে আপনার অ্যাপের বাকি অংশ এখন নীচের মতো দেখায়।

পরে:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

আমরা এইমাত্র যে কোডটি যোগ করেছি তাতে বেশ কয়েকটি গুরুত্বপূর্ণ কল রয়েছে:

  • MainHandler.get এর মধ্যে blobstore.create_upload_url কে কল করা হয়। এই কলটি সেই URL তৈরি করে যেখানে ফর্মটি POST এবং ফাইলটিকে Blobstore-এ পাঠানোর জন্য আপলোড হ্যান্ডলারকে কল করে।
  • UploadHandler.post এর মধ্যে blobstore_handlers.BlobstoreUploadHandler.get_uploads কে কল করা হয়। এটাই সেই আসল জাদু যা ফাইলটিকে Blobstore-এ রাখে এবং সেই ফাইলের জন্য একটি অনন্য ও স্থায়ী আইডি, অর্থাৎ তার BlobKey , ফেরত দেয়।
  • ViewBlobHandler.get এ, কোনো ফাইলের BlobKey সহ blobstore_handlers.BlobstoreDownloadHandler.send কল করলে ফাইলটি ফেচ করা হয় এবং তা অন্তিম ব্যবহারকারীর ব্রাউজারে ফরোয়ার্ড করা হয়।

এই কলগুলোই অ্যাপে যোগ করা ফিচারগুলো অ্যাক্সেস করার মূল অংশ। main.py তে করা এই দ্বিতীয় এবং চূড়ান্ত পরিবর্তনগুলোর একটি সচিত্র উপস্থাপনা নিচে দেওয়া হলো:

da2960525ac1b90d.png

এইচটিএমএল টেমপ্লেট আপডেট করুন

মূল অ্যাপ্লিকেশনের কিছু আপডেট অ্যাপটির ইউজার ইন্টারফেস (UI)-কে প্রভাবিত করে, তাই ওয়েব টেমপ্লেটেও অনুরূপ পরিবর্তন প্রয়োজন, প্রকৃতপক্ষে দুটি পরিবর্তন:

  1. একটি ফাইল আপলোড ফর্ম প্রয়োজন, যেখানে তিনটি ইনপুট উপাদান থাকবে: একটি ফাইল এবং যথাক্রমে ফাইল আপলোড ও স্কিপ করার জন্য একজোড়া সাবমিট বাটন।
  2. যেসব ভিজিটের সাথে ফাইল আপলোড করা হয়েছে, সেগুলোর জন্য একটি 'ভিউ' লিঙ্ক এবং অন্যথায় 'নন' লিঙ্ক যোগ করে সাম্প্রতিকতম ভিজিট আউটপুট আপডেট করুন।

পূর্বে:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

</body>
</html>

আপডেট করা টেমপ্লেটটি তৈরি করতে উপরের তালিকায় থাকা পরিবর্তনগুলো বাস্তবায়ন করুন:

পরে:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
{% if upload_url %}

<h3>Welcome... upload a file? (optional)</h3>
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
    <input type="file" name="file"><p></p>
    <input type="submit"> <input type="submit" value="Skip">
</form>

{% else %}

<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }}
    <i><code>
    {% if visit.file_blob %}
        (<a href="/view/{{ visit.file_blob }}" target="_blank">view</a>)
    {% else %}
        (none)
    {% endif %}
    </code></i>
    from {{ visit.visitor }}
</li>
{% endfor %}
</ul>

{% endif %}

</body>
</html>

এই চিত্রটি index.html এ প্রয়োজনীয় আপডেটগুলো তুলে ধরেছে:

8583e975f25aa9e7.png

শেষ একটি পরিবর্তন হলো, জিনজা২ (Jinja2) তার টেমপ্লেটগুলো একটি templates ফোল্ডারে রাখতে পছন্দ করে, তাই সেই ফোল্ডারটি তৈরি করুন এবং index.html তার ভেতরে সরিয়ে নিন। এই শেষ পদক্ষেপটির মাধ্যমে, মডিউল ০ স্যাম্পল অ্যাপে ব্লবস্টোর (Blobstore) ব্যবহারের জন্য প্রয়োজনীয় সমস্ত পরিবর্তন আপনার সম্পন্ন হলো।

(ঐচ্ছিক) ক্লাউড স্টোরেজ "উন্নয়ন"

ব্লবস্টোর স্টোরেজ অবশেষে ক্লাউড স্টোরেজে রূপান্তরিত হয়েছে। এর মানে হলো, ব্লবস্টোরে আপলোড করা ফাইলগুলো ক্লাউড কনসোলে, বিশেষ করে ক্লাউড স্টোরেজ ব্রাউজারে দেখা যায়। প্রশ্ন হলো, কোথায়? উত্তর হলো, আপনার অ্যাপ ইঞ্জিন অ্যাপের ডিফল্ট ক্লাউড স্টোরেজ বাকেটে। এর নামটি হলো আপনার অ্যাপ ইঞ্জিন অ্যাপের সম্পূর্ণ ডোমেইন নেম, অর্থাৎ PROJECT_ID .appspot.com । এটি খুবই সুবিধাজনক, কারণ সব প্রজেক্ট আইডিই তো অনন্য, তাই না?

স্যাম্পল অ্যাপ্লিকেশনটিতে করা আপডেটগুলো আপলোড করা ফাইলগুলোকে ওই বাকেটে রাখে, কিন্তু ডেভেলপারদের আরও নির্দিষ্ট একটি অবস্থান বেছে নেওয়ার সুযোগ রয়েছে। ডিফল্ট বাকেটটি google.appengine.api.app_identity.get_default_gcs_bucket_name() -এর মাধ্যমে প্রোগ্রাম্যাটিকভাবে অ্যাক্সেস করা যায়। এই ভ্যালুটি অ্যাক্সেস করতে চাইলে, যেমন আপলোড করা ফাইলগুলোকে সাজানোর জন্য প্রিফিক্স হিসেবে ব্যবহার করতে চাইলে, একটি নতুন ইম্পোর্টের প্রয়োজন হবে। উদাহরণস্বরূপ, ফাইলের ধরন অনুযায়ী সাজানো:

f61f7a23a1518705.png

উদাহরণস্বরূপ, ছবির জন্য এরকম কিছু প্রয়োগ করতে হলে, আপনার এই ধরনের কোডের সাথে এমন কিছু কোড থাকবে যা ফাইলের ধরন যাচাই করে কাঙ্ক্ষিত বাকেট নামটি বেছে নেবে:

ROOT_BUCKET = app_identity.get_default_gcs_bucket_name()
IMAGE_BUCKET = '%s/%s' % (ROOT_BUCKET, 'images')

ছবির ধরন নিশ্চিত করতে আপনি পাইথন স্ট্যান্ডার্ড লাইব্রেরির imghdr মডিউলের মতো কোনো টুল ব্যবহার করে আপলোড করা ছবিগুলো যাচাই করবেন। সবশেষে, দুষ্কৃতকারীদের হাত থেকে সুরক্ষার জন্য আপনি সম্ভবত আপলোডের আকার সীমিত করতে চাইবেন।

ধরা যাক, এই সব কাজ করা হয়ে গেছে। আপলোড করা ফাইলগুলো কোথায় সংরক্ষণ করা হবে তা নির্দিষ্ট করার সুবিধা যোগ করতে আমরা কীভাবে আমাদের অ্যাপটি আপডেট করতে পারি? এর মূল উপায় হলো MainHandler.get এ থাকা blobstore.create_upload_url কলটিকে সামান্য পরিবর্তন করে gs_bucket_name প্যারামিটারটি যোগ করার মাধ্যমে আপলোডের জন্য ক্লাউড স্টোরেজের কাঙ্ক্ষিত স্থানটি নির্দিষ্ট করে দেওয়া, যেমনটা নিচে দেখানো হয়েছে:

blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))

যেহেতু এটি একটি ঐচ্ছিক আপডেট এবং আপনি নির্দিষ্ট করতে চান যে আপলোডগুলো কোথায় যাবে, তাই এটি রিপো-র main.py ফাইলের অংশ নয়। এর পরিবর্তে, আপনার পর্যালোচনার জন্য রিপো-তে main-gcs.py নামে একটি বিকল্প .appspot.com উপলব্ধ আছে। একটি পৃথক বাকেট "ফোল্ডার" ব্যবহার করার পরিবর্তে, main-gcs.py এর কোড main.py মতোই আপলোডগুলোকে "রুট" বাকেটে ( PROJECT_ID ) সংরক্ষণ করে, কিন্তু এই বিভাগে যেমন ইঙ্গিত দেওয়া হয়েছে, যদি আপনি নমুনাটিকে আরও উন্নত কিছুতে রূপান্তরিত করতে চান, তবে এটি আপনার প্রয়োজনীয় কাঠামো সরবরাহ করে। নিচে main.py এবং main-gcs.py মধ্যেকার "ডিফস"-এর একটি চিত্র দেওয়া হলো।

256e1ea68241a501.png

৬. সারসংক্ষেপ/পরিষ্কারকরণ

এই অংশে অ্যাপটি ডেপ্লয় করে, এটি উদ্দেশ্য অনুযায়ী কাজ করছে কিনা তা যাচাই করে এবং যেকোনো প্রতিফলিত আউটপুটে তা পরীক্ষা করে এই কোডল্যাবটি শেষ করা হবে। অ্যাপ যাচাইকরণের পর, যেকোনো পরিষ্করণমূলক পদক্ষেপ গ্রহণ করুন এবং পরবর্তী পদক্ষেপগুলো বিবেচনা করুন।

অ্যাপ্লিকেশনটি স্থাপন এবং যাচাই করুন

gcloud app deploy ব্যবহার করে আপনার অ্যাপটি পুনরায় ডিপ্লয় করুন এবং নিশ্চিত করুন যে অ্যাপটি প্রত্যাশা অনুযায়ী কাজ করছে, তবে এর ইউজার এক্সপেরিয়েন্স (UX) মডিউল ০ অ্যাপের থেকে ভিন্ন হবে। এখন আপনার অ্যাপে দুটি ভিন্ন স্ক্রিন রয়েছে, যার মধ্যে প্রথমটি হলো ফাইল আপলোড ফর্ম ভিজিট করার প্রম্পট:

f5b5f9f19d8ae978.png সেখান থেকে, ব্যবহারকারীরা হয় একটি ফাইল আপলোড করে 'সাবমিট' ক্লিক করেন, অথবা কিছু আপলোড না করার জন্য 'স্কিপ'-এ ক্লিক করেন। উভয় ক্ষেত্রেই, ফলাফল হলো সর্বশেষ ভিজিটের স্ক্রিন, যা এখন ভিজিটের টাইমস্ট্যাম্প এবং ভিজিটরের তথ্যের মধ্যে 'ভিউ' লিঙ্ক বা 'নন' দিয়ে বর্ধিত করা হয়েছে:

f5ac6b98ee8a34cb.png

মডিউল ০ স্যাম্পল অ্যাপে অ্যাপ ইঞ্জিন ব্লবস্টোর-এর ব্যবহার যুক্ত করার এই কোডল্যাবটি সম্পন্ন করার জন্য অভিনন্দন। আপনার কোড এখন FINISH (মডিউল ১৫) ফোল্ডারের কোডের সাথে মিলে যাওয়া উচিত। বিকল্প main-gcs.py ফাইলটিও সেই ফোল্ডারে রয়েছে।

পরিষ্কার করা

সাধারণ

আপাতত আপনার কাজ শেষ হয়ে গেলে, বিল এড়ানোর জন্য আমরা আপনাকে আপনার অ্যাপ ইঞ্জিন অ্যাপটি নিষ্ক্রিয় করার পরামর্শ দিচ্ছি। তবে, আপনি যদি আরও কিছু পরীক্ষা বা নিরীক্ষা করতে চান, তাহলে অ্যাপ ইঞ্জিন প্ল্যাটফর্মের একটি বিনামূল্যের কোটা রয়েছে, এবং যতক্ষণ আপনি সেই ব্যবহারের সীমা অতিক্রম না করবেন, ততক্ষণ আপনার কোনো চার্জ লাগার কথা নয়। এটি কম্পিউট ব্যবহারের জন্য, তবে প্রাসঙ্গিক অ্যাপ ইঞ্জিন পরিষেবাগুলোর জন্যও চার্জ লাগতে পারে, তাই আরও তথ্যের জন্য এর প্রাইসিং পেজটি দেখুন। এই মাইগ্রেশনে যদি অন্য কোনো ক্লাউড পরিষেবা অন্তর্ভুক্ত থাকে, তবে সেগুলোর বিল আলাদাভাবে করা হবে। উভয় ক্ষেত্রেই, প্রযোজ্য হলে, নিচের "এই কোডল্যাবের জন্য নির্দিষ্ট" অংশটি দেখুন।

সম্পূর্ণ স্বচ্ছতার জন্য, অ্যাপ ইঞ্জিনের মতো গুগল ক্লাউড সার্ভারলেস কম্পিউট প্ল্যাটফর্মে ডেপ্লয় করতে সামান্য বিল্ড এবং স্টোরেজ খরচ হয়। ক্লাউড বিল্ড এবং ক্লাউড স্টোরেজ উভয়েরই নিজস্ব ফ্রি কোটা রয়েছে। সেই ইমেজটি স্টোরেজ করতে সেই কোটার কিছু অংশ ব্যবহৃত হয়। তবে, আপনি এমন কোনো অঞ্চলে থাকতে পারেন যেখানে এই ধরনের কোনো ফ্রি টিয়ার নেই, তাই সম্ভাব্য খরচ কমাতে আপনার স্টোরেজ ব্যবহারের বিষয়ে সচেতন থাকুন। ক্লাউড স্টোরেজের যে নির্দিষ্ট "ফোল্ডারগুলো" আপনার পর্যালোচনা করা উচিত, সেগুলো হলো:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • উপরের স্টোরেজ লিঙ্কগুলি আপনার PROJECT_ID এবং * LOC *-এর উপর নির্ভর করে, উদাহরণস্বরূপ, " us " যদি আপনার অ্যাপটি মার্কিন যুক্তরাষ্ট্রে হোস্ট করা হয়।

অন্যদিকে, যদি আপনি এই অ্যাপ্লিকেশন বা অন্যান্য সম্পর্কিত মাইগ্রেশন কোডল্যাবগুলো নিয়ে আর কাজ চালিয়ে যেতে না চান এবং সবকিছু পুরোপুরি মুছে ফেলতে চান, তাহলে আপনার প্রজেক্টটি শাট ডাউন করুন

এই কোডল্যাবের জন্য নির্দিষ্ট

নীচে তালিকাভুক্ত পরিষেবাগুলি এই কোডল্যাবের জন্য অনন্য। আরও তথ্যের জন্য প্রতিটি পণ্যের ডকুমেন্টেশন দেখুন:

পরবর্তী পদক্ষেপ

পরবর্তী যৌক্তিক মাইগ্রেশনটি মডিউল ১৬-তে আলোচনা করা হয়েছে, যেখানে ডেভেলপারদের দেখানো হয়েছে কীভাবে অ্যাপ ইঞ্জিন ব্লবস্টোর সার্ভিস থেকে ক্লাউড স্টোরেজ ক্লায়েন্ট লাইব্রেরি ব্যবহারে মাইগ্রেট করতে হয়। আপগ্রেড করার সুবিধাগুলোর মধ্যে রয়েছে ক্লাউড স্টোরেজের আরও বেশি ফিচার অ্যাক্সেস করতে পারা এবং এমন একটি ক্লায়েন্ট লাইব্রেরির সাথে পরিচিত হওয়া যা অ্যাপ ইঞ্জিনের বাইরের অ্যাপগুলোর জন্যও কাজ করে, তা গুগল ক্লাউড, অন্যান্য ক্লাউড বা এমনকি অন-প্রেমিসেই হোক না কেন। যদি আপনার মনে হয় ক্লাউড স্টোরেজের সমস্ত ফিচারের প্রয়োজন নেই অথবা এর খরচের প্রভাব নিয়ে আপনি চিন্তিত, তাহলে আপনি অ্যাপ ইঞ্জিন ব্লবস্টোরেই থাকতে পারেন।

মডিউল ১৬-এর বাইরে আরও অনেক সম্ভাব্য মাইগ্রেশন রয়েছে, যেমন ক্লাউড এনডিবি ও ক্লাউড ডেটাস্টোর, ক্লাউড টাস্কস, বা ক্লাউড মেমোরিস্টোর। এছাড়াও ক্লাউড রান এবং ক্লাউড ফাংশনস-এ ক্রস-প্রোডাক্ট মাইগ্রেশনও রয়েছে। মাইগ্রেশন রিপোটিতে সমস্ত কোড স্যাম্পল রয়েছে, উপলব্ধ সমস্ত কোডল্যাব এবং ভিডিওর লিঙ্ক দেওয়া আছে, এবং কোন মাইগ্রেশনগুলো বিবেচনা করা উচিত ও মাইগ্রেশনগুলোর কোনো প্রাসঙ্গিক "ক্রম" সম্পর্কেও নির্দেশনা প্রদান করা হয়েছে।

৭. অতিরিক্ত সম্পদ

কোডল্যাবের সমস্যা/মতামত

এই কোডল্যাবে কোনো সমস্যা পেলে, অভিযোগ জানানোর আগে অনুগ্রহ করে সমস্যাটি অনুসন্ধান করুন। নতুন সমস্যা অনুসন্ধান ও তৈরি করার লিঙ্ক:

অভিবাসন সম্পদ

মডিউল ০ (শুরু) এবং মডিউল ১৫ (শেষ)-এর রিপো ফোল্ডারগুলোর লিঙ্ক নিচের টেবিলে পাওয়া যাবে। এছাড়াও, সমস্ত অ্যাপ ইঞ্জিন কোডল্যাব মাইগ্রেশনের রিপো থেকেও এগুলো অ্যাক্সেস করা যাবে, যা আপনি ক্লোন করতে পারেন অথবা একটি জিপ ফাইল হিসেবে ডাউনলোড করতে পারেন।

কোডল্যাব

পাইথন ২

পাইথন ৩

মডিউল ০

কোড

প্রযোজ্য নয়

মডিউল ১৫ (এই কোডল্যাব)

কোড

প্রযোজ্য নয়

অনলাইন রিসোর্স

এই টিউটোরিয়ালটির জন্য প্রাসঙ্গিক হতে পারে এমন কিছু অনলাইন রিসোর্স নিচে দেওয়া হলো:

অ্যাপ ইঞ্জিন

গুগল ক্লাউড

পাইথন

ভিডিও

লাইসেন্স

এই কাজটি ক্রিয়েটিভ কমন্স অ্যাট্রিবিউশন ২.০ জেনেরিক লাইসেন্সের অধীনে রয়েছে।