Initial commit
Some checks failed
Continuous Integration - Pull Request / code-tests (pull_request) Has been cancelled
Continuous Integration - Pull Request / deployment-tests (local-code) (pull_request) Has been cancelled
helm-chart-ci / helm-chart-ci (pull_request) Has been cancelled
kubevious-manifests-ci / kubevious-manifests-ci (pull_request) Has been cancelled
kustomize-build-ci / kustomize-build-ci (pull_request) Has been cancelled
terraform-validate-ci / terraform-validate-ci (pull_request) Has been cancelled
Clean up deployment / cleanup-namespace (pull_request) Has been cancelled
Continuous Integration - Main/Release / code-tests (push) Has been cancelled
Continuous Integration - Main/Release / deployment-tests (local-code) (push) Has been cancelled
helm-chart-ci / helm-chart-ci (push) Has been cancelled
kubevious-manifests-ci / kubevious-manifests-ci (push) Has been cancelled
kustomize-build-ci / kustomize-build-ci (push) Has been cancelled
terraform-validate-ci / terraform-validate-ci (push) Has been cancelled
Some checks failed
Continuous Integration - Pull Request / code-tests (pull_request) Has been cancelled
Continuous Integration - Pull Request / deployment-tests (local-code) (pull_request) Has been cancelled
helm-chart-ci / helm-chart-ci (pull_request) Has been cancelled
kubevious-manifests-ci / kubevious-manifests-ci (pull_request) Has been cancelled
kustomize-build-ci / kustomize-build-ci (pull_request) Has been cancelled
terraform-validate-ci / terraform-validate-ci (pull_request) Has been cancelled
Clean up deployment / cleanup-namespace (pull_request) Has been cancelled
Continuous Integration - Main/Release / code-tests (push) Has been cancelled
Continuous Integration - Main/Release / deployment-tests (local-code) (push) Has been cancelled
helm-chart-ci / helm-chart-ci (push) Has been cancelled
kubevious-manifests-ci / kubevious-manifests-ci (push) Has been cancelled
kustomize-build-ci / kustomize-build-ci (push) Has been cancelled
terraform-validate-ci / terraform-validate-ci (push) Has been cancelled
This commit is contained in:
2
src/currencyservice/.dockerignore
Normal file
2
src/currencyservice/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
client.js
|
||||
node_modules/
|
||||
1
src/currencyservice/.gitignore
vendored
Normal file
1
src/currencyservice/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
42
src/currencyservice/Dockerfile
Normal file
42
src/currencyservice/Dockerfile
Normal file
@@ -0,0 +1,42 @@
|
||||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM --platform=$BUILDPLATFORM node:20.20.0-alpine@sha256:09e2b3d9726018aecf269bd35325f46bf75046a643a66d28360ec71132750ec8 AS builder
|
||||
|
||||
# Some packages (e.g. @google-cloud/profiler) require additional
|
||||
# deps for post-install scripts
|
||||
RUN apk add --update --no-cache \
|
||||
python3 \
|
||||
make \
|
||||
g++
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install --only=production
|
||||
|
||||
FROM alpine:3.23.2@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62
|
||||
|
||||
RUN apk add --no-cache nodejs
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 7000
|
||||
|
||||
ENTRYPOINT [ "node", "server.js" ]
|
||||
68
src/currencyservice/client.js
Normal file
68
src/currencyservice/client.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2015 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
require('@google-cloud/trace-agent').start();
|
||||
|
||||
const path = require('path');
|
||||
const grpc = require('grpc');
|
||||
const pino = require('pino');
|
||||
|
||||
const PROTO_PATH = path.join(__dirname, './proto/demo.proto');
|
||||
const PORT = 7000;
|
||||
|
||||
const shopProto = grpc.load(PROTO_PATH).hipstershop;
|
||||
const client = new shopProto.CurrencyService(`localhost:${PORT}`,
|
||||
grpc.credentials.createInsecure());
|
||||
|
||||
const logger = pino({
|
||||
name: 'currencyservice-client',
|
||||
messageKey: 'message',
|
||||
formatters: {
|
||||
level (logLevelString, logLevelNum) {
|
||||
return { severity: logLevelString }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const request = {
|
||||
from: {
|
||||
currency_code: 'CHF',
|
||||
units: 300,
|
||||
nanos: 0
|
||||
},
|
||||
to_code: 'EUR'
|
||||
};
|
||||
|
||||
function _moneyToString (m) {
|
||||
return `${m.units}.${m.nanos.toString().padStart(9,'0')} ${m.currency_code}`;
|
||||
}
|
||||
|
||||
client.getSupportedCurrencies({}, (err, response) => {
|
||||
if (err) {
|
||||
logger.error(`Error in getSupportedCurrencies: ${err}`);
|
||||
} else {
|
||||
logger.info(`Currency codes: ${response.currency_codes}`);
|
||||
}
|
||||
});
|
||||
|
||||
client.convert(request, (err, response) => {
|
||||
if (err) {
|
||||
logger.error(`Error in convert: ${err}`);
|
||||
} else {
|
||||
logger.log(`Convert: ${_moneyToString(request.from)} to ${_moneyToString(response)}`);
|
||||
}
|
||||
});
|
||||
35
src/currencyservice/data/currency_conversion.json
Normal file
35
src/currencyservice/data/currency_conversion.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"EUR": "1.0",
|
||||
"USD": "1.1305",
|
||||
"JPY": "126.40",
|
||||
"BGN": "1.9558",
|
||||
"CZK": "25.592",
|
||||
"DKK": "7.4609",
|
||||
"GBP": "0.85970",
|
||||
"HUF": "315.51",
|
||||
"PLN": "4.2996",
|
||||
"RON": "4.7463",
|
||||
"SEK": "10.5375",
|
||||
"CHF": "1.1360",
|
||||
"ISK": "136.80",
|
||||
"NOK": "9.8040",
|
||||
"HRK": "7.4210",
|
||||
"RUB": "74.4208",
|
||||
"TRY": "6.1247",
|
||||
"AUD": "1.6072",
|
||||
"BRL": "4.2682",
|
||||
"CAD": "1.5128",
|
||||
"CNY": "7.5857",
|
||||
"HKD": "8.8743",
|
||||
"IDR": "15999.40",
|
||||
"ILS": "4.0875",
|
||||
"INR": "79.4320",
|
||||
"KRW": "1275.05",
|
||||
"MXN": "21.7999",
|
||||
"MYR": "4.6289",
|
||||
"NZD": "1.6679",
|
||||
"PHP": "59.083",
|
||||
"SGD": "1.5349",
|
||||
"THB": "36.012",
|
||||
"ZAR": "16.0583"
|
||||
}
|
||||
23
src/currencyservice/genproto.sh
Executable file
23
src/currencyservice/genproto.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash -eu
|
||||
#
|
||||
# Copyright 2018 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# [START gke_currencyservice_genproto]
|
||||
|
||||
# protos are loaded dynamically for node, simply copies over the proto.
|
||||
mkdir -p proto
|
||||
cp -r ../../protos/* ./proto
|
||||
|
||||
# [END gke_currencyservice_genproto]
|
||||
3589
src/currencyservice/package-lock.json
generated
Normal file
3589
src/currencyservice/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
src/currencyservice/package.json
Normal file
27
src/currencyservice/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "grpc-currency-service",
|
||||
"version": "0.1.0",
|
||||
"description": "A gRPC currency conversion microservice",
|
||||
"repository": "https://github.com/GoogleCloudPlatform/microservices-demo",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@google-cloud/profiler": "6.0.3",
|
||||
"@google-cloud/trace-agent": "8.0.0",
|
||||
"@grpc/grpc-js": "1.14.3",
|
||||
"@grpc/proto-loader": "0.8.0",
|
||||
"async": "3.2.6",
|
||||
"google-protobuf": "4.0.1",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/exporter-otlp-grpc": "0.26.0",
|
||||
"@opentelemetry/instrumentation-grpc": "0.211.0",
|
||||
"@opentelemetry/resources": "2.5.0",
|
||||
"@opentelemetry/semantic-conventions": "1.39.0",
|
||||
"@opentelemetry/sdk-trace-base": "2.5.0",
|
||||
"@opentelemetry/sdk-node": "0.211.0",
|
||||
"pino": "10.3.0",
|
||||
"xml2js": "0.6.2"
|
||||
}
|
||||
}
|
||||
260
src/currencyservice/proto/demo.proto
Normal file
260
src/currencyservice/proto/demo.proto
Normal file
@@ -0,0 +1,260 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package hipstershop;
|
||||
|
||||
// -----------------Cart service-----------------
|
||||
|
||||
service CartService {
|
||||
rpc AddItem(AddItemRequest) returns (Empty) {}
|
||||
rpc GetCart(GetCartRequest) returns (Cart) {}
|
||||
rpc EmptyCart(EmptyCartRequest) returns (Empty) {}
|
||||
}
|
||||
|
||||
message CartItem {
|
||||
string product_id = 1;
|
||||
int32 quantity = 2;
|
||||
}
|
||||
|
||||
message AddItemRequest {
|
||||
string user_id = 1;
|
||||
CartItem item = 2;
|
||||
}
|
||||
|
||||
message EmptyCartRequest {
|
||||
string user_id = 1;
|
||||
}
|
||||
|
||||
message GetCartRequest {
|
||||
string user_id = 1;
|
||||
}
|
||||
|
||||
message Cart {
|
||||
string user_id = 1;
|
||||
repeated CartItem items = 2;
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
// ---------------Recommendation service----------
|
||||
|
||||
service RecommendationService {
|
||||
rpc ListRecommendations(ListRecommendationsRequest) returns (ListRecommendationsResponse){}
|
||||
}
|
||||
|
||||
message ListRecommendationsRequest {
|
||||
string user_id = 1;
|
||||
repeated string product_ids = 2;
|
||||
}
|
||||
|
||||
message ListRecommendationsResponse {
|
||||
repeated string product_ids = 1;
|
||||
}
|
||||
|
||||
// ---------------Product Catalog----------------
|
||||
|
||||
service ProductCatalogService {
|
||||
rpc ListProducts(Empty) returns (ListProductsResponse) {}
|
||||
rpc GetProduct(GetProductRequest) returns (Product) {}
|
||||
rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse) {}
|
||||
}
|
||||
|
||||
message Product {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string description = 3;
|
||||
string picture = 4;
|
||||
Money price_usd = 5;
|
||||
|
||||
// Categories such as "clothing" or "kitchen" that can be used to look up
|
||||
// other related products.
|
||||
repeated string categories = 6;
|
||||
}
|
||||
|
||||
message ListProductsResponse {
|
||||
repeated Product products = 1;
|
||||
}
|
||||
|
||||
message GetProductRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message SearchProductsRequest {
|
||||
string query = 1;
|
||||
}
|
||||
|
||||
message SearchProductsResponse {
|
||||
repeated Product results = 1;
|
||||
}
|
||||
|
||||
// ---------------Shipping Service----------
|
||||
|
||||
service ShippingService {
|
||||
rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse) {}
|
||||
rpc ShipOrder(ShipOrderRequest) returns (ShipOrderResponse) {}
|
||||
}
|
||||
|
||||
message GetQuoteRequest {
|
||||
Address address = 1;
|
||||
repeated CartItem items = 2;
|
||||
}
|
||||
|
||||
message GetQuoteResponse {
|
||||
Money cost_usd = 1;
|
||||
}
|
||||
|
||||
message ShipOrderRequest {
|
||||
Address address = 1;
|
||||
repeated CartItem items = 2;
|
||||
}
|
||||
|
||||
message ShipOrderResponse {
|
||||
string tracking_id = 1;
|
||||
}
|
||||
|
||||
message Address {
|
||||
string street_address = 1;
|
||||
string city = 2;
|
||||
string state = 3;
|
||||
string country = 4;
|
||||
int32 zip_code = 5;
|
||||
}
|
||||
|
||||
// -----------------Currency service-----------------
|
||||
|
||||
service CurrencyService {
|
||||
rpc GetSupportedCurrencies(Empty) returns (GetSupportedCurrenciesResponse) {}
|
||||
rpc Convert(CurrencyConversionRequest) returns (Money) {}
|
||||
}
|
||||
|
||||
// Represents an amount of money with its currency type.
|
||||
message Money {
|
||||
// The 3-letter currency code defined in ISO 4217.
|
||||
string currency_code = 1;
|
||||
|
||||
// The whole units of the amount.
|
||||
// For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar.
|
||||
int64 units = 2;
|
||||
|
||||
// Number of nano (10^-9) units of the amount.
|
||||
// The value must be between -999,999,999 and +999,999,999 inclusive.
|
||||
// If `units` is positive, `nanos` must be positive or zero.
|
||||
// If `units` is zero, `nanos` can be positive, zero, or negative.
|
||||
// If `units` is negative, `nanos` must be negative or zero.
|
||||
// For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000.
|
||||
int32 nanos = 3;
|
||||
}
|
||||
|
||||
message GetSupportedCurrenciesResponse {
|
||||
// The 3-letter currency code defined in ISO 4217.
|
||||
repeated string currency_codes = 1;
|
||||
}
|
||||
|
||||
message CurrencyConversionRequest {
|
||||
Money from = 1;
|
||||
|
||||
// The 3-letter currency code defined in ISO 4217.
|
||||
string to_code = 2;
|
||||
}
|
||||
|
||||
// -------------Payment service-----------------
|
||||
|
||||
service PaymentService {
|
||||
rpc Charge(ChargeRequest) returns (ChargeResponse) {}
|
||||
}
|
||||
|
||||
message CreditCardInfo {
|
||||
string credit_card_number = 1;
|
||||
int32 credit_card_cvv = 2;
|
||||
int32 credit_card_expiration_year = 3;
|
||||
int32 credit_card_expiration_month = 4;
|
||||
}
|
||||
|
||||
message ChargeRequest {
|
||||
Money amount = 1;
|
||||
CreditCardInfo credit_card = 2;
|
||||
}
|
||||
|
||||
message ChargeResponse {
|
||||
string transaction_id = 1;
|
||||
}
|
||||
|
||||
// -------------Email service-----------------
|
||||
|
||||
service EmailService {
|
||||
rpc SendOrderConfirmation(SendOrderConfirmationRequest) returns (Empty) {}
|
||||
}
|
||||
|
||||
message OrderItem {
|
||||
CartItem item = 1;
|
||||
Money cost = 2;
|
||||
}
|
||||
|
||||
message OrderResult {
|
||||
string order_id = 1;
|
||||
string shipping_tracking_id = 2;
|
||||
Money shipping_cost = 3;
|
||||
Address shipping_address = 4;
|
||||
repeated OrderItem items = 5;
|
||||
}
|
||||
|
||||
message SendOrderConfirmationRequest {
|
||||
string email = 1;
|
||||
OrderResult order = 2;
|
||||
}
|
||||
|
||||
|
||||
// -------------Checkout service-----------------
|
||||
|
||||
service CheckoutService {
|
||||
rpc PlaceOrder(PlaceOrderRequest) returns (PlaceOrderResponse) {}
|
||||
}
|
||||
|
||||
message PlaceOrderRequest {
|
||||
string user_id = 1;
|
||||
string user_currency = 2;
|
||||
|
||||
Address address = 3;
|
||||
string email = 5;
|
||||
CreditCardInfo credit_card = 6;
|
||||
}
|
||||
|
||||
message PlaceOrderResponse {
|
||||
OrderResult order = 1;
|
||||
}
|
||||
|
||||
// ------------Ad service------------------
|
||||
|
||||
service AdService {
|
||||
rpc GetAds(AdRequest) returns (AdResponse) {}
|
||||
}
|
||||
|
||||
message AdRequest {
|
||||
// List of important key words from the current page describing the context.
|
||||
repeated string context_keys = 1;
|
||||
}
|
||||
|
||||
message AdResponse {
|
||||
repeated Ad ads = 1;
|
||||
}
|
||||
|
||||
message Ad {
|
||||
// url to redirect to when an ad is clicked.
|
||||
string redirect_url = 1;
|
||||
|
||||
// short advertisement text to display.
|
||||
string text = 2;
|
||||
}
|
||||
43
src/currencyservice/proto/grpc/health/v1/health.proto
Normal file
43
src/currencyservice/proto/grpc/health/v1/health.proto
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2015 The gRPC Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The canonical version of this proto can be found at
|
||||
// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package grpc.health.v1;
|
||||
|
||||
option csharp_namespace = "Grpc.Health.V1";
|
||||
option go_package = "google.golang.org/grpc/health/grpc_health_v1";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HealthProto";
|
||||
option java_package = "io.grpc.health.v1";
|
||||
|
||||
message HealthCheckRequest {
|
||||
string service = 1;
|
||||
}
|
||||
|
||||
message HealthCheckResponse {
|
||||
enum ServingStatus {
|
||||
UNKNOWN = 0;
|
||||
SERVING = 1;
|
||||
NOT_SERVING = 2;
|
||||
}
|
||||
ServingStatus status = 1;
|
||||
}
|
||||
|
||||
service Health {
|
||||
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
|
||||
}
|
||||
198
src/currencyservice/server.js
Normal file
198
src/currencyservice/server.js
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2018 Google LLC.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const pino = require('pino');
|
||||
const logger = pino({
|
||||
name: 'currencyservice-server',
|
||||
messageKey: 'message',
|
||||
formatters: {
|
||||
level (logLevelString, logLevelNum) {
|
||||
return { severity: logLevelString }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(process.env.DISABLE_PROFILER) {
|
||||
logger.info("Profiler disabled.")
|
||||
}
|
||||
else {
|
||||
logger.info("Profiler enabled.")
|
||||
require('@google-cloud/profiler').start({
|
||||
serviceContext: {
|
||||
service: 'currencyservice',
|
||||
version: '1.0.0'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Register GRPC OTel Instrumentation for trace propagation
|
||||
// regardless of whether tracing is emitted.
|
||||
const { GrpcInstrumentation } = require('@opentelemetry/instrumentation-grpc');
|
||||
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
|
||||
|
||||
registerInstrumentations({
|
||||
instrumentations: [new GrpcInstrumentation()]
|
||||
});
|
||||
|
||||
if(process.env.ENABLE_TRACING == "1") {
|
||||
logger.info("Tracing enabled.")
|
||||
|
||||
const { resourceFromAttributes } = require('@opentelemetry/resources');
|
||||
|
||||
const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions');
|
||||
|
||||
const opentelemetry = require('@opentelemetry/sdk-node');
|
||||
|
||||
const { OTLPTraceExporter } = require('@opentelemetry/exporter-otlp-grpc');
|
||||
|
||||
const collectorUrl = process.env.COLLECTOR_SERVICE_ADDR;
|
||||
const traceExporter = new OTLPTraceExporter({url: collectorUrl});
|
||||
const sdk = new opentelemetry.NodeSDK({
|
||||
resource: resourceFromAttributes({
|
||||
[ ATTR_SERVICE_NAME ]: process.env.OTEL_SERVICE_NAME || 'currencyservice',
|
||||
}),
|
||||
traceExporter: traceExporter,
|
||||
});
|
||||
|
||||
sdk.start()
|
||||
}
|
||||
else {
|
||||
logger.info("Tracing disabled.")
|
||||
}
|
||||
|
||||
const path = require('path');
|
||||
const grpc = require('@grpc/grpc-js');
|
||||
const protoLoader = require('@grpc/proto-loader');
|
||||
|
||||
const MAIN_PROTO_PATH = path.join(__dirname, './proto/demo.proto');
|
||||
const HEALTH_PROTO_PATH = path.join(__dirname, './proto/grpc/health/v1/health.proto');
|
||||
|
||||
const PORT = process.env.PORT;
|
||||
|
||||
const shopProto = _loadProto(MAIN_PROTO_PATH).hipstershop;
|
||||
const healthProto = _loadProto(HEALTH_PROTO_PATH).grpc.health.v1;
|
||||
|
||||
/**
|
||||
* Helper function that loads a protobuf file.
|
||||
*/
|
||||
function _loadProto (path) {
|
||||
const packageDefinition = protoLoader.loadSync(
|
||||
path,
|
||||
{
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true
|
||||
}
|
||||
);
|
||||
return grpc.loadPackageDefinition(packageDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that gets currency data from a stored JSON file
|
||||
* Uses public data from European Central Bank
|
||||
*/
|
||||
function _getCurrencyData (callback) {
|
||||
const data = require('./data/currency_conversion.json');
|
||||
callback(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that handles decimal/fractional carrying
|
||||
*/
|
||||
function _carry (amount) {
|
||||
const fractionSize = Math.pow(10, 9);
|
||||
amount.nanos += (amount.units % 1) * fractionSize;
|
||||
amount.units = Math.floor(amount.units) + Math.floor(amount.nanos / fractionSize);
|
||||
amount.nanos = amount.nanos % fractionSize;
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the supported currencies
|
||||
*/
|
||||
function getSupportedCurrencies (call, callback) {
|
||||
logger.info('Getting supported currencies...');
|
||||
_getCurrencyData((data) => {
|
||||
callback(null, {currency_codes: Object.keys(data)});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts between currencies
|
||||
*/
|
||||
function convert (call, callback) {
|
||||
try {
|
||||
_getCurrencyData((data) => {
|
||||
const request = call.request;
|
||||
|
||||
// Convert: from_currency --> EUR
|
||||
const from = request.from;
|
||||
const euros = _carry({
|
||||
units: from.units / data[from.currency_code],
|
||||
nanos: from.nanos / data[from.currency_code]
|
||||
});
|
||||
|
||||
euros.nanos = Math.round(euros.nanos);
|
||||
|
||||
// Convert: EUR --> to_currency
|
||||
const result = _carry({
|
||||
units: euros.units * data[request.to_code],
|
||||
nanos: euros.nanos * data[request.to_code]
|
||||
});
|
||||
|
||||
result.units = Math.floor(result.units);
|
||||
result.nanos = Math.floor(result.nanos);
|
||||
result.currency_code = request.to_code;
|
||||
|
||||
logger.info(`conversion request successful`);
|
||||
callback(null, result);
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`conversion request failed: ${err}`);
|
||||
callback(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint for health checks
|
||||
*/
|
||||
function check (call, callback) {
|
||||
callback(null, { status: 'SERVING' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an RPC server that receives requests for the
|
||||
* CurrencyConverter service at the sample server port
|
||||
*/
|
||||
function main () {
|
||||
logger.info(`Starting gRPC server on port ${PORT}...`);
|
||||
const server = new grpc.Server();
|
||||
server.addService(shopProto.CurrencyService.service, {getSupportedCurrencies, convert});
|
||||
server.addService(healthProto.Health.service, {check});
|
||||
|
||||
server.bindAsync(
|
||||
`[::]:${PORT}`,
|
||||
grpc.ServerCredentials.createInsecure(),
|
||||
function() {
|
||||
logger.info(`CurrencyService gRPC server started on port ${PORT}`);
|
||||
server.start();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user