Google ডেটা প্রোটোকলে পুনঃসূচনাযোগ্য মিডিয়া আপলোড

এরিক বিডেলম্যান, G Suite APIs টিম
ফেব্রুয়ারী 2010

  1. ভূমিকা
  2. পুনঃসূচনাযোগ্য প্রোটোকল
    1. একটি পুনঃসূচনাযোগ্য আপলোড অনুরোধ শুরু করা হচ্ছে৷
    2. একটি ফাইল আপলোড করা হচ্ছে
    3. একটি আপলোড পুনরায় শুরু করা হচ্ছে৷
    4. একটি আপলোড বাতিল করা হচ্ছে
    5. একটি বিদ্যমান সম্পদ আপডেট করা হচ্ছে
  3. ক্লায়েন্ট লাইব্রেরি উদাহরণ

ভূমিকা

বর্তমান ওয়েব স্ট্যান্ডার্ডগুলি বড় ফাইলগুলির HTTP আপলোডের সুবিধার্থে কোন নির্ভরযোগ্য প্রক্রিয়া প্রদান করে না। ফলস্বরূপ, Google এবং অন্যান্য সাইটে ফাইল আপলোডগুলি ঐতিহ্যগতভাবে মাঝারি আকারে সীমাবদ্ধ (যেমন 100 MB)। ইউটিউব এবং Google ডকুমেন্ট লিস্ট API-এর মতো পরিষেবাগুলির জন্য যা বড় ফাইল আপলোড সমর্থন করে, এটি একটি বড় বাধা উপস্থাপন করে।

Google ডেটা পুনঃসূচনাযোগ্য প্রোটোকল HTTP/1.0-এ পুনঃসূচনাযোগ্য POST/PUT HTTP অনুরোধগুলিকে সমর্থন করে সরাসরি পূর্বোক্ত সমস্যাগুলির সমাধান করে। প্রোটোকলটি Google Gears টিমের দ্বারা প্রস্তাবিত ResumableHttpRequestsProposal এর পরে মডেল করা হয়েছিল।

এই দস্তাবেজটি বর্ণনা করে যে কীভাবে আপনার অ্যাপ্লিকেশনগুলিতে Google ডেটার পুনঃসূচনাযোগ্য আপলোড বৈশিষ্ট্য অন্তর্ভুক্ত করা যায়৷ নীচের উদাহরণগুলি Google ডকুমেন্ট লিস্ট ডেটা API ব্যবহার করে৷ মনে রাখবেন যে অতিরিক্ত Google API যেগুলি এই প্রোটোকলটি প্রয়োগ করে তাদের সামান্য ভিন্ন প্রয়োজনীয়তা/প্রতিক্রিয়া কোড/ইত্যাদি থাকতে পারে। সুনির্দিষ্ট জন্য পরিষেবার ডকুমেন্টেশন পরামর্শ করুন.

পুনঃসূচনাযোগ্য প্রোটোকল

একটি পুনঃসূচনাযোগ্য আপলোড অনুরোধ শুরু করা হচ্ছে৷

একটি পুনঃসূচনাযোগ্য আপলোড সেশন শুরু করতে, পুনঃসূচনাযোগ্য-পোস্ট লিঙ্কে একটি HTTP POST অনুরোধ পাঠান৷ এই লিঙ্কটি ফিড স্তরে পাওয়া যায়। DocList API এর পুনঃসূচনাযোগ্য-পোস্ট লিঙ্কটি এরকম দেখাচ্ছে:

<link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml"
    href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>

আপনার POST অনুরোধের মূল অংশটি খালি হওয়া উচিত বা একটি Atom XML এন্ট্রি থাকা উচিত এবং প্রকৃত ফাইল সামগ্রী অন্তর্ভুক্ত করা উচিত নয়৷ নীচের উদাহরণটি একটি বড় পিডিএফ আপলোড করার জন্য একটি পুনঃসূচনাযোগ্য অনুরোধ তৈরি করে এবং Slug হেডার ব্যবহার করে ভবিষ্যতের নথির জন্য একটি শিরোনাম অন্তর্ভুক্ত করে।

POST /feeds/upload/create-session/default/private/full HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
Content-Length: 0
Slug: MyTitle
X-Upload-Content-Type: content_type
X-Upload-Content-Length: content_length

empty body

X-Upload-Content-Type এবং X-Upload-Content-Length শিরোনামগুলি আপনি শেষ পর্যন্ত আপলোড করা ফাইলের মাইমেটাইপ এবং আকারে সেট করা উচিত। আপলোড সেশন তৈরির সময় বিষয়বস্তুর দৈর্ঘ্য অজানা থাকলে, X-Upload-Content-Length শিরোনামটি বাদ দেওয়া যেতে পারে।

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

POST /feeds/upload/create-session/default/private/full?convert=false HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
Content-Length: atom_metadata_content_length
Content-Type: application/atom+xml
X-Upload-Content-Type: application/msword
X-Upload-Content-Length: 7654321

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#document"/>
  <title>MyTitle</title>
  <docs:writersCanInvite value="false"/>
</entry>

প্রাথমিক POST থেকে সার্ভারের প্রতিক্রিয়া হল Location হেডারে একটি অনন্য আপলোড URI এবং একটি খালি প্রতিক্রিয়া বডি:

HTTP/1.1 200 OK
Location: <upload_uri>

অনন্য আপলোড ইউআরআই ফাইলের অংশগুলি আপলোড করতে ব্যবহার করা হবে।

দ্রষ্টব্য : প্রাথমিক POST অনুরোধ ফিডে একটি নতুন এন্ট্রি তৈরি করে না। এটি শুধুমাত্র তখনই ঘটে যখন সম্পূর্ণ আপলোড অপারেশন সম্পন্ন হয়।

দ্রষ্টব্য : একটি পুনরায় শুরু করা সেশন URI এক সপ্তাহ পরে মেয়াদ শেষ হয়ে যায়।

একটি ফাইল আপলোড করা হচ্ছে

পুনঃসূচনাযোগ্য প্রোটোকল 'খণ্ডে' সামগ্রী আপলোড করার অনুমতি দেয়, কিন্তু প্রয়োজন হয় না, কারণ অনুরোধের আকারে HTTP-তে কোনও অন্তর্নিহিত সীমাবদ্ধতা নেই। আপনার ক্লায়েন্ট তার খণ্ড আকার চয়ন করতে বা সম্পূর্ণরূপে ফাইল আপলোড করতে বিনামূল্যে। এই উদাহরণটি একটি পুনঃসূচনাযোগ্য PUT ইস্যু করতে অনন্য আপলোড URI ব্যবহার করে। নিম্নলিখিত উদাহরণটি 1234567 বাইট পিডিএফ ফাইলের প্রথম 100000 বাইট পাঠায়:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 100000
Content-Range: bytes 0-99999/1234567

bytes 0-99999

যদি পিডিএফ ফাইলের আকার অজানা ছিল, তাহলে এই উদাহরণটি ব্যবহার করবে Content-Range: bytes 0-99999/*এখানে Content-Range শিরোনাম সম্পর্কে আরও তথ্য পড়ুন।

সার্ভার বর্তমান বাইট পরিসরের সাথে সাড়া দেয় যা সংরক্ষণ করা হয়েছে:

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-99999

সম্পূর্ণ ফাইলটি আপলোড না হওয়া পর্যন্ত আপনার ক্লায়েন্টকে ফাইলের প্রতিটি অংশ PUT চালিয়ে যেতে হবে। আপলোড সম্পূর্ণ না হওয়া পর্যন্ত, সার্ভার একটি HTTP 308 Resume Incomplete এবং Range হেডারে যে বাইট রেঞ্জ সম্পর্কে জানে তার সাথে প্রতিক্রিয়া জানাবে। পরবর্তী খণ্ডটি কোথায় শুরু করবেন তা নির্ধারণ করতে ক্লায়েন্টদের অবশ্যই Range হেডার ব্যবহার করতে হবে। অতএব, অনুমান করবেন না যে সার্ভারটি PUT অনুরোধে পাঠানো সমস্ত বাইট পেয়েছে।

দ্রষ্টব্য : সার্ভার একটি খণ্ডের সময় Location শিরোনামে একটি নতুন অনন্য আপলোড URI জারি করতে পারে৷ আপনার ক্লায়েন্টের একটি আপডেট হওয়া Location জন্য পরীক্ষা করা উচিত এবং সার্ভারে অবশিষ্ট অংশগুলি পাঠাতে সেই URI ব্যবহার করা উচিত।

আপলোড সম্পূর্ণ হলে, প্রতিক্রিয়া একই হবে যেন আপলোডটি API-এর অ-পুনঃসূচনাযোগ্য আপলোড পদ্ধতি ব্যবহার করে করা হয়েছিল। অর্থাৎ, সার্ভার দ্বারা তৈরি করা <atom:entry> এর সাথে একটি 201 Created করা হবে। ইউনিক আপলোড ইউআরআই-তে পরবর্তী PUT গুলি আপলোড সম্পূর্ণ হওয়ার পরে যা ফেরত দেওয়া হয়েছিল সেই একই প্রতিক্রিয়া দেবে। কিছু সময়ের পরে, প্রতিক্রিয়া হবে 410 Gone বা 404 Not Found .

একটি আপলোড পুনরায় শুরু করা হচ্ছে৷

সার্ভার থেকে একটি প্রতিক্রিয়া পাওয়ার আগে আপনার অনুরোধটি বন্ধ হয়ে গেলে বা আপনি যদি সার্ভার থেকে একটি HTTP 503 প্রতিক্রিয়া পান, তাহলে আপনি অনন্য আপলোড URI-তে একটি খালি PUT অনুরোধ জারি করে আপলোডের বর্তমান স্থিতি জিজ্ঞাসা করতে পারেন৷

ক্লায়েন্ট কোন বাইট পেয়েছে তা নির্ধারণ করতে সার্ভারকে পোল করে:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 0
Content-Range: bytes */content_length

দৈর্ঘ্য জানা না থাকলে content_length হিসাবে * ব্যবহার করুন।

সার্ভার বর্তমান বাইট পরিসরের সাথে প্রতিক্রিয়া জানায়:

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-42

দ্রষ্টব্য : সার্ভার যদি সেশনের জন্য কোনো বাইট প্রতিশ্রুতি না করে থাকে, তাহলে এটি Range হেডারটি বাদ দেবে।

দ্রষ্টব্য : সার্ভার একটি খণ্ডের সময় Location শিরোনামে একটি নতুন অনন্য আপলোড URI জারি করতে পারে৷ আপনার ক্লায়েন্টের একটি আপডেট হওয়া Location জন্য পরীক্ষা করা উচিত এবং সার্ভারে অবশিষ্ট অংশগুলি পাঠাতে সেই URI ব্যবহার করা উচিত।

অবশেষে, ক্লায়েন্ট আবার শুরু করে যেখানে সার্ভার ছেড়ে গেছে:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 57
Content-Range: 43-99/100

<bytes 43-99>

একটি আপলোড বাতিল করা হচ্ছে

আপনি যদি আপলোডটি বাতিল করতে চান এবং এটির উপর আর কোনো পদক্ষেপ আটকাতে চান তবে অনন্য আপলোড URI-তে একটি DELETE অনুরোধ জারি করুন।

DELETE upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 0

সফল হলে, সার্ভার প্রতিক্রিয়া জানায় যে সেশনটি বাতিল করা হয়েছে, এবং আরও PUT s বা ক্যোয়ারী স্ট্যাটাস অনুরোধের জন্য একই কোডের সাথে প্রতিক্রিয়া জানায়:

HTTP/1.1 499 Client Closed Request

দ্রষ্টব্য : যদি একটি আপলোড বাতিল না করে পরিত্যক্ত হয়, তবে এটি তৈরির এক সপ্তাহ পরে স্বাভাবিকভাবেই মেয়াদ শেষ হয়ে যায়।

একটি বিদ্যমান সম্পদ আপডেট করা হচ্ছে

একটি পুনঃসূচনাযোগ্য আপলোড সেশন শুরু করার অনুরূপ, আপনি একটি বিদ্যমান ফাইলের বিষয়বস্তু প্রতিস্থাপন করতে পুনরায় শুরুযোগ্য আপলোড প্রোটোকল ব্যবহার করতে পারেন৷ একটি পুনঃসূচনাযোগ্য আপডেটের অনুরোধ শুরু করতে, rel=' ...#resumable-edit-media ' সহ এন্ট্রির লিঙ্কে একটি HTTP PUT পাঠান। প্রতিটি মিডিয়া entry এমন একটি লিঙ্ক থাকবে যদি API রিসোর্সের বিষয়বস্তু আপডেট করা সমর্থন করে।

উদাহরণ হিসেবে, ডকলিস্ট এপিআই-তে একটি নথি এন্ট্রিতে অনুরূপ একটি লিঙ্ক থাকবে:

<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
      href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>

সুতরাং, প্রাথমিক অনুরোধ হবে:

PUT /feeds/upload/create-session/default/private/full/document%3A12345 HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
If-Match: ETag | *
Content-Length: 0
X-Upload-Content-Length: content_length
X-Upload-Content-Type: content_type

empty body

একই সময়ে একটি সম্পদের মেটাডেটা এবং বিষয়বস্তু আপডেট করতে, একটি খালি বডির পরিবর্তে Atom XML অন্তর্ভুক্ত করুন৷ একটি পুনরায় শুরু করা আপলোড অনুরোধ বিভাগে উদাহরণ দেখুন।

যখন সার্ভার অনন্য আপলোড URI-এর সাথে সাড়া দেয়, তখন আপনার পেলোডের সাথে একটি PUT পাঠান। একবার আপনার অনন্য আপলোড ইউআরআই হয়ে গেলে, ফাইলের বিষয়বস্তু আপডেট করার প্রক্রিয়াটি একটি ফাইল আপলোড করার মতোই।

এই বিশেষ উদাহরণটি একটি শটে বিদ্যমান নথির বিষয়বস্তু আপডেট করবে:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 1000
Content-Range: 0-999/1000

<bytes 0-999>

উপরে ফিরে যাও

ক্লায়েন্ট লাইব্রেরি উদাহরণ

নীচে Google ডেটা ক্লায়েন্ট লাইব্রেরিতে Google ডক্সে (পুনরায় শুরু করা আপলোড প্রোটোকল ব্যবহার করে) একটি চলচ্চিত্র ফাইল আপলোড করার নমুনা রয়েছে৷ দ্রষ্টব্য, যে সমস্ত লাইব্রেরি এই সময়ে পুনঃসূচনাযোগ্য বৈশিষ্ট্যটিকে সমর্থন করে না৷

int MAX_CONCURRENT_UPLOADS = 10;
int PROGRESS_UPDATE_INTERVAL = 1000;
int DEFAULT_CHUNK_SIZE = 10485760;


DocsService client = new DocsService("yourCompany-yourAppName-v1");
client.setUserCredentials("user@gmail.com", "pa$$word");

// Create a listener
FileUploadProgressListener listener = new FileUploadProgressListener(); // See the sample for details on this class.

// Pool for handling concurrent upload tasks
ExecutorService executor = Executors.newFixedThreadPool(MAX_CONCURRENT_UPLOADS);

// Create {@link ResumableGDataFileUploader} for each file to upload
List uploaders = Lists.newArrayList();

File file = new File("test.mpg");
String contentType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();
MediaFileSource mediaFile = new MediaFileSource(file, contentType);
URL createUploadUrl = new URL("https://docs.google.com/feeds/upload/create-session/default/private/full");
ResumableGDataFileUploader uploader = new ResumableGDataFileUploader(createUploadUrl, mediaFile, client, DEFAULT_CHUNK_SIZE,
                                                                     executor, listener, PROGRESS_UPDATE_INTERVAL);
uploaders.add(uploader);

listener.listenTo(uploaders); // attach the listener to list of uploaders

// Start the upload(s)
for (ResumableGDataFileUploader uploader : uploaders) {
  uploader.start();
}

// wait for uploads to complete
while(!listener.isDone()) {
  try {
    Thread.sleep(100);
  } catch (InterruptedException ie) {
    listener.printResults();
    throw ie; // rethrow
  }
// Chunk size in MB
int CHUNK_SIZE = 1;

ClientLoginAuthenticator cla = new ClientLoginAuthenticator(
    "yourCompany-yourAppName-v1", ServiceNames.Documents, "user@gmail.com", "pa$$word");

// Set up resumable uploader and notifications
ResumableUploader ru = new ResumableUploader(CHUNK_SIZE);
ru.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(this.OnDone);
ru.AsyncOperationProgress += new AsyncOperationProgressEventHandler(this.OnProgress);

// Set metadata for our upload.
Document entry = new Document()
entry.Title = "My Video";
entry.MediaSource = new MediaFileSource("c:\\test.mpg", "video/mpeg");

// Add the upload uri to document entry.
Uri createUploadUrl = new Uri("https://docs.google.com/feeds/upload/create-session/default/private/full");
AtomLink link = new AtomLink(createUploadUrl.AbsoluteUri);
link.Rel = ResumableUploader.CreateMediaRelation;
entry.DocumentEntry.Links.Add(link);

ru.InsertAsync(cla, entry.DocumentEntry, userObject);
- (void)uploadAFile {
  NSString *filePath = @"~/test.mpg";
  NSString *fileName = [filePath lastPathComponent];

  // get the file's data
  NSData *data = [NSData dataWithContentsOfMappedFile:filePath];

  // create an entry to upload
  GDataEntryDocBase *newEntry = [GDataEntryStandardDoc documentEntry];
  [newEntry setTitleWithString:fileName];

  [newEntry setUploadData:data];
  [newEntry setUploadMIMEType:@"video/mpeg"];
  [newEntry setUploadSlug:fileName];

  // to upload, we need the entry, our service object, the upload URL,
  // and the callback for when upload has finished
  GDataServiceGoogleDocs *service = [self docsService];
  NSURL *uploadURL = [GDataServiceGoogleDocs docsUploadURL];
  SEL finishedSel = @selector(uploadTicket:finishedWithEntry:error:);

  // now start the upload
  GDataServiceTicket *ticket = [service fetchEntryByInsertingEntry:newEntry
                                                        forFeedURL:uploadURL
                                                          delegate:self
                                                 didFinishSelector:finishedSel];

  // progress monitoring is done by specifying a callback, like this
  SEL progressSel = @selector(ticket:hasDeliveredByteCount:ofTotalByteCount:);
  [ticket setUploadProgressSelector:progressSel];
}

// callback for when uploading has finished
- (void)uploadTicket:(GDataServiceTicket *)ticket
   finishedWithEntry:(GDataEntryDocBase *)entry
               error:(NSError *)error {
  if (error == nil) {
    // upload succeeded
  }
}

- (void)pauseOrResumeUploadForTicket:(GDataServiceTicket *)ticket {
  if ([ticket isUploadPaused]) {
    [ticket resumeUpload];
  } else {
    [ticket pauseUpload];
  }
}
import os.path
import atom.data
import gdata.client
import gdata.docs.client
import gdata.docs.data

CHUNK_SIZE = 10485760

client = gdata.docs.client.DocsClient(source='yourCompany-yourAppName-v1')
client.ClientLogin('user@gmail.com', 'pa$$word', client.source);

f = open('test.mpg')
file_size = os.path.getsize(f.name)

uploader = gdata.client.ResumableUploader(
    client, f, 'video/mpeg', file_size, chunk_size=CHUNK_SIZE, desired_class=gdata.docs.data.DocsEntry)

# Set metadata for our upload.
entry = gdata.docs.data.DocsEntry(title=atom.data.Title(text='My Video'))
new_entry = uploader.UploadFile('/feeds/upload/create-session/default/private/full', entry=entry)
print 'Document uploaded: ' + new_entry.title.text
print 'Quota used: %s' % new_entry.quota_bytes_used.text

সম্পূর্ণ নমুনা এবং উত্স কোড রেফারেন্সের জন্য, নিম্নলিখিত সংস্থানগুলি দেখুন:

উপরে ফিরে যাও