Referencing messages of other .proto files - import

I have seen there already similar problems published, I could not resolve the problem with the solutions proposed.
I am struggeling to reference a proto in another proto file.
I have the .proto file example.proto that is referencing A.proto in the dependency folder, example.proto is placed next to the dependency folder.
A.proto
syntax = "proto3";
package dependency;
message AttributeA {
// Some attribute.
string body = 1;
}
example.proto
syntax = "proto3";
import "src/proto_test/dependency/A.proto";
package example;
message CheckRequest {
// The request attributes.
int32 id = 1;
dependency.AttributeA att = 2;
}
The server file looks as following:
Server
const grpc = require("#grpc/grpc-js");
const PROTO_PATH = "./src/proto_test/example.proto";
var protoLoader = require("#grpc/proto-loader");
const options = {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: [path.join(__dirname,"/proto_test/dependency")]
};
var packageDefinition = protoLoader.loadSync(PROTO_PATH, options);
const proto = grpc.loadPackageDefinition(packageDefinition);
const server = new grpc.Server();
server.bindAsync(
"127.0.0.1:50054",
grpc.ServerCredentials.createInsecure(),
(error, port) => {
console.log("Server running at http://127.0.0.1:50054");
server.start();
}
);
Error
Error: no such Type or Enum 'dependency.AttributeA' in Type .example.CheckRequest#
Is there anything wrong with this code?

I do not know exactly why, but this code is working:
example.proto
syntax = "proto3";
import "dependency/A.proto";
package example;
message CheckRequest {
// The request attributes.
int32 id = 1;
dependency.AttributeA att = 2;
}
Server
const grpc = require("#grpc/grpc-js");
const PROTO_PATH = "example.proto";
var protoLoader = require("#grpc/proto-loader");
var path = require('path')
const options = {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs: [
path.join(__dirname,"/proto_test/dependency"),
path.join(__dirname,"/proto_test")]
};
var packageDefinition = protoLoader.loadSync(PROTO_PATH, options);
console.log(packageDefinition);
const proto = grpc.loadPackageDefinition(packageDefinition);
const server = new grpc.Server();
server.bindAsync(
"127.0.0.1:50054",
grpc.ServerCredentials.createInsecure(),
(error, port) => {
console.log("Server running at http://127.0.0.1:50054");
server.start();
}
);

Related

trying to get uploads saving in MongoDB

I currently have the following code, which saves the temp file to public/files I have tried to understand the MongoDB GridFS documentation but with no success.
I am wondering how do I get the files to save inside MongoDB GridFS instead of my public/file directory
I am aware I am missing the part where I need to send the uploaded file to mongodb - this is the part I don't know how to do.
In mongodb example they say to do something like:
fs.createReadStream('./myFile').pipe(
bucket.openUploadStream('myFile', {
chunkSizeBytes: 1048576,
metadata: { field: 'myField', value: 'myValue' },
})
);
however I am not using FS or do I need to upload the file to the temp and then do the fs
import formidable from 'formidable';
import { MongoClient, ObjectId } from 'mongodb';
var Grid = require('gridfs-stream');
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
const uri = process.env.MONGODB_URI;
let client;
let clientPromise;
const options = {};
client = new MongoClient(uri, options);
clientPromise = client.connect();
const clients = await clientPromise;
const database = clients.db('AdStitchr');
var gfs = Grid(database, client);
gfs.collection('uploads');
const form = new formidable.IncomingForm();
form.uploadDir = 'public/files';
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
var file = files.file;
console.log(JSON.stringify(file));
try {
const newFile = File.create({
name: `files\${file.newFilename}.mp3`,
});
res.status(200).json({ status: 'success' });
} catch (error) {
res.send(error);
}
});
};

NEXT, upload file along with metadata (Axios and Formidable with Node JS)

I want to upload a file to NEXT apis along with metadata:
const data = new FormData();
data.append('file', file);
data.append('body', JSON.stringify({ hello: 'world' }));
console.log('Sending');
axios
.post('/api/test-route', data, {
headers: {
'content-type': 'multipart/form-data',
'Authorization': 'json-token',
},
})
.then((response: AxiosResponse) =>
console.log('data = ', response.data)
)
.catch((error: unknown) => console.log(error));
Here's my API Code:
// Backend
import formidable from 'formidable';
import { NextApiRequest, NextApiResponse } from 'next';
import {
errorResponse,
genericResponse,
getErrorDetailsFromKey,
} from '#global-backend/utils/api/responseSynthesizer';
import {
ErrorCodes,
IResponse,
} from '#constants/interfaces/gcorn/backend/apis/response.interfaces';
export const config = {
api: {
bodyParser: false,
},
};
// eslint-disable-next-line import/no-anonymous-default-export
export default async (req: NextApiRequest, res: NextApiResponse) => {
const form = new formidable.IncomingForm();
//#ts-ignore
form.uploadDir = './'; //#ts-ignore
form.keepExtensions = true;
const opsDetails = getErrorDetailsFromKey(
ErrorCodes.INVALID_OR_CORRUPTED_FILE
);
let response = errorResponse({ opsDetails });
let status_code = 400;
const payload: { response: IResponse; status_code: number; error: boolean } =
await new Promise((resolve) => {
let flag = 0;
form.parse(req, (err, _, files) => {
const isError = err?.message !== undefined;
if (isError) {
response = errorResponse({
message: err.message,
opsDetails,
});
status_code = 400;
}
console.log('Files = ', Object.keys(files.file));
const fileCheck = checkImageFileValidity(files.file as unknown as File);
if (fileCheck.error) {
opsDetails.details = fileCheck.message;
response = errorResponse({
message: fileCheck.message,
opsDetails,
});
status_code = 400;
}
response = genericResponse({
status_code: 201,
opsDetails: getErrorDetailsFromKey(
ErrorCodes.FUNFUSE_PROFILE_UPDATE_SUCESS
),
});
status_code = 201;
flag = 1;
resolve({ response, status_code, error: false });
});
});
return res.status(payload.status_code).json(payload.response);
};
const checkImageFileValidity = (
file: File
): { error: boolean; message: string } => {
const { type, size } = file;
// Must be less than 5MBs in Size and Must be Image File
if (size > 5000000)
return { error: true, message: 'File Size More than 5MBs' };
if (!type.includes('image'))
return { error: true, message: 'File is not an image' };
return { error: false, message: 'File is valid' };
};
But for some reason, I don't know how can I parse body part of my form which extracts the info: {hello:world}.
Does anyone know a way to parse it and collect in the backend ?
Assuming everything else is correct, you need to check the _ variable

MessageCreate.js prefix issues with database - Discord.js v13/MongoDB

I have this code in my messageCreate event:
// MODULES
const Discord = require('discord.js');
const mongoose = require('mongoose');
const Levels = require('discord.js-leveling');
// FILES
const Guild = require('../../models/guild');
const config = require('../../files/config.json');
const swearwords = require("../../files/data.json");
const colors = require('../../files/colors.json');
// ERROR MESSAGE
const errorMain = new Discord.MessageEmbed()
.setDescription("There was an error!")
.setColor(colors.COLOR)
const addedDatabase = new Discord.MessageEmbed()
.setDescription("This server is now added to our database.")
.setColor(colors.COLOR)
module.exports = async (Discord, client, message) => {
if (!message.guild) return;
if (message.author.bot) return;
const settings = await Guild.findOne({
guildID: message.guild.id
}, (err, guild) => {
if (err) message.channel.send(errorMain);
if (!guild) {
const newGuild = new Guild({
_id: mongoose.Types.ObjectId(),
guildID: message.guild.id,
prefix: config.PREFIX,
logChannelID: String,
enableLog: false,
enableSwearFilter: true,
enableMusic: true,
enableLevel: true,
});
newGuild.save()
.catch(err => message.channel.send(errorMain));
return message.channel.send({embeds: [addedDatabase]}).then(m => m.delete({ timeout: 10000 }))
}
});
// VARIABLES
const IDGuild = message.guild.id;
const user = message.author;
const prefix = settings.prefix;
const swearFilterOn = settings.enableSwearFilter;
// LEVEL SYSTEM
if (settings.enableLevel === "true") {
const requiredXp = Levels.xpFor(parseInt(user.level) + 1)
const randomAmountOfXp = Math.floor(Math.random() * 29) + 1;
const hasLeveledUp = await Levels.appendXp(message.author.id, message.guild.id, randomAmountOfXp);
if (hasLeveledUp) {
const user = await Levels.fetch(message.author.id, message.guild.id);
const levelEmbed = new Discord.MessageEmbed()
.setTitle('New Level!')
.setColor(colors.COLOR)
.setDescription(`**GG** ${message.author}, you just leveled up to level **${user.level}**!\nContiune to chat to level up again.`)
const sendEmbed = await message.channel.send({embeds: [levelEmbed]});
}
}
// EXECUTE COMMAND AND SWEARFILTER
if (swearFilterOn === "true") {
var msg = message.content.toLowerCase();
for (let i = 0; i < swearwords["swearwords"].length; i++) {
if (msg.includes(swearwords["swearwords"][i])) {
message.delete();
return message.channel.send("Please do not swear.").then(msg => msg.delete({ timeout: 3000 }));
}
}
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) ||
client.commands.find(a => a.aliases && a.aliases.includes(cmd));;
if (command) command.execute(client, message, args, Discord)
} else {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) ||
client.commands.find(a => a.aliases && a.aliases.includes(cmd));;
if (command) command.execute(client, message, args, Discord)
}
}
And when i send a message right after the bot joines the discord, it gives the error that it cannot read properties of null (reading 'prefix').
The bot crashes, and when it's restarted it works because it has been added to the Database. So how can i fix that when it sends the first message it can still read 'prefix'. its probably a database issue.
I was told that settings.prefix probaly wasn't assinged a value, is there a way to fix this?
I'm using mongodb for my database.
You really should assign the prefix right after the bot joins new server with guildCreate event. It may cause some issues if your database is down etc. When you wait till the message event

MongoDB doesn't add a new user after previous request with UNIQUE referral code. MongoDB webpage "REFRESH" helps only. What I did wrong?

Auth.js (CONTROLLER):
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const User = require('../models/User')
const keys = require('../config/keys')
const errorHandler = require('../utils/errorHandler')
// REGISTRATION
module.exports.register = async function(req, res) {
const candidate = await User.findOne({email: req.body.email})
const phone = await User.findOne({phone: req.body.phone})
if (candidate) {
// user exist
res.status(409).json({
message: 'Email is taken. Try another one!'
})
} else {
// new user
const salt = bcrypt.genSaltSync(10)
const password = req.body.password
const user = new User({
username: req.body.username,
password: bcrypt.hashSync(password, salt),
})
try {
await user.save()
res.status(201).json(user)
} catch(e) {
errorHandler(res, e)
}
}
}
Auth.js (ROUTES):
const express = require('express')
const controller = require('../controllers/auth')
const router = express.Router()
//localhost:5000/api/auth/register
router.post('/register', controller.register)
module.exports = router
User.js(MODEL):
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
username: {
type: String,
unique: false
},
password: {
type: String,
required: true
},
codeRef: {
type: String,
default: makeid(6).toString(),
unique: true
}
})
// GENERATE RANDOM REFFERAL LINK
function makeid(length) {
var result = ''
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
var charactersLength = characters.length
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength))
}
return result
}
module.exports = mongoose.model('users', userSchema)
Everything works fine, the new user added successfully.
The problem comes with another added user after the first one. Generated referral code gives error until we refresh the MongoDB database or restart the server (NPM).
(Results from POSTMAN)
{
"success": false,
"message": "E11000 duplicate key error collection: Cluster.users index: codeRef_1 dup key: { codeRef: \"DDP1SF\" }"
}
Logs from console:
POST /api/auth/register 201 457.563 ms - 350
POST /api/auth/register 500 304.148 ms - 142
POST /api/auth/register 500 190.155 ms - 142
Tried to change the const to var... Should I clear the Schema data of previous request somehow? Because my generated random code for 6 symbols is the same until refresh.
MODELS should NOT contain functions because they are static.
Placing the function inside CONTROLLER file did the work.
// GENERATE RANDOM REFFERAL LINK
function makeid(length) {
var result = ''
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
var charactersLength = characters.length
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength))
}
return result
}
To show the response after the server was updated, use new: true :
const user = new User({
username: req.body.username,
password: bcrypt.hashSync(password, salt),
codeRef: makeid(6).toString(),
new: true
})

Angular 6 Downloading file from rest api

I have my REST API where I put my pdf file, now I want my angular app to download it on click via my web browser but I got HttpErrorResponse
"Unexpected token % in JSON at position 0"
"SyntaxError: Unexpected token % in JSON at position 0↵ at JSON.parse (
this is my endpoint
#GetMapping("/help/pdf2")
public ResponseEntity<InputStreamResource> getPdf2(){
Resource resource = new ClassPathResource("/pdf-sample.pdf");
long r = 0;
InputStream is=null;
try {
is = resource.getInputStream();
r = resource.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok().contentLength(r)
.contentType(MediaType.parseMediaType("application/pdf"))
.body(new InputStreamResource(is));
}
this is my service
getPdf() {
this.authKey = localStorage.getItem('jwt_token');
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/pdf',
'Authorization' : this.authKey,
responseType : 'blob',
Accept : 'application/pdf',
observe : 'response'
})
};
return this.http
.get("http://localhost:9989/api/download/help/pdf2", httpOptions);
}
and invocation
this.downloadService.getPdf()
.subscribe((resultBlob: Blob) => {
var downloadURL = URL.createObjectURL(resultBlob);
window.open(downloadURL);});
I resolved it as follows:
// header.component.ts
this.downloadService.getPdf().subscribe((data) => {
this.blob = new Blob([data], {type: 'application/pdf'});
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement('a');
link.href = downloadURL;
link.download = "help.pdf";
link.click();
});
//download.service.ts
getPdf() {
const httpOptions = {
responseType: 'blob' as 'json')
};
return this.http.get(`${this.BASE_URL}/help/pdf`, httpOptions);
}
I solved the issue in this way (please note that I have merged multiple solutions found on stack overflow, but I cannot find the references. Feel free to add them in the comments).
In My service I have:
public getPDF(): Observable<Blob> {
//const options = { responseType: 'blob' }; there is no use of this
let uri = '/my/uri';
// this.http refers to HttpClient. Note here that you cannot use the generic get<Blob> as it does not compile: instead you "choose" the appropriate API in this way.
return this.http.get(uri, { responseType: 'blob' });
}
In the component, I have (this is the part merged from multiple answers):
public showPDF(fileName: string): void {
this.myService.getPDF()
.subscribe(x => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([x], { type: "application/pdf" });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob, fileName);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
link.href = data;
link.download = fileName;
// this is necessary as link.click() does not work on the latest firefox
link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data);
link.remove();
}, 100);
});
}
The code above works in IE, Edge, Chrome and Firefox. However, I don't really like it, as my component is pulluted with browser specific stuff which will surely change over time.
For Angular 12+, I came up with something like this:
this.ApiService
.getFileFromApi()
.pipe(take(1))
.subscribe((response) => {
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(new Blob([response.body], { type: response.body.type }));
const contentDisposition = response.headers.get('content-disposition');
const fileName = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();
downloadLink.download = fileName;
downloadLink.click();
});
The subscribe is on a simple get() with the Angular HttpClient.
// api-service.ts
getFileFromApi(url: string): Observable<HttpResponse<Blob>> {
return this.httpClient.get<Blob>(this.baseApiUrl + url, { observe: 'response', responseType: 'blob' as 'json'});
}
You can do it with angular directives:
#Directive({
selector: '[downloadInvoice]',
exportAs: 'downloadInvoice',
})
export class DownloadInvoiceDirective implements OnDestroy {
#Input() orderNumber: string;
private destroy$: Subject<void> = new Subject<void>();
_loading = false;
constructor(private ref: ElementRef, private api: Api) {}
#HostListener('click')
onClick(): void {
this._loading = true;
this.api.downloadInvoice(this.orderNumber)
.pipe(
takeUntil(this.destroy$),
map(response => new Blob([response], { type: 'application/pdf' })),
)
.subscribe((pdf: Blob) => {
this.ref.nativeElement.href = window.URL.createObjectURL(pdf);
this.ref.nativeElement.click();
});
}
// your loading custom class
#HostBinding('class.btn-loading') get loading() {
return this._loading;
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
In the template:
<a
downloadInvoice
[orderNumber]="order.number"
class="btn-show-invoice"
>
Show invoice
</a>
My answer is based on #Yennefer's, but I wanted to use the file name from the server since I didn't have it in my FE. I used the Content-Disposition header to transmit this, since that is what the browser uses for a direct download.
First, I needed access to the headers from the request (notice the get method options object):
public getFile(): Observable<HttpResponse<Blob>> {
let uri = '/my/uri';
return this.http.get(uri, { responseType: 'blob', observe: 'response' });
}
Next, I needed to extract the file name from the header.
public getFileName(res: HttpResponse<any>): string {
const disposition = res.headers.get('Content-Disposition');
if (!disposition) {
// either the disposition was not sent, or is not accessible
// (see CORS Access-Control-Expose-Headers)
return null;
}
const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; |$)/;
const asciiFilenameRegex = /filename=(["'])(.*?[^\\])\1(?:; |$)/;
let fileName: string = null;
if (utf8FilenameRegex.test(disposition)) {
fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
} else {
const matches = asciiFilenameRegex.exec(disposition);
if (matches != null && matches[2]) {
fileName = matches[2];
}
}
return fileName;
}
This method checks for both ascii and utf-8 encoded file names, prefering utf-8.
Once I have the file name, I can update the download property of the link object (in #Yennifer's answer, that's the lines link.download = 'FileName.ext' and window.navigator.msSaveOrOpenBlob(newBlob, 'FileName.ext');)
A couple of notes on this code:
Content-Disposition is not in the default CORS whitelist, so it may not be accessible from the response object based on the your server's configuration. If this is the case, in the response server, set the header Access-Control-Expose-Headers to include Content-Disposition.
Some browsers will further clean up file names. My version of chrome seems to replace : and " with underscores. I'm sure there are others but that's out of scope.
//Step: 1
//Base Service
this.getPDF() {
return this.http.get(environment.baseUrl + apiUrl, {
responseType: 'blob',
headers: new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Authorization': localStorage.getItem('AccessToken') || ''
})
});
}
//Step: 2
//downloadService
getReceipt() {
return new Promise((resolve, reject) => {
try {
// {
const apiName = 'js/getReceipt/type/10/id/2';
this.getPDF(apiName).subscribe((data) => {
if (data !== null && data !== undefined) {
resolve(data);
} else {
reject();
}
}, (error) => {
console.log('ERROR STATUS', error.status);
reject(error);
});
} catch (error) {
reject(error);
}
});
}
//Step 3:
//Component
getReceipt().subscribe((respect: any) => {
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement(‘a’);
link.href = downloadURL;
link.download = “sample.pdf";
link.click();
});
This also works in IE and Chrome, almost the same answer only for other browsers the answer is a bit shorter.
getPdf(url: string): void {
this.invoiceService.getPdf(url).subscribe(response => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
const newBlob = new Blob([(response)], { type: 'application/pdf' });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const downloadURL = URL.createObjectURL(newBlob);
window.open(downloadURL);
});
}