database.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import {MysqlDB,MysqlUtil} from '../extra/mysqldb';
  2. // const RedisBridge = require(Core.Path.ExtraLib + '/redisdb.js');
  3. import MongoDB from 'mongodb';
  4. import MemcacheDB from 'memcached';
  5. import * as RedisDB from 'redis';
  6. (global as any).MysqlUtil = MysqlUtil;
  7. //默认配置
  8. const DatabaseOption:any = {
  9. mysql : '{"host":"localhost","port":3306,"user":"root","password":"","database":"","prefix":"","connectionLimit":10}',
  10. mongodb : '{"host":"localhost","port":27017,"user":null,"password":"","database":"","prefix":""}',
  11. memcache : '{"host":"localhost","port":11211}',
  12. redis : '{"host":"localhost","port":6379,"prefix":null}'
  13. }
  14. class Database {
  15. /**
  16. * @param {String} DatabaseType 数据库类型
  17. * @param {Object} option 数据库配置
  18. * @param {String} GlobalName 自动全局命名
  19. * @param {Function} callback 回调函数
  20. */
  21. public static async create(DatabaseType:string,option:DBOption,GlobalName?:string){
  22. DatabaseType = DatabaseType.toLowerCase();
  23. switch(DatabaseType){
  24. case 'mysql':
  25. return await Creater._createMysqlConnection(option,GlobalName);
  26. case 'mongodb':
  27. return await Creater._createMongoConnection(option,GlobalName);
  28. case 'memcache':
  29. return await Creater._createMemcacheConnection(option,GlobalName);
  30. case 'redis':
  31. return await Creater._createRedisConnection(option,GlobalName);
  32. default:
  33. return {err:new Error('Wrong database type!')};
  34. }
  35. }
  36. //生成默认配置
  37. public static getOption(type:string){
  38. type = type.toLowerCase();
  39. if(DatabaseOption[type]!=undefined){
  40. return JSON.parse(DatabaseOption[type]);
  41. }else{
  42. return null;
  43. }
  44. }
  45. }
  46. //连接控制器
  47. class Creater{
  48. static _createMysqlConnection (option:DBOption,GlobalName?:string){
  49. return new Promise((resolve,reject)=>{
  50. const _MysqlDB = new MysqlDB(option);
  51. // if(!callback || typeof(callback)!='function') callback = ()=>{return}
  52. //连接测试
  53. _MysqlDB.query('SELECT VERSION() as version',(err,result,fields?:any)=>{
  54. if(err){
  55. LOGGER.error('Mysql Connect error,please recheck your config');
  56. if(err.stack) LOGGER.error(err.stack);
  57. return resolve({err})
  58. }else{
  59. LOGGER.info('Mysql Connect success');
  60. LOGGER.info(`Mysql Version: ${result[0]['version']} | User: ${option.user} | Database: ${option.database} | GlobalName: ${GlobalName}`);
  61. if(GlobalName){
  62. if((global as any)[GlobalName]){
  63. LOGGER.error(`Create global name fail with "${GlobalName}"`);
  64. return resolve({err:new Error('Duplicate global name')})
  65. }else{
  66. (global as any)[GlobalName] = _MysqlDB;
  67. }
  68. }
  69. resolve({err:null,client:_MysqlDB})
  70. }
  71. });
  72. })
  73. }
  74. static _createMongoConnection(option:DBOption,GlobalName?:string){
  75. return new Promise((resolve,rejects)=>{
  76. const verify = option.user?option.user+':'+option.password+'@':'';
  77. const mongoConnect = 'mongodb://' + verify + option.host+':'+option.port+'/'+option.database;
  78. // if(!callback) callback = ()=>{return}
  79. MongoDB.MongoClient.connect(mongoConnect,(err?:Error,db?:any)=>{
  80. if(err) {
  81. LOGGER.error('MongoDB connect error!');
  82. if(err.stack) LOGGER.error(err.stack);
  83. return resolve({err})
  84. }else{
  85. LOGGER.info(`Mongodb Connect success | GlobalName: ${GlobalName}`);
  86. const _mongoClient = {
  87. db:db,
  88. c:(collection:any)=>{
  89. return db.collection(option.prefix+collection);
  90. }
  91. };
  92. if(GlobalName){
  93. if((global as any)[GlobalName]){
  94. LOGGER.error(`Create global name fail with "${GlobalName}"`);
  95. return resolve({err:new Error('Duplicate global name')})
  96. }
  97. (global as any)[GlobalName] = _mongoClient;
  98. }
  99. resolve({err:null,client:_mongoClient})
  100. }
  101. });
  102. })
  103. }
  104. static _createMemcacheConnection(option:DBOption,GlobalName?:string){
  105. return new Promise(async (resolve,reject)=>{
  106. const _Memcache = new MemcacheDB(option.host+':'+option.port);
  107. _Memcache.version(function(err,data){
  108. if(err){
  109. LOGGER.error('Memcache Connect error,please recheck your config');
  110. LOGGER.error(err);
  111. resolve({err});
  112. }else{
  113. LOGGER.info('Memcache Connect success');
  114. LOGGER.info(`Memcache Version: ${data[0]['version']} | GlobalName: ${GlobalName}`);
  115. if(GlobalName){
  116. if((global as any)[GlobalName]){
  117. LOGGER.error(`Create global name fail with "${GlobalName}"`);
  118. resolve({err:new Error('Duplicate global name')});
  119. return;
  120. }else{
  121. (global as any)[GlobalName] = _Memcache;
  122. }
  123. }
  124. resolve({err:null,client:_Memcache});
  125. }
  126. });
  127. });
  128. }
  129. static async _createRedisConnection(option:DBOption,GlobalName?:string){
  130. return new Promise(async (resolve,reject)=>{
  131. let _redisConnStr = `${option.host}:${option.port}`;
  132. _redisConnStr = `redis://${option.user||''}:${option.password||''}@${_redisConnStr}`;
  133. const _redisClient = RedisDB.createClient({url:_redisConnStr,socket:{keepAlive:30000}});
  134. _redisClient.on('error',(err:Error)=>{
  135. if(err instanceof RedisDB.SocketClosedUnexpectedlyError){
  136. LOGGER.error(`Redis [${option.host}:${option.port}] connect has been refused,please recheck your config,and make sure redis server is running!`);
  137. resolve({err:err});
  138. }
  139. })
  140. _redisClient.on('ready',async ()=>{
  141. LOGGER.info(`Redis Connect [${option.user||''}@${option.host}:${option.port}] success [${GlobalName||'UNKNOW'}]`);
  142. const infoStr = <string>await _redisClient.info();
  143. const infoLine = infoStr.split('\n');
  144. const info:any = {};
  145. for(const line of infoLine){
  146. const lineArr = line.split(':');
  147. if(lineArr.length>1) info[lineArr[0]] = lineArr[1];
  148. }
  149. if(info.redis_version) LOGGER.info(`GlobalName: ${GlobalName||'UNKNOW'} | Server Version: ${info.redis_version}`);
  150. // _redisClient.stream.setKeepAlive(true,30 * 1000);
  151. if(GlobalName){
  152. if((global as any)[GlobalName]){
  153. LOGGER.error(`Create global name fail with "${GlobalName}"`);
  154. return resolve({err:new Error('Duplicate global name')});
  155. }else{
  156. (global as any)[GlobalName] = _redisClient;
  157. }
  158. }
  159. resolve({err:null,client:_redisClient});
  160. });
  161. _redisClient.on('reconnecting',function(e:any){
  162. LOGGER.warn('Redis lost connect,reconnecting!');
  163. });
  164. await _redisClient.connect();
  165. })
  166. // {port:option.port,host:option.host,socket_keepalive:true,socket_initialdelay:30000,retry_strategy: function (retryData) {
  167. // if (retryData.error && retryData.error.code === 'ECONNREFUSED') {
  168. // }
  169. // if (retryData.total_retry_time > 1000 * 10) {
  170. // LOGGER.error('Redis retry connect time exhausted');
  171. // }
  172. // if (retryData.attempt > 10) {
  173. // LOGGER.error('Redis unknow error');
  174. // }
  175. // // reconnect after
  176. // return Math.min(retryData.attempt * 100, 3000);
  177. // },prefix:option.prefix});
  178. // if(!callback || typeof(callback)!='function') callback = ()=>{}
  179. }
  180. }
  181. // (global as any).DBManager = Database;
  182. module.exports = Database;