নিম্নলিখিত টিউটোরিয়ালে আমরা দেখাবো কিভাবে Google Protocol Buffers (protobuf) সংজ্ঞা ব্যবহার করে JSON-এ একটি ফিড তৈরি করতে হয়। আমরা protobuf স্কিমার উপর ভিত্তি করে সোর্স কোড তৈরি করতে protobuf কম্পাইলার ব্যবহার করব। জেনারেটেড সোর্স কোড ব্যবহার করে একটি ফিড তৈরি করা একটি সহজ ইন্টারফেস প্রদান করে এবং ভুল ফিল্ড নাম বা ফিল্ড টাইপ দিয়ে ফিড তৈরি করা থেকে বিরত রাখে।
প্রকল্প সেটআপ
- একটি নতুন প্রকল্প ডিরেক্টরি তৈরি করুন।
- প্রোটো সংজ্ঞা থেকে offer.proto money.proto dayofweek.proto timeofday.proto date.proto এর বিষয়বস্তু নতুন ফাইল হিসেবে আপনার প্রোজেক্ট ডিরেক্টরি রুটে কপি করুন।
- প্রোটোক কম্পাইলার ইনস্টল করুন
.proto ফাইলগুলি থেকে সোর্স কোড তৈরি করতে, আপনার protoc কম্পাইলারের প্রয়োজন হবে। Protocle Buffers GitHub রিলিজ পৃষ্ঠা থেকে সর্বশেষ পূর্ব-নির্মিত বাইনারিটি ডাউনলোড করুন।
জিপটি বের করুন এবং PATH এনভায়রনমেন্ট ভেরিয়েবলে বিন পাথ যোগ করুন, উদাহরণস্বরূপ:
unzip protoc-22.0-linux-x86_64.zip -d /usr/local/protoc export PATH="$PATH:/usr/local/protoc/bin"
সোর্স কোড তৈরি করুন
পাইথন
- পাইথন প্রোটোবাফ লাইব্রেরি ইনস্টল করুন
pip install protobuf
- ক্লায়েন্ট সোর্স কোড তৈরি করুন।
প্রোটো আউটপুট ডিরেক্টরি তৈরি করুন: তৈরি করা হয়েছে
protoc --python_out=./generated offer.proto money.proto dayofweek.proto timeofday.proto date.proto
উদাহরণস্বরূপ, জেনারেট করা পাথ অন্তর্ভুক্ত করার জন্য PYTHONPATH এনভায়রনমেন্ট ভেরিয়েবল আপডেট করুন:
export PYTHONPATH="$PYTHONPATH:./generated"
যদি আপনি Bazel ব্যবহার করেন, তাহলে protoc চালানোর বিকল্প হিসেবে py_proto_library নিয়মটি ব্যবহার করে দেখুন।
ব্যবহারের উদাহরণ
সম্পূর্ণ উদাহরণ প্রকল্পটি এখানে পাওয়া যাবে।
import json from google.protobuf.json_format import MessageToDict from google.protobuf.timestamp_pb2 import Timestamp # Replace these imports with your actual generated proto package paths from generated import offer_pb2 from generated import money_pb2 from generated import dayofweek_pb2 from generated import timeofday_pb2 _MAX_BYTES_DATA_FILE = 200 * 1024 * 1024 def generate_offer_feed(): # Create OfferFeed feed = offer_pb2.OfferFeed() # Build the offers offer = offer_pb2.Offer( offer_id="offer-1", entity_ids=["dining-1"], offer_source=offer_pb2.OFFER_SOURCE_AGGREGATOR, action_type=offer_pb2.ACTION_TYPE_DINING, offer_modes=[ offer_pb2.OFFER_MODE_WALK_IN, offer_pb2.OFFER_MODE_FREE_RESERVATION ], offer_category=offer_pb2.OFFER_CATEGORY_BASE_OFFER, offer_details=offer_pb2.OfferDetails( offer_display_text="₹100 off on your order", # Note: If this is a 'oneof', you set the field name directly discount_value=money_pb2.Money( currency_code="INR", units=100 ) ), offer_restrictions=offer_pb2.OfferRestrictions( combinable_with_other_offers=True, combinable_offer_categories=[ offer_pb2.OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER, offer_pb2.OFFER_CATEGORY_ADD_ON_COUPON_OFFER ] ), terms=offer_pb2.Terms( restricted_to_certain_users=False, terms_and_conditions="Valid on all menu items." ), validity_periods=[ offer_pb2.ValidityPeriod( valid_period=offer_pb2.ValidityRange( valid_from_time=Timestamp(seconds=1687062000), valid_through_time=Timestamp(seconds=1956556800) ), time_of_day=[ # Monday - Thursday Window offer_pb2.TimeOfDayWindow( time_windows=offer_pb2.TimeOfDayRange( open_time=timeofday_pb2.TimeOfDay(hours=13), close_time=timeofday_pb2.TimeOfDay(hours=23) ), day_of_week=[ dayofweek_pb2.DayOfWeek.MONDAY, dayofweek_pb2.DayOfWeek.TUESDAY, dayofweek_pb2.DayOfWeek.WEDNESDAY, dayofweek_pb2.DayOfWeek.THURSDAY ] ), # Friday - Sunday Window offer_pb2.TimeOfDayWindow( time_windows=offer_pb2.TimeOfDayRange( open_time=timeofday_pb2.TimeOfDay(hours=13), close_time=timeofday_pb2.TimeOfDay(hours=23, minutes=59, seconds=59) ), day_of_week=[ dayofweek_pb2.DayOfWeek.FRIDAY, dayofweek_pb2.DayOfWeek.SATURDAY, dayofweek_pb2.DayOfWeek.SUNDAY ] ) ] ) ], offer_url="https://www.example-restaurant.com/offer/base_offer_1", image_url="https://www.example-restaurant.com/images/offer_base.jpg" ) # Example testing for menu feed size # Protocol buffer message must be less than 2 GiB # https://protobuf.dev/programming-guides/proto-limits/ # It is recommended to not exceed 200 MB, as there is an Actions # Center limit of 200 MB per file after compression. if feed.ByteSize() + offer.ByteSize() < _MAX_BYTES_DATA_FILE: feed.data.append(offer) # else write current feed to file and start a new feed # Serialize to JSON # preserving_proto_field_names=True ensures camelCase becomes snake_case if defined that way in .proto json_output = json.dumps( MessageToDict(feed, preserving_proto_field_name=True) ) print(json_output) if __name__ == "__main__": generate_offer_feed()
কোড উদাহরণটি দেখায় কিভাবে একটি DINING অফার ফিড তৈরি করতে হয়। তারপর উদাহরণটি দেখায় কিভাবে ফিডটিকে JSON-এ সিরিয়ালাইজ করতে হয়।
পাইথন এপিআই বৈশিষ্ট্যগুলি সেট করে নেস্টেড অবজেক্টগুলির অলস আরম্ভকরণের অনুমতি দেয়।জাভা
- এখানে বর্ণিত maven অথবা gradle ব্যবহার করে আপনার প্রকল্পে dependencies protobuf-java এবং protobuf-java-util যোগ করুন।
- ক্লায়েন্ট সোর্স কোড তৈরি করুন।
protoc --java_out=src/main/java offer.proto money.proto dayofweek.proto timeofday.proto date.proto
maven ব্যবহার করার সময় কম্পাইলের সময় সোর্স কোড তৈরি করতে আপনি protobuf-maven-plugin ব্যবহার করতে পারেন।
যদি আপনি Bazel ব্যবহার করেন, তাহলে protoc চালানোর বিকল্প হিসেবে java_proto_library নিয়মটি ব্যবহার করে দেখুন।
ব্যবহারের উদাহরণ
সম্পূর্ণ উদাহরণ প্রকল্পটি এখানে পাওয়া যাবে।
package com.example.offers; import com.google.protobuf.util.JsonFormat; import ext.maps.booking.feeds.offers.Offer; import ext.maps.booking.feeds.offers.OfferFeed; import ext.maps.booking.feeds.offers.OfferDetails; import ext.maps.booking.feeds.offers.OfferRestrictions; import ext.maps.booking.feeds.offers.Terms; import ext.maps.booking.feeds.offers.ValidityPeriod; import ext.maps.booking.feeds.offers.ValidityRange; import ext.maps.booking.feeds.offers.OfferCategory; import ext.maps.booking.feeds.offers.OfferMode; import ext.maps.booking.feeds.offers.OfferSource; import ext.maps.booking.feeds.offers.ActionType; import ext.maps.booking.feeds.offers.TimeOfDayWindow; import ext.maps.booking.feeds.offers.TimeOfDayRange; import com.google.type.Money; import com.google.protobuf.Timestamp; import com.google.type.DayOfWeek; import com.google.type.TimeOfDay; public class OfferFeedGenerator { // 200 MB public static final int MAX_BYTES_DATA_FILE = 200 * 1024 * 1024; public static void main(String[] args) throws Exception { // Create OfferFeed OfferFeed.Builder feed = OfferFeed.newBuilder(); // Build the offers Offer offer = Offer.newBuilder() .setOfferId("offer-1") .addEntityIds("dining-1") .setOfferSource(OfferSource.OFFER_SOURCE_AGGREGATOR) .setActionType(ActionType.ACTION_TYPE_DINING) .addOfferModes(OfferMode.OFFER_MODE_WALK_IN) .addOfferModes(OfferMode.OFFER_MODE_FREE_RESERVATION) .setOfferCategory(OfferCategory.OFFER_CATEGORY_BASE_OFFER) .setOfferDetails(OfferDetails.newBuilder() .setOfferDisplayText("₹100 off on your order") .setDiscountValue(Money.newBuilder() .setCurrencyCode("INR") .setUnits(100))) .setOfferRestrictions(OfferRestrictions.newBuilder() .setCombinableWithOtherOffers(true) .addCombinableOfferCategories(OfferCategory.OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER) .addCombinableOfferCategories(OfferCategory.OFFER_CATEGORY_ADD_ON_COUPON_OFFER)) .setTerms(Terms.newBuilder() .setRestrictedToCertainUsers(false) .setTermsAndConditions("Valid on all menu items.")) .addValidityPeriods(ValidityPeriod.newBuilder() .setValidPeriod(ext.maps.booking.feeds.offers.ValidityRange.newBuilder() .setValidFromTime(Timestamp.newBuilder().setSeconds(1687062000)) .setValidThroughTime(Timestamp.newBuilder().setSeconds(1956556800))) // // Monday - Thursday Window .addTimeOfDay(ext.maps.booking.feeds.offers.TimeOfDayWindow.newBuilder() .setTimeWindows(ext.maps.booking.feeds.offers.TimeOfDayRange.newBuilder() .setOpenTime(com.google.type.TimeOfDay.newBuilder().setHours(13)) .setCloseTime(com.google.type.TimeOfDay.newBuilder().setHours(23))) .addDayOfWeek(DayOfWeek.MONDAY) .addDayOfWeek(DayOfWeek.TUESDAY) .addDayOfWeek(DayOfWeek.WEDNESDAY) .addDayOfWeek(DayOfWeek.THURSDAY)) // Friday - Sunday Window .addTimeOfDay(ext.maps.booking.feeds.offers.TimeOfDayWindow.newBuilder() .setTimeWindows(ext.maps.booking.feeds.offers.TimeOfDayRange.newBuilder() .setOpenTime(com.google.type.TimeOfDay.newBuilder().setHours(13)) .setCloseTime(com.google.type.TimeOfDay.newBuilder().setHours(23).setMinutes(59).setSeconds(59))) .addDayOfWeek(DayOfWeek.FRIDAY) .addDayOfWeek(DayOfWeek.SATURDAY) .addDayOfWeek(DayOfWeek.SUNDAY)) ) .setOfferUrl("https://www.example-restaurant.com/offer/base_offer_1") .setImageUrl("https://www.example-restaurant.com/images/offer_base.jpg") .build(); // Example testing for offer feed size // Protocol buffer message must be less than 2 GiB // https://protobuf.dev/programming-guides/proto-limits/ // It is recommended to not exceed 200 MB, as there is an Actions // Center limit of 200 MB per file after compression. int offerSize = offer.getSerializedSize(); int currentFeedSize = feed.build().getSerializedSize(); if (currentFeedSize + offerSize < MAX_BYTES_DATA_FILE) { feed.addData(offer); } else { // 1. Serialize and save the current 'feed' to a file // 2. Reset 'feed' to a new empty OfferFeed // 3. Add the 'offer' to the new feed } // Serialize to JSON String jsonOutput = JsonFormat.printer() .preservingProtoFieldNames() .print(feed); System.out.println(jsonOutput); } }
কোড উদাহরণটি দেখায় কিভাবে একটি DINING অফার ফিড তৈরি করতে হয়। তারপর উদাহরণটি দেখায় কিভাবে ফিডটিকে JSON-এ সিরিয়ালাইজ করতে হয়।
যাও
- গো-এর জন্য প্রোটোক প্লাগইন ইনস্টল করুন
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
PATH এনভায়রনমেন্ট ভেরিয়েবলটি আপডেট করুন যাতে protoc-gen-go প্লাগইন অন্তর্ভুক্ত করা যায়, উদাহরণস্বরূপ:
export PATH="$PATH:$(go env GOPATH)/bin"
- অ্যাপটি আরম্ভ করুন এবং ক্লায়েন্ট সোর্স কোড তৈরি করুন।
go mod init feed/app mkdir generated protoc --go_out=./generated/ offer.proto money.proto dayofweek.proto timeofday.proto date.proto
যদি আপনি Bazel ব্যবহার করেন, তাহলে protoc চালানোর বিকল্প হিসেবে go_proto_library নিয়মটি ব্যবহার করে দেখুন।
ব্যবহারের উদাহরণ
সম্পূর্ণ উদাহরণ প্রকল্পটি এখানে পাওয়া যাবে।
package main import ( pb "feed/app/generated/ext/maps/booking/offers/proto" "fmt" "log" money "google.golang.org/genproto/googleapis/type/money" timestamppb "google.golang.org/protobuf/types/known/timestamppb" dayofweek "google.golang.org/genproto/googleapis/type/dayofweek" timeofday "google.golang.org/genproto/googleapis/type/timeofday" proto "google.golang.org/protobuf/proto" "google.golang.org/protobuf/encoding/protojson" ) func main() { // 200 MB feed file size limit const MaxBytesDataFile = 200 * 1024 * 1024 // Create OfferFeed with offers feed := &pb.OfferFeed{} // Build the offers offer := &pb.Offer{ OfferId: "offer-1", EntityIds: []string{"dining-1"}, OfferSource: pb.OfferSource_OFFER_SOURCE_AGGREGATOR, ActionType: pb.ActionType_ACTION_TYPE_DINING, OfferModes: []pb.OfferMode{ pb.OfferMode_OFFER_MODE_WALK_IN, pb.OfferMode_OFFER_MODE_FREE_RESERVATION, }, OfferCategory: pb.OfferCategory_OFFER_CATEGORY_BASE_OFFER, OfferDetails: &pb.OfferDetails{ OfferDisplayText: "₹100 off on your order", OfferSpecification: &pb.OfferDetails_DiscountValue{ DiscountValue: &money.Money{ CurrencyCode: "INR", Units: 100, }, }, }, OfferRestrictions: &pb.OfferRestrictions{ CombinableWithOtherOffers: true, CombinableOfferCategories: []pb.OfferCategory{ pb.OfferCategory_OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER, pb.OfferCategory_OFFER_CATEGORY_ADD_ON_COUPON_OFFER, }, }, Terms: &pb.Terms{ RestrictedToCertainUsers: false, TermsAndConditions: "Valid on all menu items.", }, ValidityPeriods: []*pb.ValidityPeriod{ { ValidPeriod: &pb.ValidityRange{ ValidFromTime: ×tamppb.Timestamp{Seconds: 1687062000}, ValidThroughTime: ×tamppb.Timestamp{Seconds: 1956556800}, }, TimeOfDay: []*pb.TimeOfDayWindow{ // Monday - Thursday Window { TimeWindows: &pb.TimeOfDayRange{ OpenTime: &timeofday.TimeOfDay{Hours: 13}, CloseTime: &timeofday.TimeOfDay{Hours: 23}, }, DayOfWeek: []dayofweek.DayOfWeek{ dayofweek.DayOfWeek_MONDAY, dayofweek.DayOfWeek_TUESDAY, dayofweek.DayOfWeek_WEDNESDAY, dayofweek.DayOfWeek_THURSDAY, }, }, // Friday - Sunday Window { TimeWindows: &pb.TimeOfDayRange{ OpenTime: &timeofday.TimeOfDay{Hours: 13}, CloseTime: &timeofday.TimeOfDay{ Hours: 23, Minutes: 59, Seconds: 59, }, }, DayOfWeek: []dayofweek.DayOfWeek{ dayofweek.DayOfWeek_FRIDAY, dayofweek.DayOfWeek_SATURDAY, dayofweek.DayOfWeek_SUNDAY, }, }, }, }, }, OfferUrl: "https://www.example-restaurant.com/offer/base_offer_1", ImageUrl: "https://www.example-restaurant.com/images/offer_base.jpg", } // Example testing for feed size // Protocol buffer message must be less than 2 GiB // https://protobuf.dev/programming-guides/proto-limits/ // It is recommended to not exceed 200 MB, as there is an Actions // Center limit of 200 MB per file after compression. offerSize := proto.Size(offer) currentFeedSize := proto.Size(feed) if currentFeedSize + offerSize < MaxBytesDataFile { feed.Data = append(feed.Data, offer) } else { // 1. Serialize and save the current 'feed' to a file // 2. Reset 'feed' to a new empty OfferFeed // 3. Add the 'offer' to the new feed } // Serialize to JSON marshaler := protojson.MarshalOptions{ UseProtoNames: true, } jsonOutput, err := marshaler.Marshal(feed) if err != nil { log.Fatalf("Failed to marshal feed: %v", err) } fmt.Println(string(jsonOutput)) }
কোড উদাহরণটি দেখায় কিভাবে একটি DINING অফার ফিড তৈরি করতে হয়। তারপর উদাহরণটি দেখায় কিভাবে ফিডটিকে JSON-এ সিরিয়ালাইজ করতে হয়।
টাইপস্ক্রিপ্ট
- টাইপস্ক্রিপ্ট প্রোটোক প্লাগইনটি ইনস্টল করুন।
মনে রাখবেন যে ts-proto কোনও আনুষ্ঠানিকভাবে সমর্থিত Google প্রকল্প নয়।npm init npm i -D typescript npm i ts-proto
- আউটপুট ডিরেক্টরি তৈরি করুন এবং ক্লায়েন্ট সোর্স কোড তৈরি করুন।
প্রোটো আউটপুট ডিরেক্টরি তৈরি করুন: src/generated
protoc --plugin="./node_modules/.bin/protoc-gen-ts_proto" --ts_proto_opt=useOptionals=all --ts_proto_opt=snakeToCamel=false --ts_proto_opt=onlyTypes=true --ts_proto_out="./src/generated" offer.proto money.proto dayofweek.proto timeofday.proto date.proto
যদি আপনি Bazel ব্যবহার করেন, তাহলে protoc চালানোর বিকল্প হিসেবে js_proto_library নিয়মটি ব্যবহার করে দেখুন।
ব্যবহারের উদাহরণ
সম্পূর্ণ উদাহরণ প্রকল্পটি এখানে পাওয়া যাবে।
import { Offer, OfferFeed, OfferSource, ActionType, OfferMode, OfferCategory } from "./generated/offer"; // Path to your generated types import { Money } from "./generated/money"; import { DayOfWeek } from "./generated/dayofweek"; import { TimeOfDay } from "./generated/timeofday"; import { Timestamp } from "./generated/google/protobuf/timestamp"; import { Duration } from "./generated/google/protobuf/duration"; // 200 MB Limit const MAX_BYTES_DATA_FILE = 200 * 1024 * 1024; function generateOfferFeed() { // Build the Offer object const offer: Offer = { offer_id: "offer-1", entity_ids: ["dining-1"], offer_source: OfferSource.OFFER_SOURCE_AGGREGATOR, action_type: ActionType.ACTION_TYPE_DINING, offer_modes: [ OfferMode.OFFER_MODE_WALK_IN, OfferMode.OFFER_MODE_FREE_RESERVATION, ], offer_category: OfferCategory.OFFER_CATEGORY_BASE_OFFER, offer_details: { offer_display_text: "₹100 off on your order", // Set 'oneof' field: discountValue discount_value: { currency_code: "INR", units: 100, }, }, offer_restrictions: { combinable_with_other_offers: true, combinable_offer_categories: [ OfferCategory.OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER, OfferCategory.OFFER_CATEGORY_ADD_ON_COUPON_OFFER, ], }, terms: { restricted_to_certain_users: false, terms_and_conditions: "Valid on all menu items.", }, validity_periods: [ { valid_period: { valid_from_time: new Date(1687062000000), valid_through_time: new Date(1956556800000), }, time_of_day: [ // Monday - Thursday Window { time_windows: { open_time: { hours: 13, minutes: 0, seconds: 0, nanos: 0 }, close_time: { hours: 23, minutes: 0, seconds: 0, nanos: 0 }, }, day_of_week: [ DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, ], }, // Friday - Sunday Window { time_windows: { open_time: { hours: 13, minutes: 0, seconds: 0, nanos: 0 }, close_time: { hours: 23, minutes: 59, seconds: 59, nanos: 0 }, }, day_of_week: [ DayOfWeek.FRIDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY, ], }, ], }, ], offer_url: "https://www.example-restaurant.com/offer/base_offer_1", image_url: "https://www.example-restaurant.com/images/offer_base.jpg", }; // 2. Initialize the Feed const feed: OfferFeed = { data: [] }; // 3. Size checking // encode().finish() returns a Uint8Array (the binary representation) const offerSize = new Blob([JSON.stringify(offer)]).size; const currentFeedSize = new Blob([JSON.stringify(feed)]).size; if (currentFeedSize + offerSize < MAX_BYTES_DATA_FILE) { if (feed.data == undefined) { feed.data = [offer]; } else { feed.data.push(offer); } } else { // Logic for file rotation goes here console.log("Feed size limit reached. Rotate file."); } // 4. Serialize to JSON // In JS/TS, we often just use JSON.stringify for the plain object // if you used proto3 and want to ensure proper enum/timestamp formatting, // use the library's toJSON method. const jsonOutput = JSON.stringify(feed); console.log(jsonOutput); } generateOfferFeed();
কোড উদাহরণটি দেখায় কিভাবে একটি DINING অফার ফিড তৈরি করতে হয়। তারপর উদাহরণটি দেখায় কিভাবে ফিডটিকে JSON-এ সিরিয়ালাইজ করতে হয়।
দ্রষ্টব্য: প্রোটো স্কিমা থেকে JSON স্কিমা তৈরি করার জন্য তৃতীয় পক্ষের প্রোটোক কম্পাইলার এক্সটেনশন রয়েছে। আপনি যদি JSON স্কিমা ফাইলগুলির সাথে কাজ করতে পছন্দ করেন, তাহলে আপনি এখানে এমন একটি উদাহরণ পর্যালোচনা করতে পারেন।