
/*=============================================================================================
	author:ZhaoJun
	version:1.2
	email:2732810281@qq.com
=============================================================================================*/


//严格模式
/*-------------------------------------------------------------------------------------------*/	
'use strict';
/*-------------------------------------------------------------------------------------------*/

// tcp请求操作
/*-------------------------------------------------------------------------------------------*/	
    class rpc
    {		
		static async com({param,time,type,$ip,$port,service='rpc'})
		{
			let con
			try 
			{
				con=await $ExtendPool[type].pool[service].able()
				if(!param.$unique)param.$unique=$Sys.gid().unis
				param.$timeEnd=param.$timeEnd=Date.now()+time
				con.json(param,{$ip,$port,encode:type=='tcp'})
	
				
				let race=new Promise
				(
					(res,rej)=>
					{
						let fun=function (data)
						{
							try 
							{
								if(param.$unique==data.$unique)
								res(data)
							} 
							catch (error) 
							{
								rej(error)
							}
						}
						con.dataBack=fun
					}
				)
	
				return await $Sys.race(race,time,`${service}等待`)
			} 
			catch (error) 
			{
				console.error(`${service}发生错误`,error)
				throw Error(`${service}发生错误`)
			}
			finally
			{
				if(con)con.release('dataBack')
			}
		}

		static async comHash({param,time,type,$ip,$port,count=2,service='rpc'})
		{
			let uni=$Sys.gid().unis;
			if(!param.$unique)param.$unique=uni
			await $ExtendPool[type].pool[service].hash(count).json(param,{$ip,$port,encode:type=='tcp'});
			
			let pro= new Promise
			(
				function(reslove,rej)
				{
					$ExtendPool[type].data[uni]={time:Date.now,rej:rej,res:reslove}
				}
			)
			
			return $Sys.race(pro,time,service).finally
			(
				()=>
				{
					Reflect.deleteProperty($ExtendPool[type].data,uni)
				}
			)
		}

		static async sendCom(param,time,type,style,count=1,$ip,$port,service='rpc')
		{
			let fun=async ()=>
			{
				if(style=='able')
				{
					//{param,time,type,$ip,$port}
					return await rpc.com({param,time,type,$ip,$port,service})
				}
				else
				{
					//{param,time,type,$ip,$port,count=2}
					return await rpc.comHash({param,time,type,$ip,$port,count,service})
				}
			}

			for (let index = 0; index < count; index++) 
			{
				try 
				{
					return await fun()
				} 
				catch (error) 
				{
					let counts=index+1
					console.warn(`[rpc]第${counts}次，请求失败`,error)
					if(count=counts)throw error
				}
			}
			
		}
		
		static async send({param,path,time=1000*3,style='able',count=1,service='rpc'}) 
		{
			let data={query:param,path}
			return await rpc.sendCom(data,time,'tcp',style,count,undefined,undefined,service)
		}

		static async sendPost({param,time=1000*3,style='able',count=1,service='rpc'}) 
		{
			let data={post:param,path}
			return await rpc.sendCom(data,time,'tcp',style,count,undefined,undefined,service)
		}

		static udpCom($ip,$port)
		{
			let obj={$ip,$port}
			if($ip && $port)
			{
				return obj
			}
			let optList=$ExtendPool.udp.opt.rpc.list
			if(!optList)$Sys.err({message:"[rpc]当前没有可用udp目标地址"})

			var len=optList.length;
			let back = optList[parseInt((Date.now()*Math.random()))%len];
			back.$ip=back.host
			back.$port=back.port

			return back
		}

		static async sendUdp({param,path,time=1000*3,$ip,$port,style='able',count=1,service='rpc'}) 
		{
			let data={query:param,path}
			let obj=rpc.udpCom($ip,$port)
			return await rpc.sendCom(data,time,'udp',style,count,obj.$ip,obj.$port,service)
		}

		static async sendPostUdp({param,time=1000*3,$ip,$port,style='able',count=1,service='rpc'}) 
		{
			let data={post:param,path}
			let obj=rpc.udpCom($ip,$port)
			return await rpc.sendCom(data,time,'udp',style,count,obj.$ip,obj.$port,service)
		}


		static multi(message)
		{
			let udp=$ExtendNet.udp
			if(!udp.server)return
			return udp.server.send(message,udp.multiPort,udp.multiAddr)
		}


    }
/*-------------------------------------------------------------------------------------------*/    
module.exports=rpc;
