manager.js
复制代码
require('dotenv').config()
const express = require('express')
const app = express()
const http = require('http').Server(app)
const io = require('socket.io')(http)
const socket_api = require('socket.io-client')('http://192.168.1.10:3000')
// const socket_api = require('socket.io-client')('http://nexon25.synology.me:3000')
//global constant
const port = 1234
const Printer = require('./printer')
let printer = new Printer()
//server init
http.listen(port, "0.0.0.0", function() {
console.log('listening on :', port)
})
// printer.printTest(function(){
// console.log('printing done');
// })
// printer.printTest()
let userData = {}
// [---------------SOCKET COMMUNICATION WITH API-----------------------------------]
// Listen to Tagging
socket_api.on(process.env.NAME, function(data) {
// socket_api.on(process.env.NAME, function(data) {
// console.log(data);
// Parse User Data into an Object from API into Printable & Reusable format.
// console.log(data);
if (data.isNexonAccount) {
userData.isNexonAccount = true
console.log('Nexon user data received');
let registeredTime = new Date(data.nexonData.user.registeredAt)
userData.registeredDate = `${registeredTime.getFullYear()}-${registeredTime.getMonth()+1}-${registeredTime.getDate()}`
userData.favoriteGame = data.nexonData.user.favoriteGameGenre
userData.gameData = data.nexonData.games
}else{
userData.isNexonAccount = false
console.log('Non-Nexon user data received');
}
// console.log(data);
let loginDateTime = new Date(data.loginDate)
let logoutDateTime = new Date(Date.now())
let quests = []
let questResults = []
let completedQuest = []
let failedQuest = []
for (quest of data.quests) {
if (quest.name !== 'logout1' && quest.name !== 'logout2') {
quests.push(quest.longName)
questResults.push(quest.isCompleted)
if (quest.isCompleted)
completedQuest.push(quest.longName)
else
failedQuest.push(quest.longName)
}
}
userData.quests = quests
userData.questResults = questResults
userData.username = data.username
userData.userLang = data.language
userData.characterId = data.quests[0].extra
userData.today = `${logoutDateTime.getFullYear()}-${logoutDateTime.getMonth()+1}-${logoutDateTime.getDate()}`
userData.playtime = `${loginDateTime.getHours()}:${loginDateTime.getMinutes()} - ${logoutDateTime.getHours()}:${logoutDateTime.getMinutes()}(${Math.floor(Number(Date.now() - Date.parse(data.loginDate))/60000)}m)`
userData.questCount = completedQuest.length + failedQuest.length // no logout in quests
userData.completedQuest = completedQuest
userData.failedQuest = failedQuest
// Nexon Game Coupon Data
let couponGame = []
let couponCode = []
for (coupon of data.coupons){
couponGame.push(coupon.name)
couponCode.push(coupon.code)
}
userData.couponGame = couponGame
userData.couponCode = couponCode
// printer.printTest()
// Send Tag signal to Unity App
// printer.printUserData(userData, function(){
// console.log('priting done');
// })
io.emit('logout-tagging', {
"userData": userData
})
})
//-------------------------------------------LOCAL APP--------------------------------------------------//
io.on('connection', function(socket) {
console.log('logout app connected');
//---------------------------------------- FROM APP -------------------------------------------------//
// Listen to APP to Print Receipt
socket.on('print-receipt', function(data) {
console.log('printing')
// let printer = new Printer()
// printer.unityPrintTest()
// Print Receipt
printer.isPrinting = true
printer.printUserData(userData, function(){
console.log('priting end');
socket.emit('printing-done', {
"print":"done"
})
})
// Catch the end of printing process. => let the API knows.
})
socket.on('end-of-experience', function(data) {
socket_api.emit('experience', {
"experience": process.env.NAME,
"data": "experience"
})
})
})
//------------------------------------------------------------------------------------------------------//
//----------------------------------------NODE MANAGER--------------------------------------------------//
//------------------------------------------------------------------------------------------------------//
//pre-exit scripts
let preExit = []
//catch exit
process.stdin.resume()
process.on('exit', code => {
let i
console.log('Process exit')
for (i = 0; i < preExit.length; i++) {
preExit[i](code)
}
process.exit(code)
})
//catch CTRL+C
process.on('SIGINT', () => {
process.exit(0)
})
//catch uncaught exception
process.on('uncaughtException', err => {
console.dir(err, {
depth: null
})
})
//catch unhandledRejection
process.on('unhandledRejection', error => {
console.log('unhandledRejection', error.message);
});
//add pre-exit script
preExit.push(code => {
console.log('Exit code %d, cleaning up...', code)
})
printer.js
复制代码
let options = {
encoding: "EUC-KR"
}
// const printerPort = process.env.COM
const printerPort = process.env.COM
const escpos = require('escpos')
let nexonLogo = '_data/NexonFoundation_en.png'
class Printer {
constructor() {
this.isPrinting = false
}
printUserData(userData, callback) {
let device, printer
let options = {
encoding: "EUC-KR"
}
// console.log('on printer',userData);
device = new escpos.Serial(printerPort)
printer = new escpos.Printer(device, options)
console.log('printer is working');
escpos.Image.load(nexonLogo, (image) => {
device.open(() => {
printer
.align('lt')
.text('\n')
.text('\n')
.size(2, 2)
.style('b')
.spacing(0)
// Exhibition Logo
.lineSpace(24)
.align('ct')
.text('Game ')
.text('a ')
.text(' me ')
.text('/i nvi te')
.text(' yo u_ ')
.align('lt')
.text('\n')
.text('\n')
.text('\n')
//ExhibitionAchivement
.size(2, 2)
.align('lt')
.style('b')
.lineSpace(28)
.lineSpace(35)
.text('EXHIBITION ARCHIVE')
//ExhibitionData
.size(1, 1)
.style('normal')
.align('lt')
.lineSpace(35)
.text('ID:' + userData.username)
.text('DATE:' + userData.today)
.text('PLAYTIME:' + userData.playtime)
.lineSpace(42)
.text('QUEST:' + userData.completedQuest.length + '/' + userData.questCount)
.lineSpace(35)
// Quest Accomplishment
// Completed Quest
.size(1, 1)
.align('lt')
.style('b')
.lineSpace(34)
.style('normal')
this.userCompletedQuestPrint(userData, printer)
printer
// Failed Quest
.style('b')
.style('normal')
this.userFailedQuestPrint(userData, printer)
// for Users has Nexon Game Data
if(userData.isNexonAccount){
printer
.text('\n')
// Nexon Archive
// Nexon Data Header
.size(2, 2)
.align('lt')
.lineSpace(35)
.style('b')
.text('NEXON ARCHIVE')
.size(1, 1)
.style('normal')
.align('lt')
.text('ID:' + userData.username)
.text('SINCE ' + userData.registerdDate)
.text('FAVORITE(2019): ' + userData.favoriteGame)
.size(1, 1)
.lineSpace(34)
this.userGamePrint(userData, printer)
}
printer
.text('')
.text('\n')
.align('ct')
.size(1, 1)
.style('b')
.text('THANKS FOR PLAYING GAME!')
.size(1, 1)
.lineSpace(28)
.text('\n')
for(let i = 0; i < 5; i++){
printer
.lineSpace(28)
.size(1,1)
.align('ct')
// .style('b')
.text(userData.couponGame[i])
.style('normal')
.align('ct')
.size(1,1)
.lineSpace(50)
.text(userData.couponCode[i])
}
printer
.lineSpace(50)
.align('ct')
.text('\n')
.size(1, 1)
.raster(image)
.text('\n')
.cut()
.close(() => {
callback()
})
})
})
}
userCompletedQuestPrint(userData, printer) {
let calcDotsBetweenText = this.calcDotsBetweenText.bind(this)
for (let i = 0; i < userData.completedQuest.length; i++) {
printer
.text('[' + userData.completedQuest[i] + ']' + calcDotsBetweenText(42, '[' + userData.completedQuest[i] + ']', 'Completed') + 'Completed')
}
}
userFailedQuestPrint(userData, printer) {
let calcDotsBetweenText = this.calcDotsBetweenText.bind(this)
for (let i = 0; i < userData.failedQuest.length; i++) {
printer
.text('[' + userData.failedQuest[i] + ']' + calcDotsBetweenText(42, '[' + userData.failedQuest[i] + ']', 'Failed') + 'Failed')
}
}
userGamePrint(userData, printer) {
for (const [i, game] of userData.gameData.entries()) {
printer
.text('{')
.text(' "gameName": ' + game.gameName + ',')
.text(' "mainCharaterId": ' + game.mainCharaterId + ',')
.text(' "mainCharacterNickname": ' + game.mainCharacterNickname + ',')
.text(' "mainCharacterTribe": ' + game.mainCharacterTribe + ',')
.text(' "mainCharacterClass": ' + game.mainCharacterClass + ',')
.text(' "mainCharacterLevel": ' + game.mainCharacterLevel + ',')
.text(' "numCharacter": ' + game.numCharacter + ',')
.text(' "PlayTimeInMinutes": ' + game.PlayTimeInMinutes + ',')
.text(' "mainCharacterCreatedAt": ')
.text(' ' + game.mainCharacterCreatedAt)
if ((i + 1) == (userData.gameData.length))
printer
.text('}')
else
printer
.text('},')
}
}
calcDotsBetweenText(rowSpacesCount, leftText, rightText) {
let dots = ''
let remainingSpace = rowSpacesCount - Number(leftText.length) - Number(rightText.length)
for (var i = 0; i < remainingSpace; i++) {
dots += '.'
}
return dots
}
endOfPrinting(){
console.log('Printing ends')
isPrinting = false;
}
printTest(callback) {
let device, printer
let options = {
encoding: "EUC-KR"
}
device = new escpos.Serial(printerPort)
printer = new escpos.Printer(device, options)
console.log('printer is working');
device.open(function() {
printer
.size(1, 1)
.align('lt')
.text('\n')
.text('\n')
.style('b')
.text('printer testing')
.text('printer testing')
.text('printer testing')
.text('printer testing')
.text('printer testing')
.text('\n')
.text('\n')
.text('\n')
.cut()
.close(() => {
callback()
})
})
}
}
module.exports = Printer
package.json
复制代码
{
"name": "nexon-expo25-logout",
"version": "0.0.1",
"description": "server application for logout kiosk",
"main": "manager.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "jonghyeon",
"license": "ISC",
"dependencies": {
"@babel/runtime": "^7.5.4",
"body-parser": "^1.19.0",
"canvas": "^2.5.0",
"dotenv": "^8.0.0",
"escpos": "^2.4.11",
"express": "^4.17.1",
"floyd-steinberg": "^1.0.6",
"fs": "0.0.1-security",
"path": "^0.12.7",
"pngjs": "^3.4.0",
"pug": "^2.0.3",
"serialport": "^7.1.5",
"sharp": "^0.22.1",
"socket.io": "^2.2.0",
"thermalprinter": "^0.3.8"
}
}