Hello i am creating an express service that prints to a pos printer at http request. The problem is that my solution does not print images on the first print but it does at the second and so on.
I am using https://github.com/song940/node-escpos
Here is my server.js
var print = require('./print')
var express = require('express')
var cors = require('cors')
var bodyParser = require('body-parser');
var app = express();
var corsOptions = {
origin: '*',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.get('/print', cors(corsOptions), (req, res) => {
print.demoPrint();
return res.send(req.body);
});
app.listen(3000, () => {
console.log('Express server is started')
});
Here is my print.js
const escpos = require('escpos');
const device = new escpos.USB(0x1504,0x003d);
const options = { encoding: "GB18030"};
const printer = new escpos.Printer(device);
const fs = require('fs')
const printSettings = JSON.parse(fs.readFileSync('printConfig.json', 'utf8'));
exports.demoPrint = () => {
device.open(function() {
printSettings.forEach((currentLine) => {
if(currentLine.printType === "text") {
console.log("PRINTING TEXT");
printer
.font(currentLine.font)
.align(currentLine.align)
.style('bu')
.size(currentLine.size, currentLine.size)
.text(currentLine.text)
}
else if(currentLine.printType === "image") {
escpos.Image.load(currentLine.path, (image) => {
console.log("PRINTING IMAGE");
printer
.align(currentLine.align)
.size(currentLine.size, currentLine.size)
.image(image)
});
}
else if(currentLine.printType === "barcode") {
console.log("PRINTING BARCODE");
printer
.align(currentLine.align)
.barcode(currentLine.text, 'CODE39', {
height: 64,
font: 'B'
});
}
});
printer
.text('\n')
.text('\n')
.cut()
.close();
});
};
Since this hasn't been answered yet I will provide the solution that worked for me. The problem was that the images were starting to load on the first time I submitted a request. By the second time I submitted a request the images were already loaded and were successfully printed.
I solved the problem by a adding a check that would not allow to print until the images were loaded.
Related
So first what i want to say, is that none of the public questions on stackoverflow did not helped me with this error. I am running the Stripe CLI on my local machine like this : stripe listen --forward-to localhost:4242/webhook , but weirdly when i try to proccess all the events inside i get the error :
No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
I have already tried using request.rawBody , but it didn't fix my issue.
I am posting all of the code, so maybe someone will see what i can't and help me fixing it
router.js :
let express = require('express');
let router = express.Router();
let bodyParser = require('body-parser')
let postMong = require('./post')
require("dotenv").config()
router.use(express.json());
const YOUR_DOMAIN = 'http://localhost:4242';
const stripe = require('stripe')(process.env.PUBLIC_KEY);
router.post('/checkout/create-order', async (req, res) => {
const price = req.body.order.stripe_price || undefined,
product = req.body.order.stripe_product || undefined
const session = await stripe.checkout.sessions.create({
shipping_address_collection: {
allowed_countries: ['US', 'CA'],
},
shipping_options: [
{
shipping_rate_data: {
type: 'fixed_amount',
fixed_amount: {
amount: 2499,
currency: 'usd',
},
display_name: 'International Shipping',
// Delivers between 5-7 business days
delivery_estimate: {
minimum: {
unit: 'week',
value: 2,
},
}
}
},
],
line_items: [
{
price: price,
quantity: 1,
},
],
payment_method_types: ["card", 'us_bank_account'],
mode: 'payment',
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/index.html`,
});
res.json({url: session.url})
});
router.post('/posts/add', async (req,res)=>{
try{
const {author, id, name, picture, pixels, price, size, stripe_price, stripe_product} = req.body
const pos = await postMong.create( {author, id, name, picture, pixels, price, size, stripe_price, stripe_product})
res.json(pos)
} catch(e){
res.status(500).json(e)
}
})
router.get('/ideas', async (req,res)=>{
try{
const posts = await postMong.find()
return res.json(posts);
} catch(e){
reject(res.status(500).json(e))
}
})
const endpointSecret = 'whsec_****';
const fulfillOrder = (session) => {
// TODO: fill me in
console.log("Fulfilling order", session);
}
router.use(bodyParser.json());
router.post('/webhook', (request, response) => {
const payload = request.body;
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);
console.log(event)
} catch (err) {
console.log(err.message)
return response.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the checkout.session.completed event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Fulfill the purchase...
fulfillOrder(session);
}
response.status(200);
});
module.exports = router
server.js :
const router = require("./router");
const account = require("./routerAccount");
const express = require('express');
const mongoose = require("mongoose")
const app = express();
const cors = require('cors')
var session = require('express-session');
require("dotenv").config()
const db_url = process.env.MONGO_URL
app.use(session({
cookie: {
httpOnly: true
},
rolling: true,
resave: true,
saveUninitialized: true,
secret: '~~~~~'
}));
app.set('view engine','ejs');
app.use(express.static('public'));
//app.use(express.json());
app.use(cors())
app.use('/', router)
app.use('/', account)
async function startApp(){
try{
await mongoose.connect(db_url, {
useUnifiedTopology: true,
useNewUrlParser:true
})
app.listen(4242, () => {console.log("server is working")})
} catch(e) {
console.log("some error appearead" + e)
}
}
startApp()
Normally when you see this error, it means that, either the HTTP request body Stripe sent to your webhook handler has been altered in some way or You may not be using the correct webhook secret.
The most likely reason it is throwing an exception is because your router is parsing body as JSON with router.use(express.json()). constructEvent requires the raw, unparsed body you receive from the request to verify the signature. To verify you have the raw body you can print it out and see if you get something like <Buffer 28 72 10..>
You can tell your router to keep the request body raw by setting something like this on your route router.use('/webhook', express.raw({type: "*/*"}))
I found the solution for my problem.
What i added is
app.use( "/webhook",express.raw({ type: "*/*" }))
in my server.js file.
I'm developing a custom embedded app with Node+React.
I followed the official tutorial but if I use the verifyRequest() middleware I always get the following error when I navigate through my app's pages:
Expected a valid shop query parameter
I really can't understand what's wrong with the code.
Could anyone please help me?
Below is the server.js code
require('isomorphic-fetch');
const dotenv = require('dotenv');
const Koa = require('koa');
const next = require('next');
const { default: shopifyAuth } = require('#shopify/koa-shopify-auth');
const { verifyRequest } = require('#shopify/koa-shopify-auth');
const { default: Shopify, ApiVersion } = require('#shopify/shopify-api');
const Router = require('koa-router');
const RedisSessionStorage = require('./middleware/RedisSessionStorage')
const Cookies = require('cookies')
dotenv.config();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SHOPIFY_API_SCOPES.split(","),
HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.April21,
IS_EMBEDDED_APP: true,
SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(
RedisSessionStorage.storeCallback,
RedisSessionStorage.loadCallback,
RedisSessionStorage.deleteCallback,
),
});
const port = parseInt(process.env.PORT, 10) || 3001;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const ACTIVE_SHOPIFY_SHOPS = {[process.env.ACTIVE_SHOPIFY_SHOP]: process.env.SHOPIFY_API_SCOPES}
app.prepare().then(() => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
shopifyAuth({
accessMode: 'offline',
afterAuth(ctx) {
const { shop, scope, accessToken } = ctx.state.shopify;
global.accessToken = accessToken
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
ctx.redirect(`/?shop=${shop}`);
},
}),
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.get("/", async (ctx) => {
const shop = ctx.query.shop;
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
});
router.get("(/_next/static/.*)", handleRequest);
router.get("/_next/webpack-hmr", handleRequest);
router.get("(.*)", verifyRequest({accessMode: 'offline'}), handleRequest);
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
Have you tried with the default SESSION_STORAGE?
It looks like it's directing to /auth
Deno seems targeting text files, but I also need to serve image files for the website.
You can use send()
The function send() is designed to serve static content as part of a
middleware function. In the most straight forward usage, a root is
provided and requests provided to the function are fulfilled with
files from the local file system relative to the root from the
requested path.
const app = new Application();
app.use(async (context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}/static`
});
});
await app.listen({ port: 8000 });
With the following directory structure:
static/
image.jpg
server.js
You can access the image by going to http://localhost:8000/image.jpg
Basically, you just need to set the correct headers for your image type, and supply the image data as a Unit8Array:
In your middleware:
app.use(async (ctx, next) => {
// ...
const imageBuf = await Deno.readFile(pngFilePath);
ctx.response.body = imageBuf;
ctx.response.headers.set('Content-Type', 'image/png');
});
Here's a complete working example, which will download a sample image (the digitized version of the hand-drawn deno logo) and serve it at http://localhost:8000/image, and display "Hello world" at all other addresses. The run options are in the comment on the first line:
server.ts
// deno run --allow-net=localhost:8000,deno.land --allow-read=deno_logo.png --allow-write=deno_logo.png server.ts
import {Application} from 'https://deno.land/x/oak#v5.3.1/mod.ts';
import {exists} from 'https://deno.land/std#0.59.0/fs/exists.ts';
// server listen options
const listenOptions = {
hostname: 'localhost',
port: 8000,
};
// sample image
const imageFilePath = './deno_logo.png';
const imageSource = 'https://deno.land/images/deno_logo.png';
const ensureLocalFile = async (localPath: string, url: string): Promise<void> => {
const fileExists = await exists(localPath);
if (fileExists) return;
console.log(`Downloading ${url} to ${localPath}`);
const response = await fetch(url);
if (!response.ok) throw new Error('Response not OK');
const r = response.body?.getReader;
const buf = new Uint8Array(await response.arrayBuffer());
await Deno.writeFile(imageFilePath, buf);
console.log('File saved');
};
await ensureLocalFile(imageFilePath, imageSource);
const app = new Application();
app.use(async (ctx, next) => {
// only match /image
if (ctx.request.url.pathname !== '/image') {
await next(); // pass control to next middleware
return;
}
const imageBuf = await Deno.readFile(imageFilePath);
ctx.response.body = imageBuf;
ctx.response.headers.set('Content-Type', 'image/png');
});
// default middleware
app.use((ctx) => {
ctx.response.body = "Hello world";
});
// log info about server
app.addEventListener('listen', ev => {
const defaultPortHttp = 80;
const defaultPortHttps = 443;
let portString = `:${ev.port}`;
if (
(ev.secure && ev.port === defaultPortHttps)
|| (!ev.secure && ev.port === defaultPortHttp)
) portString = '';
console.log(`Listening at http${ev.secure ? 's' : ''}://${ev.hostname ?? '0.0.0.0'}${portString}`);
console.log('Use ctrl+c to stop\n');
});
await app.listen(listenOptions);
Register middleware like this:
// serve static files
app.use(async (context, next) => {
try {
await context.send({
root: `${Deno.cwd()}/wwwroot/static`,
index: "index.html",
});
} catch {
await next();
}
});
I'm trying to create a simple slackbot and I can get the thing to run on start and almost anything else, but it will not pick up incoming messages from any channel. It's not generating any errors what so ever which makes it very frusterating.
things I've tried so far:
adding the bot to the channel
console logging inside the message block
adding a catch
No matter what I do the bot seems to just outright ignore the prompt "on.message". I don't get it. My code is below.
require("dotenv").config();
const { WebClient } = require("#slack/web-api");
const { createEventAdapter } = require("#slack/events-api");
const slackEvents = createEventAdapter(process.env.SLACK_SIGNING_SECRET);
const { RTMClient } = require("#slack/rtm-api");
const axios = require('axios')
const sgMail = require("#sendgrid/mail");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const express = require("express");
const bodyParser = require("body-parser");
const pool = require("./pool");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("build"));
let config = {
headers: {
"X-Auth-Client": process.env.BG_AUTH_CLIENT,
"X-Auth-Token": process.env.BG_AUTH_TOKEN,
},
};
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log("server running on: ", PORT);
});
const token = process.env.SLACK_TOKEN;
const web = new WebClient(token);
const conversationId = "C0139RJPUEM";
// The client is initialized and then started to get an active connection to the platform
const rtm = new RTMClient(token);
slackEvents.on('error', console.error);
slackEvents.start().then(() => {
(async () => {
const res = await web.chat.postMessage({
icon_emoji: ":email:",
channel: conversationId,
text: "Testing connection",
});
message
console.log("Message sent: ", res.ts);
})();
console.log("bot listening on port", PORT);
});
slackEvents.on("message", (event) => {
console.log(
`Received a message event: user ${event.user} in channel ${event.channel} says ${event.text}`
);
(async () => {
// See: https://api.slack.com/methods/chat.postMessage
const res = await web.chat.postMessage({
icon_emoji: ":email:",
channel: conversationId,
text: "Testing message",
});
// `res` contains information about the posted message
console.log("Message sent: ", res.ts);
})();
// }
});
I think I got it, I was using a library that was not compatible, plus I didn't set up API event subscriptions and a few other dumb things. Oh well. Hopefully this will help someone who might casually come across this.
I am trying to upload image from my react native app to graphql by using Apollo client with createUploadLink(). When I am trying to mutate data by passing a ReactNativeFile as a variable, then it says
"network request failed: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. at new ApolloError ".
This this the mutation which i am trying to use
mutation publishPost(
$content: String!
$LocationInput: LocationInput!
$InputPostAttachment: [InputPostAttachment!]
) {
publishPost(
content: $content
location: $LocationInput
attachments: $InputPostAttachment
) {
content
}
}
InputPostAttachment has type
type InputPostAttachment {
type: PostAttachmentType!
file: Upload!
}
Apollo client settings and i am using apollo-upload-client
const httpLink = createUploadLink({
uri: 'http://localhost:8000/graphql',
});
const authLink = setContext(async (headers: any) => {
const token = await getToken();
return {
...headers,
headers: {
authorization: token ? `Bearer ${token}` : null,
},
};
});
const link = authLink.concat(httpLink);
// create an inmemory cache instance for caching graphql data
const cache = new InMemoryCache();
// instantiate apollo client with apollo link instance and cache instance
export const client = new ApolloClient({
link,
cache,
});
File upload Function and i am using react-native-image-crop-picker for multi image selection
const [image, setimage] = useState([]);
const _pickImage = () => {
ImagePicker.openPicker({
includeBase64: true,
multiple: true,
}).then((images: any) => {
let imageData: any = [];
images.map((data: any) => {
const file = new ReactNativeFile({
uri: data.path,
name: data.filename,
type: data.mime,
});
imageData.push({
type: 'IMAGE',
file: file,
});
});
setimage(imageData);
console.log(images);
});
};
const handlePost = async () => {
const InputPostAttachment: any = [...image];
const LocationInput = {
place: place,
vicinity: vicinity,
province: province,
};
publishPost({variables: {content, LocationInput, InputPostAttachment}})
.then(({data}) => {
console.log(data);
props.navigation.navigate('Home');
})
.catch((err) => {
console.log('err happened');
console.log(err);
});
};
could someone please help me out from this?
In addition to the chrome debugger issue, this error also happens on the expo web.
To anyone uploading images on expo web (or react-native web), here's a working solution:
/** Load image from camera/roll. */
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
quality: 1,
});
if (result.cancelled) {
return;
}
/** web platform: blob. */
const convertBase64ToBlob = async (base64) => {
const response = await fetch(base64);
const blob = await response.blob();
return blob;
};
/** android/ios platform: ReactNativeFile.*/
const createReactNativeFile = (uri) => {
const file = new ReactNativeFile({
uri,
type: mime.lookup(uri) || 'image',
name: `file-${Date.now()}`,
});
return file;
};
/** Use blob for web, ReactNativeFile otherwise. */
const file = Platform.OS === 'web'
? await convertBase64ToBlob(result.uri)
: createReactNativeFile(result.uri);
/** Upload image with apollo. */
mutate({ variables: { file } });
On the web platform, ImagePicker returns a base64 value instead of a file path. This problem doesn't happen if the platform is Android or iOS, as ImagePicker returns a file path, which is expected by apollo-upload-client.
The solution is to detect if the URI is base64 (which happens when the platform is "web") and convert it to a blob.
My apollo-client was configured using apollo-boost and i was using chrome debugger to intercept the network was causing me this issue.
To be more specific I was using the below code to get the network requests sent by my app in the chrome debugger
global.XMLHttpRequest =
global.originalXMLHttpRequest || global.XMLHttpRequest;
global.FormData = global.originalFormData || global.FormData;
if (window.FETCH_SUPPORT) {
window.FETCH_SUPPORT.blob = false;
} else {
global.Blob = global.originalBlob || global.Blob;
global.FileReader = global.originalFileReader || global.FileReader;
}
apollo-upload-client wont send the data in multipart data if we are using chrome debugger. We will face network issue.This issue has the answer. or I had not removed apollo-boost and some part of my app was using it that was also a issue.