├── README.md ├── service ├── app.js ├── bin │ └── www ├── db │ ├── db.js │ └── db.sql ├── package.json ├── public │ ├── config │ │ └── config.json │ └── stylesheets │ │ └── style.css ├── routes │ ├── app │ │ ├── admin.js │ │ ├── index.js │ │ └── user.js │ ├── index.js │ ├── qiniu.js │ └── response.js ├── utis │ ├── contant.js │ ├── email.js │ ├── emoji.js │ └── md5.js └── views │ ├── error.jade │ ├── index.jade │ └── layout.jade └── taskservice ├── app.js ├── bin └── www ├── db └── db.js ├── package.json ├── public └── stylesheets │ └── style.css ├── routes └── task.js └── views ├── error.jade ├── index.jade └── layout.jade /README.md: -------------------------------------------------------------------------------- 1 | # flutter-vjujiao-server 2 | 3 | 此仓库为flutter-vjujiao的后台支撑代码,主要技术为node+mysql 4 | 5 | service 服务与app的接口,如用户,rss订阅源 6 | 7 | taskservice 用于定时同步所采集的rss订阅源数据到数据库 8 | 9 | 说明:rss订阅源采集了rsshub上的数据源 10 | 11 | 如果需要跑该套代码请先行在代码处修改为自己的mysql的配置: 12 | * service/db/db.js 第八行 13 | * taskservice/db/db.js 第八行 14 | * 分别复制service/db/db.sql和taskservice/db/db.sql的代码,用于创建数据表 15 | 16 | 17 | 如有问题请提issues,开源不易,求star 18 | -------------------------------------------------------------------------------- /service/app.js: -------------------------------------------------------------------------------- 1 | var createError = require('http-errors'); 2 | var express = require('express'); 3 | var path = require('path'); 4 | var cookieParser = require('cookie-parser'); 5 | var logger = require('morgan'); 6 | var db = require('./db/db') 7 | var appRouter = require('./routes/app/index'); 8 | var qiniuRouter = require('./routes/qiniu'); 9 | 10 | var app = express(); 11 | 12 | // view engine setup 13 | app.set('views', path.join(__dirname, 'views')); 14 | app.set('view engine', 'jade'); 15 | 16 | app.use(logger('dev')); 17 | app.use(express.json()); 18 | app.use(express.urlencoded({ extended: false })); 19 | app.use(cookieParser()); 20 | app.use(express.static(path.join(__dirname, 'public'))); 21 | 22 | //---------------------配置token start---------------------------// 23 | var expressJWT = require('express-jwt'); 24 | var contant = require("./utis/contant") 25 | app.use(expressJWT({ 26 | secret: contant.JWT_SECRET, 27 | getToken: function (req) { 28 | if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { 29 | return req.headers.authorization.split(' ')[1]; 30 | } 31 | return null; 32 | } 33 | }).unless({ 34 | path: [ 35 | "/app/user/login", 36 | "/app/user/register", 37 | "/apidoc/index.html", 38 | // "/qiniu/getToken", 39 | "/app/user/sendEmailCode", 40 | "/app/user/resetPassword", 41 | ] 42 | })) 43 | var {filterEmoji} = require('./utis/emoji') 44 | //过滤emoji表情 45 | app.use(function(req,res,next){ 46 | if(req.query){ 47 | Object.keys(req.query).forEach(key => { 48 | req.query[key] = filterEmoji(req.query[key]) 49 | }) 50 | } 51 | if(req.body){ 52 | Object.keys(req.body).forEach(key => { 53 | req.body[key] = filterEmoji(req.body[key]) 54 | }) 55 | } 56 | next(); 57 | }) 58 | app.use(function (err, req, res, next) { 59 | if (err.name == "UnauthorizedError") { 60 | res.status(401).send('invalid token...'); 61 | } else { 62 | next() 63 | } 64 | }) 65 | //---------------------配置token end---------------------------// 66 | 67 | app.use('/app', appRouter); 68 | app.use('/qiniu', qiniuRouter); 69 | 70 | // catch 404 and forward to error handler 71 | app.use(function (req, res, next) { 72 | next(createError(404)); 73 | }); 74 | 75 | // error handler 76 | app.use(function (err, req, res, next) { 77 | // set locals, only providing error in development 78 | res.locals.message = err.message; 79 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 80 | 81 | // render the error page 82 | res.status(err.status || 500); 83 | res.render('error'); 84 | }); 85 | 86 | module.exports = app; 87 | -------------------------------------------------------------------------------- /service/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('service:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '80'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /service/db/db.js: -------------------------------------------------------------------------------- 1 | var mysql = require('mysql') 2 | 3 | var mysqlPool = mysql.createPool({ 4 | acquireTimeout: 60, 5 | waitForConnections: true, 6 | connectionLimit: 200, 7 | user: "root", 8 | host: "172.17.97.19",//更改为自己的数据库ip,本地的为localhost 9 | password: "xxxxxxxx",//数据库密码 10 | port: 3306, 11 | database: "vjujiao" 12 | }) 13 | 14 | function getMysqlPool(callback) { 15 | mysqlPool.getConnection(function (error, connection) { 16 | if (error) { 17 | console.log('netlog-getConnection',error) 18 | throw error 19 | } else { 20 | callback && callback(connection) 21 | } 22 | }) 23 | } 24 | 25 | var beginTransaction = (tran) => { 26 | return new Promise((resolve, reject) => { //返回promise提供事务成功与失败的接口 27 | getMysqlPool((conn) => { 28 | conn.beginTransaction((err) => { //开始事务处理 29 | if (err) { 30 | conn.release() 31 | reject(err) 32 | } else { 33 | let promise = tran(conn) //调用事务处理函数 34 | promise.then(result => { 35 | conn.commit(err => { //事务处理函数resolve则提交事务 36 | if (err) { 37 | reject(err) 38 | } else { 39 | resolve(result) 40 | } 41 | conn.release() 42 | }) 43 | }).catch(err => { 44 | conn.rollback(() => { //事务处理函数reject则回滚事务 45 | conn.release() 46 | reject(err) 47 | }) 48 | }) 49 | } 50 | }) 51 | }) 52 | }) 53 | } 54 | 55 | beginTransaction.query = (conn, sql, params) => { 56 | return new Promise((resolve, reject) => { 57 | conn.query(sql, params, (err, result) => { 58 | if (err) { 59 | reject(err) 60 | } else { 61 | resolve(result) 62 | } 63 | }) 64 | }) 65 | } 66 | 67 | module.exports = { 68 | getMysqlPool, 69 | beginTransaction, 70 | } -------------------------------------------------------------------------------- /service/db/db.sql: -------------------------------------------------------------------------------- 1 | 2 | create database vjujiao default character set utf8; 3 | 4 | /** 5 | * 用户表 sex 1 男 0 女 status 0 开启 1 禁用 role 角色 6 | */ 7 | create table if not exists user( 8 | user_id int primary key auto_increment, 9 | email varchar(100) unique, 10 | password varchar(500), 11 | sex int default 1, 12 | name varchar(50), 13 | avatar_url varchar(500), 14 | intro varchar(500), 15 | status int default 0, 16 | role int default 0, 17 | time long 18 | ) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 19 | 20 | /** 21 | * 标签类型 22 | */ 23 | create table if not exists tag( 24 | tag_id int primary key auto_increment, 25 | name varchar(500) unique, 26 | orders int default 1, 27 | time long 28 | ) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 29 | 30 | /** 31 | * RSS enable 1开启 0关闭 32 | */ 33 | create table if not exists rss( 34 | rss_id int primary key auto_increment, 35 | enable int default 1, 36 | name varchar(500) unique, 37 | logo text, 38 | description text, 39 | rss_url varchar (500), 40 | time long, 41 | target_tag_id int, 42 | type int DEFAULT 1, 43 | foreign key (target_tag_id) references tag(tag_id) ON UPDATE CASCADE ON DELETE RESTRICT 44 | ) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 45 | 46 | 47 | /** 48 | * RSS订阅 49 | */ 50 | create table if not exists sub_rss( 51 | sub_rss_id int primary key auto_increment, 52 | target_rss_id int, 53 | target_user_id int, 54 | time long , 55 | foreign key (target_rss_id) references rss(rss_id) ON UPDATE CASCADE ON DELETE RESTRICT, 56 | foreign key (target_user_id) references user(user_id) ON UPDATE CASCADE ON DELETE RESTRICT 57 | ) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 58 | 59 | /** 60 | * 反馈 61 | */ 62 | create table if not exists feedback( 63 | feedback_id int primary key auto_increment, 64 | from_user_id int, 65 | content varchar(500), 66 | time long , 67 | foreign key (from_user_id) references user(user_id) ON UPDATE CASCADE ON DELETE RESTRICT 68 | ) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 69 | 70 | /** 71 | * sync rss to mysql 72 | */ 73 | create table if not exists backup_rss( 74 | backup_rss_id int primary key auto_increment, 75 | target_rss_id int, 76 | title varchar(500), 77 | link varchar(500), 78 | time long , 79 | foreign key (target_rss_id) references rss(rss_id) ON UPDATE CASCADE ON DELETE RESTRICT 80 | ) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 81 | 82 | /** 83 | * 安全码 84 | */ 85 | create table if not exists email_code( 86 | email_code_id int primary key auto_increment, 87 | email varchar(500), 88 | code int, 89 | time long 90 | )DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 91 | 92 | /** 93 | * 申请栏目 94 | */ 95 | create table if not exists apply_rss( 96 | apply_rss_id int primary key auto_increment, 97 | name varchar(500), 98 | rss_url varchar(500), 99 | target_user_id int, 100 | time long, 101 | foreign key (target_user_id) references user(user_id) ON UPDATE CASCADE ON DELETE RESTRICT 102 | )DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 103 | 104 | /** 105 | * 添加收藏 106 | */ 107 | create table if not exists collect_rss( 108 | collect_rss_id int primary key auto_increment, 109 | target_backup_rss_id int, 110 | target_rss_id int, 111 | target_user_id int, 112 | time long, 113 | foreign key (target_user_id) references user(user_id) ON UPDATE CASCADE ON DELETE RESTRICT, 114 | foreign key (target_backup_rss_id) references backup_rss(backup_rss_id) ON UPDATE CASCADE ON DELETE RESTRICT, 115 | foreign key (target_rss_id) references rss(rss_id) ON UPDATE CASCADE ON DELETE RESTRICT 116 | )DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 117 | 118 | /** 119 | * 上报错误 120 | */ 121 | create table if not exists error_backup_rss( 122 | error_backup_rss_id int primary key auto_increment, 123 | target_backup_rss_id int, 124 | target_user_id int, 125 | content text, 126 | time long, 127 | foreign key (target_user_id) references user(user_id) ON UPDATE CASCADE ON DELETE RESTRICT, 128 | foreign key (target_backup_rss_id) references backup_rss(backup_rss_id) ON UPDATE CASCADE ON DELETE RESTRICT 129 | )DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 130 | 131 | /** 132 | * 系统消息 133 | */ 134 | create table if not exists system_msg( 135 | system_msg_id int primary key auto_increment, 136 | text text, 137 | time long 138 | )DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 139 | -------------------------------------------------------------------------------- /service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "service", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "cookie-parser": "~1.4.3", 10 | "debug": "~2.6.9", 11 | "express": "~4.16.0", 12 | "express-jwt": "^5.3.1", 13 | "fast-xml-parser": "^3.12.16", 14 | "http-errors": "~1.6.2", 15 | "jade": "~1.11.0", 16 | "morgan": "~1.9.0", 17 | "mysql": "^2.17.1", 18 | "node-schedule": "^1.3.2", 19 | "nodemailer": "^6.2.1", 20 | "qiniu": "^7.2.1", 21 | "request": "^2.88.0" 22 | }, 23 | "apidoc": { 24 | "title": "接口文档", 25 | "url": "http://localhost:3000" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/public/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "android_new_version" : 1, 3 | "android_download_url":"http://10.1.1.217:3000/config/test.apk" 4 | } -------------------------------------------------------------------------------- /service/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /service/routes/app/admin.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var Response = require("../response") 4 | var { getMysqlPool, beginTransaction } = require("../../db/db") 5 | var request = require('request') 6 | var fastXmlParser = require('fast-xml-parser'); 7 | 8 | 9 | router.post("/syncRss", function (req, response) { 10 | let { rss_id } = req.body; 11 | let result = new Response(); 12 | result.data = res; 13 | response.json(result) 14 | }) 15 | 16 | module.exports = router; -------------------------------------------------------------------------------- /service/routes/app/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | var user = require("./user") 5 | var admin = require("./admin") 6 | router.use("/user",user) 7 | router.use("/admin",admin) 8 | 9 | module.exports = router; -------------------------------------------------------------------------------- /service/routes/app/user.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var Response = require("../response") 4 | var jsonwebtoken = require("jsonwebtoken") 5 | var { getMysqlPool, beginTransaction } = require("../../db/db") 6 | var md5 = require('../../utis/md5') 7 | var { randomCode, sendEmail, createActivationEmail, createFindPasswordEmail } = require('../../utis/email') 8 | 9 | /** 10 | * 创建token 11 | * TODO: token 延期需要处理,以最后以后使用app的时间戳为基准 12 | */ 13 | var contant = require("../../utis/contant") 14 | function createToken(user_id) { 15 | return jsonwebtoken.sign({ user_id }, contant.JWT_SECRET, { expiresIn: 60 * 60 * 24 * 30 }); 16 | } 17 | 18 | /** 19 | * 登陆 20 | */ 21 | router.post('/login', function (req, response) { 22 | let { email, password } = req.body; 23 | let result = new Response(); 24 | getMysqlPool(function (connection) { 25 | let sql = `select * from user where email = ? and password = ?` 26 | connection.query(sql, [email, md5(password)], function (error, res) { 27 | if (res && res.length) { 28 | let data = res[0] 29 | delete data["password"] 30 | data.token = createToken(data.user_id) 31 | result.data = data 32 | response.json(result) 33 | } else { 34 | console.log('netlog-', error) 35 | result.code = -1; 36 | result.message = "账号或密码错误" 37 | response.json(result) 38 | } 39 | connection.release(); 40 | }) 41 | }) 42 | }); 43 | 44 | /** 45 | * 注册 46 | */ 47 | router.post("/register", function (req, response) { 48 | let { email, password, sex, name, intro, avatar_url } = req.body; 49 | let result = new Response(); 50 | beginTransaction(function (connection) { 51 | let sql = "select * from user where email = ?" 52 | return beginTransaction.query(connection, sql, [email]).then(res => { 53 | if (res && res.length) { 54 | return Promise.reject("该邮箱已经被注册过了,请尝试更换") 55 | } else { 56 | let sql = "insert into user (email,password,name,sex,intro,avatar_url,time) values (?,?,?,?,?,?,?)" 57 | return beginTransaction.query(connection, sql, [email, md5(password), name, sex, intro, avatar_url, new Date().getTime()]) 58 | } 59 | }).then(res => { 60 | let sql = "select * from user where email = ? and password = ?" 61 | return beginTransaction.query(connection, sql, [email, md5(password)]) 62 | }) 63 | }).then(res => { 64 | let data = res[0] 65 | delete data["password"] 66 | result.data = data; 67 | response.json(result) 68 | }).catch(error => { 69 | console.log('netlog-', error) 70 | result.code = -1; 71 | result.message = error 72 | response.json(result) 73 | }) 74 | }) 75 | 76 | /** 77 | * 发送激活码 78 | */ 79 | router.post("/sendEmailCode", function (req, response) { 80 | let { email } = req.body; 81 | let result = new Response(); 82 | let code = randomCode(); 83 | beginTransaction(connection => { 84 | let sql = "select * from user where email = ?" 85 | return beginTransaction.query(connection, sql, [email]).then(res => { 86 | if (res && res.length) { 87 | return new Promise((resover, reject) => { 88 | sendEmail(createActivationEmail(email, code), function (error, info) { 89 | if (error) { 90 | return reject(error) 91 | } else { 92 | let sql = "insert into email_code (email,code,time) values (?,?,?)" 93 | beginTransaction.query(connection, sql, [email, code, new Date().getTime()]).then(res => { 94 | resover("发送成功") 95 | }).catch(error => { 96 | reject(error) 97 | }) 98 | } 99 | }) 100 | }) 101 | } else { 102 | return Promise.reject("该邮箱还未注册") 103 | } 104 | }) 105 | }).then(res => { 106 | response.json(result) 107 | }).catch(error => { 108 | console.log('netlog-', error) 109 | result.code = -1; 110 | result.message = error 111 | response.json(result) 112 | }) 113 | }) 114 | 115 | /** 116 | * 重设密码 117 | */ 118 | router.post("/resetPassword", function (req, response) { 119 | let { email, code, password, confirmPassword } = req.body; 120 | let result = new Response(); 121 | if (password != confirmPassword) { 122 | result.code = -1; 123 | result.message = "两次密码输入不一致" 124 | response.json(result) 125 | return; 126 | } 127 | beginTransaction(function (connection) { 128 | let sql = "select * from user where email = ?" 129 | return beginTransaction.query(connection, sql, [email]).then(res => { 130 | if (res && res.length) { 131 | let sql = "select * from email_code where email = ? order by time desc" 132 | return beginTransaction.query(connection, sql, [email]).then(res => { 133 | if (res && res.length) { 134 | let data = res[0] //取最新的一条激活码 135 | if (data.code == code && data.time + 1000 * 60 * 60 * 24 > new Date().getTime()) { 136 | let sql = "update user set password = ? where email = ?" 137 | return beginTransaction.query(connection, sql, [md5(password), email]) 138 | } else { 139 | return Promise.reject("激活码错误或已过期") 140 | } 141 | } else { 142 | return Promise.reject("激活码错误") 143 | } 144 | }) 145 | } else { 146 | return Promise.reject("该邮箱还未注册") 147 | } 148 | }); 149 | }).then(res => { 150 | response.json(result) 151 | }).catch(error => { 152 | console.log('netlog-', error) 153 | result.code = -1; 154 | result.message = error 155 | response.json(result) 156 | }) 157 | }) 158 | 159 | /** 160 | * 更新用户信息 161 | */ 162 | router.put("/user", function (req, response) { 163 | let { name, sex, status, avatar_url, role, intro } = req.body; 164 | let { user_id } = req.user; 165 | let result = new Response(); 166 | beginTransaction(function (connection) { 167 | let sql = "select * from user where user_id = ?" 168 | return beginTransaction.query(connection, sql, [user_id]).then(res => { 169 | if (res && res.length) { 170 | var data = res[0]; 171 | let sql = "update user set name = ?,avatar_url = ?,role = ?,sex = ?,intro = ?,status = ? where user_id = ?" 172 | if (!name) { 173 | name = data.name; 174 | } 175 | if (!sex) { 176 | sex = data.sex; 177 | } 178 | if (!status) { 179 | status = data.status; 180 | } 181 | if (!avatar_url) { 182 | avatar_url = data.avatar_url; 183 | } 184 | if (!role) { 185 | role = data.role; 186 | } 187 | if (!intro) { 188 | intro = data.intro; 189 | } 190 | return beginTransaction.query(connection, sql, [name, avatar_url, role, sex, intro, status, backgroundImage, user_id]) 191 | } else { 192 | return Promise.reject("用户不存在") 193 | } 194 | }) 195 | }).then(res => { 196 | response.json(result) 197 | }).catch(error => { 198 | console.log('netlog-', error) 199 | result.code = -1; 200 | result.message = error; 201 | response.json(result) 202 | }) 203 | }) 204 | 205 | /** 206 | * 获取用户信息 207 | */ 208 | router.get("/userinfo", function (req, response) { 209 | let { id } = req.query; 210 | let { user_id } = req.user; 211 | let result = new Response(); 212 | getMysqlPool(function (connection) { 213 | let sql = `select * 214 | from user u 215 | where u.user_id = ?;`; 216 | connection.query(sql, [user_id], function (error, res) { 217 | if (error) { 218 | console.log('netlog-', error) 219 | result.code = -1; 220 | result.data = error; 221 | response.json(result) 222 | } else { 223 | let data = res[0]; 224 | delete data["password"] 225 | result.data = data; 226 | response.json(result) 227 | } 228 | connection.release() 229 | }) 230 | }) 231 | }) 232 | 233 | /** 234 | * 添加反馈 235 | */ 236 | router.post("/addFeedback", function (req, response) { 237 | let { content } = req.body; 238 | let { user_id } = req.user; 239 | let result = new Response(); 240 | getMysqlPool(function (connection) { 241 | let sql = `insert into feedback (from_user_id,content,time) values (?,?,?)`; 242 | connection.query(sql, [user_id, content, new Date().getTime()], function (error, res) { 243 | if (error) { 244 | console.log('netlog-', error) 245 | result.code = -1; 246 | result.data = error; 247 | response.json(result) 248 | } else { 249 | result.data = res[0]; 250 | response.json(result) 251 | } 252 | connection.release() 253 | }) 254 | }) 255 | }) 256 | 257 | /** 258 | * 添加tag标签 259 | */ 260 | router.post("/rss/tag", function (req, response) { 261 | let { name } = req.body; 262 | let { user_id } = req.user; 263 | let result = new Response(); 264 | getMysqlPool(function (connection) { 265 | let sql = `insert into tag(name,time) values (?,?)`; 266 | connection.query(sql, [name, new Date().getTime()], function (error, res) { 267 | if (error) { 268 | console.log('netlog-', error) 269 | result.code = -1; 270 | result.data = error; 271 | response.json(result) 272 | } else { 273 | response.json(result) 274 | } 275 | connection.release() 276 | }) 277 | }) 278 | }) 279 | 280 | /** 281 | * tags 标签 282 | */ 283 | router.get("/rss/tag", function (req, response) { 284 | let { user_id } = req.user; 285 | let result = new Response(); 286 | beginTransaction(function (connection) { 287 | let sql = "select * from tag order by orders desc" 288 | return beginTransaction.query(connection, sql, []); 289 | }).then(res => { 290 | result.data = res; 291 | response.json(result) 292 | }).catch(error => { 293 | console.log('netlog-', error) 294 | result.code = -1; 295 | result.message = error; 296 | response.json(result) 297 | }) 298 | }) 299 | 300 | /** 301 | * 订阅RSS 302 | */ 303 | router.post("/rss/subRss", function (req, response) { 304 | let { id } = req.body; 305 | let { user_id } = req.user; 306 | let result = new Response(); 307 | beginTransaction(function (connection) { 308 | let sql = "select * from sub_rss where target_rss_id = ? and target_user_id = ?" 309 | return beginTransaction.query(connection, sql, [id, user_id]).then(res => { 310 | if (res && res.length > 0) { 311 | return Promise.reject("你已经订阅过了~") 312 | } else { 313 | let sql = `insert into sub_rss(target_rss_id,target_user_id,time) values (?,?,?)`; 314 | return beginTransaction.query(connection, sql, [id, user_id, new Date().getTime()]) 315 | } 316 | }); 317 | }).then(res => { 318 | response.json(result) 319 | }).catch(error => { 320 | console.log('netlog-', error) 321 | result.code = -1; 322 | result.message = error; 323 | response.json(result) 324 | }) 325 | }) 326 | 327 | /** 328 | * 取消订阅RSS 329 | */ 330 | router.post("/rss/unSubRss", function (req, response) { 331 | let { id } = req.body; 332 | let { user_id } = req.user; 333 | let result = new Response(); 334 | beginTransaction(function (connection) { 335 | let sql = "select * from sub_rss where target_rss_id = ? and target_user_id = ?" 336 | return beginTransaction.query(connection, sql, [id, user_id]).then(res => { 337 | if (res && res.length > 0) { 338 | let sql = `delete from sub_rss where target_rss_id = ? and target_user_id = ?`; 339 | return beginTransaction.query(connection, sql, [id, user_id]) 340 | } else { 341 | return Promise.reject("你还没有订阅该栏目~") 342 | } 343 | }); 344 | }).then(res => { 345 | response.json(result) 346 | }).catch(error => { 347 | console.log('netlog-', error) 348 | result.code = -1; 349 | result.message = error; 350 | response.json(result) 351 | }) 352 | }) 353 | 354 | /** 355 | * RSS 广场推荐 356 | * TODO: 增加热门分组,根据订阅去排序 357 | */ 358 | router.get("/rss/recommend", function (req, response) { 359 | let { user_id } = req.user; 360 | let result = new Response(); 361 | beginTransaction(function (connection) { 362 | //先根据tag 分组 363 | let sql = `select * from tag order by orders desc;` 364 | return beginTransaction.query(connection, sql, []).then(res => { 365 | if (res && res.length > 0) { 366 | //根据tag 查询具体的rss 367 | let allPromise = res.map(tag => { 368 | if (tag.name == "热门") { 369 | //根据订阅数量排序 370 | let sql = "select target_rss_id,count(target_rss_id) as ct from sub_rss group by target_rss_id order by ct desc limit 0,10" 371 | return beginTransaction.query(connection, sql, []).then(res => { 372 | if (res && res.length) { 373 | let allPromise = res.map(rss => { 374 | let sql = "select * from rss where rss_id = ? and enable = 1" 375 | return beginTransaction.query(connection, sql, [rss.target_rss_id]); 376 | }) 377 | return Promise.all(allPromise).then(res => { 378 | let childArray = []; 379 | res.forEach(item => { 380 | if (item.length > 0) { 381 | childArray.push(item[0]) 382 | } 383 | }) 384 | return Promise.resolve({ ...tag, child: childArray }) 385 | }) 386 | } else { 387 | return Promise.resolve({ ...tag, child: [] }) 388 | } 389 | }) 390 | } else if (tag.name == "最新") { 391 | //根据时间排序 392 | let sql = "select * from rss where enable = 1 order by time desc limit 0,10" 393 | return beginTransaction.query(connection, sql, []).then(res => { 394 | return Promise.resolve({ ...tag, child: res }) 395 | }) 396 | } 397 | else { 398 | let sql = `select * 399 | from rss r 400 | where target_tag_id = ? and enable = 1 order by r.time desc limit ?,?` 401 | return beginTransaction.query(connection, sql, [tag.tag_id, 0, 10]).then(res => { 402 | if (res && res.length > 0) { 403 | return Promise.resolve({ ...tag, child: res }); 404 | } else { 405 | return Promise.resolve({ ...tag, child: [] }); 406 | } 407 | }) 408 | } 409 | }) 410 | return Promise.all(allPromise); 411 | } else { 412 | return Promise.resolve([]); 413 | } 414 | }) 415 | }).then(res => { 416 | result.data = res.filter(item => item.child.length > 0); 417 | response.json(result) 418 | }).catch(error => { 419 | console.log('netlog-', error) 420 | result.code = -1; 421 | result.message = error; 422 | response.json(result) 423 | }) 424 | }) 425 | 426 | /** 427 | * 全部的 RSS 428 | */ 429 | router.get("/rss", function (req, response) { 430 | let { user_id } = req.user; 431 | let result = new Response(); 432 | beginTransaction(function (connection) { 433 | let sql = `select * from rss where enable = 1;` 434 | return beginTransaction.query(connection, sql, []); 435 | }).then(res => { 436 | result.data = res; 437 | response.json(result) 438 | }).catch(error => { 439 | console.log('netlog-', error) 440 | result.code = -1; 441 | result.message = error; 442 | response.json(result) 443 | }) 444 | }) 445 | 446 | /** 447 | * 添加RSS 448 | */ 449 | router.post("/rss", function (req, response) { 450 | let { name, logo, description, url, target_tag_id,type = 1 } = req.body; 451 | let { user_id } = req.user; 452 | let result = new Response(); 453 | getMysqlPool(function (connection) { 454 | let sql = `insert into rss (name,logo,description,type,rss_url,target_tag_id,time) values (?,?,?,?,?,?,?)`; 455 | connection.query(sql, [name, logo, description, parseInt(type), url, target_tag_id, new Date().getTime()], function (error, res) { 456 | if (error) { 457 | console.log('netlog-', error) 458 | result.code = -1; 459 | result.data = error; 460 | response.json(result) 461 | } else { 462 | response.json(result) 463 | } 464 | connection.release() 465 | }) 466 | }) 467 | }) 468 | 469 | /** 470 | * 模糊搜索 RSS 471 | */ 472 | router.post("/rss/search", function (req, response) { 473 | let { name, offset, limit } = req.body; 474 | let { user_id } = req.user; 475 | let result = new Response(); 476 | beginTransaction(function (connection) { 477 | let sql = `select r.* 478 | from rss r 479 | where r.name like ? and r.enable = 1 order by r.time desc limit ?,?` 480 | return beginTransaction.query(connection, sql, [`%${name}%`, parseInt(offset), parseInt(limit)]); 481 | }).then(res => { 482 | result.data = res; 483 | response.json(result) 484 | }).catch(error => { 485 | console.log('netlog-', error) 486 | result.code = -1; 487 | result.message = error; 488 | response.json(result) 489 | }) 490 | }) 491 | 492 | /** 493 | * 模糊搜索 backupRSS 494 | */ 495 | router.post("/rss/backup/search", function (req, response) { 496 | let { name, offset, limit } = req.body; 497 | let { user_id } = req.user; 498 | let result = new Response(); 499 | beginTransaction(function (connection) { 500 | let sql = `select br.*,rss.* 501 | from backup_rss br 502 | left join rss rss on rss.rss_id = br.target_rss_id and rss.enable = 1 503 | where br.title like ? order by br.time desc limit ?,?` 504 | return beginTransaction.query(connection, sql, [`%${name}%`, parseInt(offset), parseInt(limit)]); 505 | }).then(res => { 506 | result.data = res; 507 | response.json(result) 508 | }).catch(error => { 509 | console.log('netlog-', error) 510 | result.code = -1; 511 | result.message = error; 512 | response.json(result) 513 | }) 514 | }) 515 | 516 | /** 517 | * 具体tag下的 rss 518 | */ 519 | router.get("/tag/rss", function (req, response) { 520 | let { tag_id, offset, limit } = req.query; 521 | let { user_id } = req.user; 522 | let result = new Response(); 523 | beginTransaction(function (connection) { 524 | let sql = "select * from tag where tag_id = ?" 525 | return beginTransaction.query(connection, sql, [tag_id]).then(res => { 526 | if (res && res.length) { 527 | let tag = res[0] 528 | if (tag.name == "热门") { 529 | //根据订阅数量排序 530 | let sql = "select target_rss_id,count(target_rss_id) as ct from sub_rss group by target_rss_id order by ct desc limit ?,?" 531 | return beginTransaction.query(connection, sql, [parseInt(offset), parseInt(limit)]).then(res => { 532 | if (res && res.length) { 533 | let allPromise = res.map(rss => { 534 | let sql = `select r.*, case when sub.target_rss_id > 0 then true else false end as hasSub 535 | from rss r 536 | left join sub_rss sub on sub.target_rss_id = r.rss_id and sub.target_user_id = ? 537 | where r.rss_id = ? and r.enable = 1` 538 | return beginTransaction.query(connection, sql, [user_id, rss.target_rss_id]); 539 | }) 540 | return Promise.all(allPromise).then(res => { 541 | let childArray = []; 542 | res.forEach(item => { 543 | childArray.push(...item) 544 | }) 545 | return Promise.resolve(childArray) 546 | }) 547 | } else { 548 | return Promise.resolve([]) 549 | } 550 | }) 551 | } else if (tag.name == "最新") { 552 | let sql = `select r.*, case when sub.target_rss_id > 0 then true else false end as hasSub 553 | from rss r 554 | left join sub_rss sub on sub.target_rss_id = r.rss_id and sub.target_user_id = ? 555 | where r.enable = 1 order by r.time desc limit ?,?`; 556 | return beginTransaction.query(connection, sql, [user_id, parseInt(offset), parseInt(limit)]) 557 | } else { 558 | let sql = `select r.*, case when sub.target_rss_id > 0 then true else false end as hasSub 559 | from rss r 560 | left join sub_rss sub on sub.target_rss_id = r.rss_id and sub.target_user_id = ? 561 | where r.target_tag_id = ? and r.enable = 1 order by r.time desc limit ?,?`; 562 | return beginTransaction.query(connection, sql, [user_id, tag_id, parseInt(offset), parseInt(limit)]); 563 | } 564 | } else { 565 | return Promise.resolve([]) 566 | } 567 | }) 568 | }).then(res => { 569 | result.data = res; 570 | response.json(result) 571 | }).catch(error => { 572 | console.log('netlog-', error) 573 | result.code = -1; 574 | result.message = error; 575 | response.json(result) 576 | }) 577 | }) 578 | 579 | /** 580 | * 我订阅的rss 581 | */ 582 | router.get("/rss/mySubRss", function (req, response) { 583 | let { limit, offset } = req.query; 584 | let { user_id } = req.user; 585 | let result = new Response(); 586 | beginTransaction(function (connection) { 587 | let sql = `select r.* 588 | from sub_rss s 589 | inner join rss r on r.rss_id = s.target_rss_id and r.enable = 1 590 | where s.target_user_id = ? order by s.time desc limit ?,?` 591 | return beginTransaction.query(connection, sql, [user_id, parseInt(offset), parseInt(limit)]); 592 | }).then(res => { 593 | result.data = res; 594 | response.json(result) 595 | }).catch(error => { 596 | console.log('netlog-', error) 597 | result.code = -1; 598 | result.message = error; 599 | response.json(result) 600 | }) 601 | }) 602 | 603 | /** 604 | * rss 列表 605 | */ 606 | router.get("/rss/list", function (req, response) { 607 | let { rss_id, limit, offset } = req.query; 608 | let { user_id } = req.user; 609 | let result = new Response(); 610 | beginTransaction(function (connection) { 611 | let sql = `select br.*,case when sub.target_rss_id > 0 then true else false end as hasSub 612 | from backup_rss br 613 | left join sub_rss sub on sub.target_rss_id = br.target_rss_id and sub.target_user_id = ? 614 | where br.target_rss_id = ? order by br.time desc limit ?,?` 615 | return beginTransaction.query(connection, sql, [user_id, rss_id, parseInt(offset), parseInt(limit)]); 616 | }).then(res => { 617 | result.data = res; 618 | response.json(result) 619 | }).catch(error => { 620 | console.log('netlog-', error) 621 | result.code = -1; 622 | result.message = error; 623 | response.json(result) 624 | }) 625 | }) 626 | 627 | /** 628 | * rssinfo 629 | */ 630 | router.get("/rss/info", function (req, response) { 631 | let { rss_id } = req.query; 632 | let { user_id } = req.user; 633 | let result = new Response(); 634 | beginTransaction(function (connection) { 635 | let sql = `select rss.*, case when sub.target_rss_id > 0 then true else false end as hasSub 636 | from rss rss 637 | left join sub_rss sub on sub.target_rss_id = rss.rss_id and sub.target_user_id = ? 638 | where rss.rss_id = ?` 639 | return beginTransaction.query(connection, sql, [user_id, rss_id]); 640 | }).then(res => { 641 | result.data = res; 642 | response.json(result) 643 | }).catch(error => { 644 | console.log('netlog-', error) 645 | result.code = -1; 646 | result.message = error; 647 | response.json(result) 648 | }) 649 | }) 650 | 651 | /** 652 | * index 653 | */ 654 | router.get("/index", function (req, response) { 655 | let { offset, limit } = req.query; 656 | let { user_id } = req.user; 657 | let result = new Response(); 658 | beginTransaction(function (connection) { 659 | let sql = `select sub.* 660 | from sub_rss sub 661 | inner join rss r on r.rss_id = sub.target_rss_id and r.enable = 1 662 | where sub.target_user_id = ?` 663 | return beginTransaction.query(connection, sql, [user_id]).then(res => { 664 | if (res && res.length > 0) { 665 | let allPromise = res.map(item => { 666 | let sql = `select b.*,r.name,r.logo,r.rss_url,r.rss_id 667 | from backup_rss b 668 | left join rss r on r.rss_id = b.target_rss_id and r.enable = 1 669 | where b.target_rss_id = ? order by b.time desc limit ?,?`; 670 | return beginTransaction.query(connection, sql, [item.target_rss_id, parseInt(offset), parseInt(limit)]); 671 | }) 672 | return Promise.all(allPromise).then(res => { 673 | let result = []; 674 | res.map(item => { 675 | item.map(i => { 676 | i.timespan = formatMsgTime(i.time); 677 | return i; 678 | }) 679 | result.push(...item) 680 | }); 681 | result.sort((a, b) => { 682 | if (a.time < b.time) { 683 | return 1; 684 | } else if (a.time == b.time) { 685 | return 0; 686 | } else { 687 | return -1; 688 | } 689 | }) 690 | return Promise.resolve(result) 691 | }); 692 | } else { 693 | return Promise.resolve([]); 694 | } 695 | }); 696 | }).then(res => { 697 | result.data = res; 698 | response.json(result) 699 | }).catch(error => { 700 | console.log('netlog-', error) 701 | result.code = -1; 702 | result.message = error; 703 | response.json(result) 704 | }) 705 | }) 706 | 707 | /** 708 | * 添加收藏 709 | */ 710 | router.post("/rss/collect", function (req, response) { 711 | let { backup_rss_id } = req.body; 712 | let { user_id } = req.user; 713 | let result = new Response(); 714 | beginTransaction(function (connection) { 715 | let sql = "select * from collect_rss where target_backup_rss_id = ? and target_user_id = ?" 716 | return beginTransaction.query(connection, sql, [backup_rss_id, user_id]).then(res => { 717 | if (res && res.length > 0) { 718 | return Promise.reject("你已经收藏过了") 719 | } else { 720 | let sql = "select * from backup_rss where backup_rss_id = ?" 721 | return beginTransaction.query(connection, sql, [backup_rss_id]) 722 | } 723 | }).then(res => { 724 | if (res && res.length > 0) { 725 | let sql = "select * from rss where rss_id = ?" 726 | return beginTransaction.query(connection, sql, [res[0].target_rss_id]) 727 | } else { 728 | return Promise.reject("收藏失败") 729 | } 730 | }).then(res => { 731 | if (res && res.length > 0) { 732 | let sql = `insert into collect_rss(target_backup_rss_id,target_user_id,target_rss_id,time) values(?,?,?,?)` 733 | return beginTransaction.query(connection, sql, [backup_rss_id, user_id, res[0].rss_id, new Date().getTime()]); 734 | } else { 735 | return Promise.reject("收藏失败") 736 | } 737 | }) 738 | }).then(res => { 739 | result.data = res; 740 | response.json(result) 741 | }).catch(error => { 742 | console.log('netlog-', error) 743 | result.code = -1; 744 | result.message = error; 745 | response.json(result) 746 | }) 747 | }) 748 | 749 | /** 750 | * 取消收藏 751 | */ 752 | router.delete("/rss/collect", function (req, response) { 753 | let { backup_rss_id } = req.query; 754 | let { user_id } = req.user; 755 | let result = new Response(); 756 | beginTransaction(function (connection) { 757 | let sql = "select * from collect_rss where target_backup_rss_id = ? and target_user_id = ?" 758 | return beginTransaction.query(connection, sql, [backup_rss_id, user_id]).then(res => { 759 | if (res && res.length > 0) { 760 | let sql = `delete from collect_rss where target_backup_rss_id = ? and target_user_id = ?` 761 | return beginTransaction.query(connection, sql, [backup_rss_id, user_id]); 762 | } else { 763 | return Promise.reject("你还没有收藏") 764 | 765 | } 766 | }) 767 | }).then(res => { 768 | result.data = res; 769 | response.json(result) 770 | }).catch(error => { 771 | console.log('netlog-', error) 772 | result.code = -1; 773 | result.message = error; 774 | response.json(result) 775 | }) 776 | }) 777 | 778 | 779 | /** 780 | * 我的收藏列表 781 | */ 782 | router.get("/rss/collect", function (req, response) { 783 | let { offset, limit } = req.query; 784 | let { user_id } = req.user; 785 | let result = new Response(); 786 | beginTransaction(function (connection) { 787 | let sql = `select b.* 788 | from collect_rss c 789 | left join backup_rss b on b.backup_rss_id = c.target_backup_rss_id 790 | where c.target_user_id = ? order by c.time desc limit ?,?` 791 | return beginTransaction.query(connection, sql, [user_id, parseInt(offset), parseInt(limit)]); 792 | }).then(res => { 793 | result.data = res; 794 | response.json(result) 795 | }).catch(error => { 796 | console.log('netlog-', error) 797 | result.code = -1; 798 | result.message = error; 799 | response.json(result) 800 | }) 801 | }) 802 | 803 | /** 804 | * 是否收藏 805 | */ 806 | router.post("/rss/collect/isCollect", function (req, response) { 807 | let { backup_rss_id } = req.body; 808 | let { user_id } = req.user; 809 | let result = new Response(); 810 | beginTransaction(function (connection) { 811 | let sql = `select * from collect_rss where target_user_id = ? and target_backup_rss_id = ?`; 812 | return beginTransaction.query(connection, sql, [user_id, backup_rss_id]); 813 | }).then(res => { 814 | result.data = res; 815 | response.json(result) 816 | }).catch(error => { 817 | console.log('netlog-', error) 818 | result.code = -1; 819 | result.message = error; 820 | response.json(result) 821 | }) 822 | }) 823 | /** 824 | * 用户申请rss栏目 825 | */ 826 | router.post("/rss/apply", function (req, response) { 827 | let { name, url } = req.body; 828 | let { user_id } = req.user; 829 | let result = new Response(); 830 | beginTransaction(function (connection) { 831 | let sql = `insert into apply_rss(name,rss_url,target_user_id,time) values(?,?,?,?)`; 832 | return beginTransaction.query(connection, sql, [name, url, user_id, new Date().getTime()]); 833 | }).then(res => { 834 | result.data = res; 835 | response.json(result) 836 | }).catch(error => { 837 | console.log('netlog-', error) 838 | result.code = -1; 839 | result.message = error; 840 | response.json(result) 841 | }) 842 | }) 843 | 844 | /** 845 | * 上报错误 846 | */ 847 | router.post("/rss/error", function (req, response) { 848 | let { target_backup_rss_id, content } = req.body; 849 | let { user_id } = req.user; 850 | let result = new Response(); 851 | getMysqlPool(function (connection) { 852 | let sql = `insert into error_backup_rss (target_backup_rss_id,target_user_id,content,time) values (?,?,?,?)`; 853 | connection.query(sql, [target_backup_rss_id, user_id, content, new Date().getTime()], function (error, res) { 854 | if (error) { 855 | console.log('netlog-', error) 856 | result.code = -1; 857 | result.data = error; 858 | response.json(result) 859 | } else { 860 | response.json(result) 861 | } 862 | connection.release() 863 | }) 864 | }) 865 | }) 866 | 867 | /** 868 | * 系统消息列表 869 | */ 870 | router.get("/systemMsg", function (req, response) { 871 | let { offset, limit } = req.query; 872 | let { user_id } = req.user; 873 | let result = new Response(); 874 | beginTransaction(function (connection) { 875 | let sql = `select * from system_msg order by time desc limit ?,?` 876 | return beginTransaction.query(connection, sql, [parseInt(offset), parseInt(limit)]); 877 | }).then(res => { 878 | result.data = res; 879 | response.json(result) 880 | }).catch(error => { 881 | console.log('netlog-', error) 882 | result.code = -1; 883 | result.message = error; 884 | response.json(result) 885 | }) 886 | }) 887 | 888 | /** 889 | * 系统消息列表 890 | */ 891 | router.post("/systemMsg", function (req, response) { 892 | let { text } = req.body; 893 | let { user_id } = req.user; 894 | let result = new Response(); 895 | beginTransaction(function (connection) { 896 | let sql = `insert into system_msg(text,time) values(?,?)` 897 | return beginTransaction.query(connection, sql, [text, new Date().getTime()]); 898 | }).then(res => { 899 | result.data = res; 900 | response.json(result) 901 | }).catch(error => { 902 | console.log('netlog-', error) 903 | result.code = -1; 904 | result.message = error; 905 | response.json(result) 906 | }) 907 | }) 908 | 909 | router.get("/test", function (req, response) { 910 | response.send("sdfsdfsadf") 911 | }) 912 | 913 | 914 | 915 | function formatMsgTime(timespan) { 916 | var dateTime = new Date(timespan); 917 | var year = dateTime.getFullYear(); 918 | var month = dateTime.getMonth() + 1; 919 | var day = dateTime.getDate(); 920 | var hour = dateTime.getHours(); 921 | var minute = dateTime.getMinutes(); 922 | var second = dateTime.getSeconds(); 923 | var now = new Date(); 924 | var now_new = now.getTime(); //typescript转换写法 925 | var milliseconds = 0; 926 | var timeSpanStr; 927 | milliseconds = now_new - timespan; 928 | 929 | if (milliseconds <= 1000 * 60 * 1) { 930 | timeSpanStr = '刚刚'; 931 | } 932 | else if (1000 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60) { 933 | timeSpanStr = Math.round((milliseconds / (1000 * 60))) + '分钟前'; 934 | } 935 | else if (1000 * 60 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60 * 24) { 936 | timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60)) + '小时前'; 937 | } 938 | else if (1000 * 60 * 60 * 24 < milliseconds && milliseconds <= 1000 * 60 * 60 * 24 * 15) { 939 | timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60 * 24)) + '天前'; 940 | } 941 | else if (milliseconds > 1000 * 60 * 60 * 24 * 15 && year == now.getFullYear()) { 942 | timeSpanStr = month + '-' + day + ' ' + hour + ':' + minute; 943 | } else { 944 | timeSpanStr = year + '-' + month + '-' + day + ' ' + hour + ':' + minute; 945 | } 946 | return timeSpanStr; 947 | } 948 | 949 | module.exports = router; -------------------------------------------------------------------------------- /service/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('index', { title: 'Express' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /service/routes/qiniu.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var qiniu = require("qiniu") 4 | var Response = require("./response") 5 | 6 | router.get("/getToken", function (req, response) { 7 | var accessKey = 'CTQSd1IBjCG50yzMhXkTvKvBbQrU8FZAh1f21KXw'; 8 | var secretKey = '4tt3iBDEPQcsnJs1g7vyxAgJsoLSTb3dgayZlt76'; 9 | var mac = new qiniu.auth.digest.Mac(accessKey, secretKey); 10 | var options = { 11 | scope: "2019project", 12 | }; 13 | var putPolicy = new qiniu.rs.PutPolicy(options); 14 | var uploadToken = putPolicy.uploadToken(mac); 15 | var result = new Response(); 16 | result.data = uploadToken; 17 | response.json(result) 18 | }) 19 | 20 | module.exports = router; -------------------------------------------------------------------------------- /service/routes/response.js: -------------------------------------------------------------------------------- 1 | 2 | class Response{ 3 | 4 | constructor(){ 5 | this.code = 200; 6 | this.data = {}; 7 | this.message = "成功" 8 | } 9 | } 10 | 11 | module.exports = Response; -------------------------------------------------------------------------------- /service/utis/contant.js: -------------------------------------------------------------------------------- 1 | 2 | var JWT_SECRET = "ikimiler" 3 | 4 | module.exports = { 5 | JWT_SECRET 6 | }; -------------------------------------------------------------------------------- /service/utis/email.js: -------------------------------------------------------------------------------- 1 | var nodemailer = require('nodemailer') 2 | 3 | const config = { 4 | host: 'smtp.mxhichina.com', 5 | port: 465, 6 | secure:true, 7 | auth: { 8 | user: 'xxxx', 9 | pass: 'xxxx' 10 | } 11 | } 12 | 13 | const transporter = nodemailer.createTransport(config) 14 | 15 | function sendEmail(email, callback) { 16 | transporter.sendMail(email, callback) 17 | } 18 | 19 | //激活账号的邮件模板 20 | function createActivationEmail(email, code) { 21 | return { 22 | from: config.auth.user, 23 | to: email, 24 | subject: "安全码", 25 | text: "安全码:" + code 26 | } 27 | } 28 | 29 | //找回密码的邮件模板 30 | function createFindPasswordEmail(email, code) { 31 | return { 32 | from: config.auth.user, 33 | to: email, 34 | subject: "找回密码", 35 | text: "安全码:" + code 36 | } 37 | } 38 | 39 | //随机生成激活码 40 | function randomCode(){ 41 | return Math.floor(Math.random() * 1000000); 42 | } 43 | 44 | module.exports = { 45 | sendEmail, 46 | createActivationEmail, 47 | createFindPasswordEmail, 48 | randomCode 49 | }; 50 | -------------------------------------------------------------------------------- /service/utis/emoji.js: -------------------------------------------------------------------------------- 1 | function filterEmoji(str){ 2 | return unescape(escape(str).replace(/\%uD.{3}/g, '')); 3 | } 4 | 5 | module.exports = { 6 | filterEmoji 7 | } -------------------------------------------------------------------------------- /service/utis/md5.js: -------------------------------------------------------------------------------- 1 | var MD5 = function (string) { 2 | 3 | function RotateLeft(lValue, iShiftBits) { 4 | return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); 5 | } 6 | 7 | function AddUnsigned(lX, lY) { 8 | var lX4, lY4, lX8, lY8, lResult; 9 | lX8 = (lX & 0x80000000); 10 | lY8 = (lY & 0x80000000); 11 | lX4 = (lX & 0x40000000); 12 | lY4 = (lY & 0x40000000); 13 | lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); 14 | if (lX4 & lY4) { 15 | return (lResult ^ 0x80000000 ^ lX8 ^ lY8); 16 | } 17 | if (lX4 | lY4) { 18 | if (lResult & 0x40000000) { 19 | return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); 20 | } else { 21 | return (lResult ^ 0x40000000 ^ lX8 ^ lY8); 22 | } 23 | } else { 24 | return (lResult ^ lX8 ^ lY8); 25 | } 26 | } 27 | 28 | function F(x, y, z) { return (x & y) | ((~x) & z); } 29 | function G(x, y, z) { return (x & z) | (y & (~z)); } 30 | function H(x, y, z) { return (x ^ y ^ z); } 31 | function I(x, y, z) { return (y ^ (x | (~z))); } 32 | 33 | function FF(a, b, c, d, x, s, ac) { 34 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); 35 | return AddUnsigned(RotateLeft(a, s), b); 36 | }; 37 | 38 | function GG(a, b, c, d, x, s, ac) { 39 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); 40 | return AddUnsigned(RotateLeft(a, s), b); 41 | }; 42 | 43 | function HH(a, b, c, d, x, s, ac) { 44 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); 45 | return AddUnsigned(RotateLeft(a, s), b); 46 | }; 47 | 48 | function II(a, b, c, d, x, s, ac) { 49 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); 50 | return AddUnsigned(RotateLeft(a, s), b); 51 | }; 52 | 53 | function ConvertToWordArray(string) { 54 | var lWordCount; 55 | var lMessageLength = string.length; 56 | var lNumberOfWords_temp1 = lMessageLength + 8; 57 | var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64; 58 | var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; 59 | var lWordArray = Array(lNumberOfWords - 1); 60 | var lBytePosition = 0; 61 | var lByteCount = 0; 62 | while (lByteCount < lMessageLength) { 63 | lWordCount = (lByteCount - (lByteCount % 4)) / 4; 64 | lBytePosition = (lByteCount % 4) * 8; 65 | lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); 66 | lByteCount++; 67 | } 68 | lWordCount = (lByteCount - (lByteCount % 4)) / 4; 69 | lBytePosition = (lByteCount % 4) * 8; 70 | lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); 71 | lWordArray[lNumberOfWords - 2] = lMessageLength << 3; 72 | lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; 73 | return lWordArray; 74 | }; 75 | 76 | function WordToHex(lValue) { 77 | var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount; 78 | for (lCount = 0; lCount <= 3; lCount++) { 79 | lByte = (lValue >>> (lCount * 8)) & 255; 80 | WordToHexValue_temp = "0" + lByte.toString(16); 81 | WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2); 82 | } 83 | return WordToHexValue; 84 | }; 85 | 86 | function Utf8Encode(string) { 87 | string = string || '' 88 | string = string.replace(/\r\n/g, "\n"); 89 | var utftext = ""; 90 | 91 | for (var n = 0; n < string.length; n++) { 92 | 93 | var c = string.charCodeAt(n); 94 | 95 | if (c < 128) { 96 | utftext += String.fromCharCode(c); 97 | } 98 | else if ((c > 127) && (c < 2048)) { 99 | utftext += String.fromCharCode((c >> 6) | 192); 100 | utftext += String.fromCharCode((c & 63) | 128); 101 | } 102 | else { 103 | utftext += String.fromCharCode((c >> 12) | 224); 104 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 105 | utftext += String.fromCharCode((c & 63) | 128); 106 | } 107 | 108 | } 109 | 110 | return utftext; 111 | }; 112 | 113 | var x = Array(); 114 | var k, AA, BB, CC, DD, a, b, c, d; 115 | var S11 = 7, S12 = 12, S13 = 17, S14 = 22; 116 | var S21 = 5, S22 = 9, S23 = 14, S24 = 20; 117 | var S31 = 4, S32 = 11, S33 = 16, S34 = 23; 118 | var S41 = 6, S42 = 10, S43 = 15, S44 = 21; 119 | 120 | string = Utf8Encode(string); 121 | 122 | x = ConvertToWordArray(string); 123 | 124 | a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; 125 | 126 | for (k = 0; k < x.length; k += 16) { 127 | AA = a; BB = b; CC = c; DD = d; 128 | a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); 129 | d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); 130 | c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB); 131 | b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); 132 | a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); 133 | d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); 134 | c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613); 135 | b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501); 136 | a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8); 137 | d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); 138 | c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); 139 | b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); 140 | a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122); 141 | d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193); 142 | c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E); 143 | b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821); 144 | a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); 145 | d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340); 146 | c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); 147 | b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); 148 | a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); 149 | d = GG(d, a, b, c, x[k + 10], S22, 0x2441453); 150 | c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); 151 | b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); 152 | a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); 153 | d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); 154 | c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); 155 | b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); 156 | a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); 157 | d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); 158 | c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); 159 | b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); 160 | a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); 161 | d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681); 162 | c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); 163 | b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); 164 | a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); 165 | d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); 166 | c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); 167 | b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); 168 | a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); 169 | d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); 170 | c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); 171 | b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05); 172 | a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); 173 | d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); 174 | c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); 175 | b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); 176 | a = II(a, b, c, d, x[k + 0], S41, 0xF4292244); 177 | d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97); 178 | c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); 179 | b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039); 180 | a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3); 181 | d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); 182 | c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); 183 | b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1); 184 | a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); 185 | d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); 186 | c = II(c, d, a, b, x[k + 6], S43, 0xA3014314); 187 | b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); 188 | a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82); 189 | d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); 190 | c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); 191 | b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391); 192 | a = AddUnsigned(a, AA); 193 | b = AddUnsigned(b, BB); 194 | c = AddUnsigned(c, CC); 195 | d = AddUnsigned(d, DD); 196 | } 197 | 198 | var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d); 199 | 200 | return temp.toLowerCase(); 201 | } 202 | module.exports = MD5 -------------------------------------------------------------------------------- /service/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /service/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /service/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /taskservice/app.js: -------------------------------------------------------------------------------- 1 | var createError = require('http-errors'); 2 | var express = require('express'); 3 | var path = require('path'); 4 | var logger = require('morgan'); 5 | var db = require('./db/db') 6 | var task = require('./routes/task') 7 | 8 | var app = express(); 9 | 10 | // view engine setup 11 | app.set('views', path.join(__dirname, 'views')); 12 | app.set('view engine', 'jade'); 13 | 14 | app.use(logger('dev')); 15 | app.use(express.json()); 16 | app.use(express.urlencoded({ extended: false })); 17 | app.use(express.static(path.join(__dirname, 'public'))); 18 | 19 | 20 | 21 | 22 | 23 | // catch 404 and forward to error handler 24 | app.use(function (req, res, next) { 25 | next(createError(404)); 26 | }); 27 | 28 | // error handler 29 | app.use(function (err, req, res, next) { 30 | // set locals, only providing error in development 31 | res.locals.message = err.message; 32 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 33 | 34 | // render the error page 35 | res.status(err.status || 500); 36 | res.render('error'); 37 | }); 38 | 39 | module.exports = app; 40 | -------------------------------------------------------------------------------- /taskservice/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('service:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3001'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /taskservice/db/db.js: -------------------------------------------------------------------------------- 1 | var mysql = require('mysql') 2 | 3 | var mysqlPool = mysql.createPool({ 4 | acquireTimeout: 60, 5 | waitForConnections: true, 6 | connectionLimit: 50, 7 | user: "root", 8 | host: "172.17.97.19",//更改为自己的数据库ip,本地的为localhost 9 | password: "xxxxxxxx",//数据库密码 10 | port: 3306, 11 | database: "vjujiao" 12 | }) 13 | 14 | function getMysqlPool(callback) { 15 | mysqlPool.getConnection(function (error, connection) { 16 | if (error) { 17 | console.log('netlog-getConnection',error) 18 | throw error 19 | } else { 20 | callback && callback(connection) 21 | } 22 | }) 23 | } 24 | 25 | var beginTransaction = (tran) => { 26 | return new Promise((resolve, reject) => { //返回promise提供事务成功与失败的接口 27 | getMysqlPool((conn) => { 28 | conn.beginTransaction((err) => { //开始事务处理 29 | if (err) { 30 | conn.release() 31 | reject(err) 32 | } else { 33 | let promise = tran(conn) //调用事务处理函数 34 | promise.then(result => { 35 | conn.commit(err => { //事务处理函数resolve则提交事务 36 | if (err) { 37 | reject(err) 38 | } else { 39 | resolve(result) 40 | } 41 | conn.release() 42 | }) 43 | }).catch(err => { 44 | conn.rollback(() => { //事务处理函数reject则回滚事务 45 | conn.release() 46 | reject(err) 47 | }) 48 | }) 49 | } 50 | }) 51 | }) 52 | }) 53 | } 54 | 55 | beginTransaction.query = (conn, sql, params) => { 56 | return new Promise((resolve, reject) => { 57 | conn.query(sql, params, (err, result) => { 58 | if (err) { 59 | reject(err) 60 | } else { 61 | resolve(result) 62 | } 63 | }) 64 | }) 65 | } 66 | 67 | module.exports = { 68 | getMysqlPool, 69 | beginTransaction, 70 | } -------------------------------------------------------------------------------- /taskservice/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "service", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "debug": "~2.6.9", 10 | "express": "~4.16.0", 11 | "fast-xml-parser": "^3.12.16", 12 | "http-errors": "~1.6.2", 13 | "jade": "~1.11.0", 14 | "morgan": "~1.9.0", 15 | "mysql": "^2.17.1", 16 | "node-schedule": "^1.3.2", 17 | "request": "^2.88.0" 18 | }, 19 | "apidoc": { 20 | "title": "接口文档", 21 | "url": "http://localhost:3000" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /taskservice/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /taskservice/routes/task.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 定时任务同步rss到本地数据库 3 | */ 4 | var fastXmlParser = require('fast-xml-parser'); 5 | var schedule = require('node-schedule'); 6 | var request = require('request') 7 | const scheduleCronstyle = () => { 8 | //每半小时触发一次同步更新 9 | // schedule.scheduleJob('0 0 * * * *', () => { 10 | // syncSql(); 11 | // }); 12 | 13 | setInterval(() => { 14 | syncSql(); 15 | }, 1000 * 60 * 10); 16 | } 17 | scheduleCronstyle(); 18 | 19 | var {getMysqlPool, beginTransaction } = require("../db/db") 20 | 21 | var startInsertMySql = totalItems => { 22 | beginTransaction(connection => { 23 | return Promise.all(totalItems.map((item, index) => { 24 | return new Promise((resover, reject) => { 25 | if(!item.title || !item.link){ 26 | resover("") 27 | return; 28 | } 29 | //插入之前需要查询是否存在,防止数据重复,维度为 title link rss_id 30 | let sql = "select * from backup_rss where title =? and link =?" 31 | connection.query(sql, [item.title, item.link], function (error, result) { 32 | if (error) { 33 | resover("") 34 | } else if (result && result.length == 0) { 35 | //不存在,开始插入数据 36 | let sql = `insert into backup_rss(target_rss_id,title,link,time) values(?,?,?,?)`; 37 | connection.query(sql, [item.rss.rss_id, item.title, item.link, item.date], function (error, res) { 38 | resover("") 39 | }) 40 | }else{ 41 | resover("") 42 | } 43 | }) 44 | }); 45 | })); 46 | }).then(res => { 47 | console.log('neltog-所有数据同步完成') 48 | totalItems.length = 0; 49 | }).catch(error => { 50 | console.log('neltog-',error) 51 | }) 52 | } 53 | 54 | var requestXMLandParder = rssResult => { 55 | let totalItems = []; 56 | let count = 0; 57 | rssResult.forEach(rss => { 58 | let url = encodeURI(rss.rss_url); 59 | //request url 60 | request.get(url, { timeout: 1000 * 60 }, (error, response) => { 61 | count++; 62 | if (count >= rssResult.length - 1) { 63 | count = 0; 64 | startInsertMySql(totalItems); 65 | } 66 | if (!error && response.statusCode == 200) { 67 | //parser xml 68 | let json = fastXmlParser.parse(response.body) 69 | if (json && json.rss && json.rss.channel && json.rss.channel.item && json.rss.channel.item.length > 0) { 70 | let lastBuildDate = json.rss.channel.lastBuildDate; 71 | json.rss.channel.item.forEach(item => { 72 | item.rss = rss; 73 | item.date = item.pubdate && item.pubdate.length > 5 ? new Date(item.pubdate).getTime() 74 | : lastBuildDate && lastBuildDate.length > 5 ? new Date(lastBuildDate).getTime() 75 | : new Date().getTime() 76 | }); 77 | //添加到集合,稍后统一插入数据库 78 | totalItems.push(...json.rss.channel.item) 79 | } 80 | } 81 | }) 82 | }); 83 | } 84 | 85 | var syncSql = async () => { 86 | getMysqlPool(function (connection) { 87 | //查询所有的rss栏目 88 | let sql = "select * from rss where enable = 1"; 89 | connection.query(sql, [], function (error, res) { 90 | if (!error) { 91 | requestXMLandParder(res); 92 | } 93 | connection.release(); 94 | }) 95 | }); 96 | } 97 | 98 | // syncSql(); 99 | 100 | 101 | // function updateRssUrl() { 102 | // beginTransaction(connection => { 103 | // let sql = "select * from rss;" 104 | // return beginTransaction.query(connection, sql, []).then(res => { 105 | // if (res && res.length > 0) { 106 | // let allPromise = res.map(item => { 107 | // let sql = "update rss set rss_url = ? where rss_id = ?" 108 | // let url = item.rss_url.replace("http://192.168.0.204:1200", "http://rsshub.app") 109 | // return beginTransaction.query(connection, sql, [url, item.rss_id]) 110 | // }) 111 | // return Promise.all(allPromise); 112 | // } 113 | // }) 114 | // }) 115 | // } 116 | 117 | -------------------------------------------------------------------------------- /taskservice/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /taskservice/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /taskservice/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | --------------------------------------------------------------------------------