33 changed files with 414 additions and 76 deletions
@ -0,0 +1,19 @@
|
||||
package net.sopod.soim.common.constant; |
||||
|
||||
/** |
||||
* DeviceEnum |
||||
* TODO 登录时客户端传递设备类型 |
||||
* http登录接口token中包含当前账号在线顺序 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 14:09 |
||||
*/ |
||||
public enum DeviceEnum { |
||||
|
||||
PC, |
||||
|
||||
ANDROID, |
||||
|
||||
IOS |
||||
|
||||
} |
||||
@ -0,0 +1,39 @@
|
||||
package net.sopod.soim.entry.config; |
||||
|
||||
import org.apache.dubbo.common.URL; |
||||
import org.apache.dubbo.rpc.Exporter; |
||||
import org.apache.dubbo.rpc.ExporterListener; |
||||
import org.apache.dubbo.rpc.RpcException; |
||||
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
import org.springframework.context.ApplicationContext; |
||||
|
||||
/** |
||||
* DubboExporterListener |
||||
* 获取服务注册地址 im-entry |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 09:55 |
||||
*/ |
||||
public class DubboImEntryExporterListener implements ExporterListener { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DubboImEntryExporterListener.class); |
||||
|
||||
@Override |
||||
public void exported(Exporter<?> exporter) throws RpcException { |
||||
URL invokerUrl = exporter.getInvoker().getUrl(); |
||||
if (DubboProtocol.NAME.equals(invokerUrl.getProtocol())) { |
||||
if (ApplicationContextHolder.getDubboAppServiceAddr() == null) { |
||||
logger.info("im-entry dubbo app serverAddr: {}", invokerUrl.getAddress()); |
||||
ApplicationContextHolder.setDubboAppServiceAddr(invokerUrl.getAddress()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void unexported(Exporter<?> exporter) { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
|
||||
im_entry_export_listener=net.sopod.soim.entry.config.DubboImEntryExporterListener |
||||
@ -0,0 +1,45 @@
|
||||
package net.sopod.soim.entry.api.route; |
||||
|
||||
import net.sopod.soim.common.constant.DubboConstant; |
||||
import net.sopod.soim.common.util.StringUtil; |
||||
import org.apache.dubbo.common.URL; |
||||
import org.apache.dubbo.rpc.Invocation; |
||||
import org.apache.dubbo.rpc.Invoker; |
||||
import org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* ImEntryServerAddressLoadBalance |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 14:45 |
||||
*/ |
||||
public class ImEntryServerAddressLoadBalance extends AbstractLoadBalance { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ImEntryServerAddressLoadBalance.class); |
||||
|
||||
@Override |
||||
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { |
||||
String invokeAddr = ""; |
||||
for (Invoker<T> invoker : invokers) { |
||||
invokeAddr += invoker.getUrl().getAddress() + ":" + invoker.getInterface() + ","; |
||||
} |
||||
logger.info("invokers: {}", invokeAddr); |
||||
String entryAddr = invocation.getAttachment(DubboConstant.IM_ENTRY_ADDR); |
||||
if (StringUtil.isEmpty(entryAddr)) { |
||||
throw new IllegalCallerException("上下文 im-entry 服务地址不能为空"); |
||||
} |
||||
logger.info("entryAddr: {}", entryAddr); |
||||
for (Invoker<T> invoker : invokers) { |
||||
if (entryAddr.equals(invoker.getUrl().getAddress())) { |
||||
logger.info("invoker address: {}", invoker.getUrl().getAddress()); |
||||
return invoker; |
||||
} |
||||
} |
||||
throw new IllegalCallerException("没有地址为 " + entryAddr + " im-entry 服务"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
package net.sopod.soim.entry.api.service; |
||||
|
||||
/** |
||||
* OnlineUserService |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 22:44 |
||||
*/ |
||||
public interface OnlineUserService { |
||||
|
||||
String getImEntryAddrByUid(Long uid); |
||||
|
||||
} |
||||
@ -0,0 +1 @@
|
||||
im_entry_loadbalance=net.sopod.soim.entry.api.route.ImEntryServerAddressLoadBalance |
||||
@ -0,0 +1,5 @@
|
||||
|
||||
其他服务到 router 的服务,通过 uid 进行一致性 hash 负载均衡, |
||||
|
||||
router 到 entry 的服务,通过指定 user 所登录的 entry 节点 serverAddr 地址进行指向性路由负载均衡。 |
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package net.sopod.soim.router.cache; |
||||
|
||||
import net.sopod.soim.router.api.model.RouterUser; |
||||
|
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
/** |
||||
* ImUserCache |
||||
* 在线用户属性缓存 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 14:07 |
||||
*/ |
||||
public class SoImUserCache { |
||||
|
||||
private static final SoImUserCache INSTANCE = new SoImUserCache(); |
||||
|
||||
private final ConcurrentHashMap<Long, RouterUser> routerUserMap = new ConcurrentHashMap<>(128); |
||||
|
||||
public static SoImUserCache getInstance() { |
||||
return INSTANCE; |
||||
} |
||||
|
||||
public void put(Long uid, RouterUser routerUser) { |
||||
routerUserMap.put(uid, routerUser); |
||||
} |
||||
|
||||
public RouterUser get(Long uid) { |
||||
return routerUserMap.get(uid); |
||||
} |
||||
|
||||
public Map<Long, RouterUser> getRouterUserMap() { |
||||
return routerUserMap; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,49 @@
|
||||
package net.sopod.soim.router.config; |
||||
|
||||
import net.sopod.soim.common.constant.DubboConstant; |
||||
import net.sopod.soim.router.api.model.RouterUser; |
||||
import net.sopod.soim.router.cache.SoImUserCache; |
||||
import org.apache.dubbo.rpc.*; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* InvokeImEntryFilter |
||||
* 调用 im-entry 服务 serverAddr 上下文设置 |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 14:56 |
||||
*/ |
||||
public class InvokeImEntryFilter implements Filter { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InvokeImEntryFilter.class); |
||||
|
||||
@Override |
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { |
||||
String serviceInterface = invoker.getUrl().getServiceInterface(); |
||||
logger.info("invoke interface: {}", serviceInterface); |
||||
// 判断是 im-entry 服务接口
|
||||
if (serviceInterface.startsWith(DubboConstant.IM_ENTRY_SERVICE_API_PACK)) { |
||||
String imEntryServerAddr = null; |
||||
// 获取请求链路用户id
|
||||
String ctxUid = invocation.getAttachment(DubboConstant.CTX_UID); |
||||
if (ctxUid != null) { |
||||
SoImUserCache soImUserCache = SoImUserCache.getInstance(); |
||||
RouterUser routerUser = soImUserCache.get(Long.valueOf(ctxUid)); |
||||
if (routerUser != null) { |
||||
imEntryServerAddr = routerUser.getImEntryAddr(); |
||||
} |
||||
} |
||||
if (imEntryServerAddr == null) { |
||||
throw new IllegalCallerException("调用im-entry服务接口,上下文服务地址未指定"); |
||||
} |
||||
String uid2 = RpcContext.getServerContext().getAttachment(DubboConstant.CTX_UID); |
||||
String uid3 = RpcContext.getServiceContext().getAttachment(DubboConstant.CTX_UID); |
||||
logger.info("ctxUid: {}, {}, {}", ctxUid, uid2, uid3); |
||||
// 设置 im-entry 服务地址
|
||||
invocation.setAttachment(DubboConstant.IM_ENTRY_ADDR, imEntryServerAddr); |
||||
} |
||||
return invoker.invoke(invocation); |
||||
} |
||||
|
||||
} |
||||
@ -1,39 +0,0 @@
|
||||
package net.sopod.soim.router.listener; |
||||
|
||||
import java.rmi.*; |
||||
import java.rmi.registry.Registry; |
||||
|
||||
/** |
||||
* ImRouterServiceRegistry |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-01 16:34 |
||||
*/ |
||||
public class ImRouterServiceRegistry implements Registry { |
||||
|
||||
@Override |
||||
public Remote lookup(String s) throws RemoteException, NotBoundException, AccessException { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public void bind(String s, Remote remote) throws RemoteException, AlreadyBoundException, AccessException { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void unbind(String s) throws RemoteException, NotBoundException, AccessException { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void rebind(String s, Remote remote) throws RemoteException, AccessException { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public String[] list() throws RemoteException, AccessException { |
||||
return new String[0]; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@
|
||||
package net.sopod.soim.router.service; |
||||
|
||||
import net.sopod.soim.entry.api.service.OnlineUserService; |
||||
import net.sopod.soim.router.api.model.RouterUser; |
||||
import net.sopod.soim.router.cache.SoImUserCache; |
||||
import org.apache.dubbo.config.annotation.DubboService; |
||||
|
||||
/** |
||||
* SoImUserServiceImpl |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 22:45 |
||||
*/ |
||||
@DubboService |
||||
public class OnlineUserServiceImpl implements OnlineUserService { |
||||
|
||||
@Override |
||||
public String getImEntryAddrByUid(Long uid) { |
||||
RouterUser routerUser = SoImUserCache.getInstance().get(uid); |
||||
return routerUser == null ? null : routerUser.getImEntryAddr(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
|
||||
package net.sopod.soim.router.util; |
||||
|
||||
import net.sopod.soim.common.constant.DubboConstant; |
||||
import net.sopod.soim.router.api.model.RouterUser; |
||||
import net.sopod.soim.router.cache.SoImUserCache; |
||||
import org.apache.dubbo.rpc.RpcContext; |
||||
|
||||
import java.util.Objects; |
||||
|
||||
/** |
||||
* RpcContextUtil |
||||
* |
||||
* @author tmy |
||||
* @date 2022-05-02 22:27 |
||||
*/ |
||||
public class RpcContextUtil { |
||||
|
||||
public static boolean setImEntryRouteServerAddrByUid(Long uid) { |
||||
Objects.requireNonNull(uid, "设置im-entry路由参数uid不能为空"); |
||||
RpcContext.getServiceContext().setAttachment(DubboConstant.CTX_UID, uid); |
||||
RouterUser routerUser = SoImUserCache.getInstance().get(uid); |
||||
String imEntryAddr; |
||||
if (routerUser == null |
||||
|| null == (imEntryAddr = routerUser.getImEntryAddr())) { |
||||
return false; |
||||
} |
||||
RpcContext.getServiceContext().setAttachment(DubboConstant.IM_ENTRY_ADDR, imEntryAddr); |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
|
||||
invoke_im_entry_filter=net.sopod.soim.router.config.InvokeImEntryFilter |
||||
Loading…
Reference in new issue