Coder Social home page Coder Social logo

yuanrw / im Goto Github PK

View Code? Open in Web Editor NEW
681.0 23.0 314.0 634 KB

IM server based on netty. Provides a client jar. Integrate with your own login system.基于netty实现的IM服务端,提供客户端jar包,可集成自己的登录系统

Java 68.67% Groovy 21.47% Dockerfile 1.82% Shell 8.03%
netty webflux instant-messaging spring-boot spring java mircoservices im proto protobuf ldap ldap-authentication client-jar client-server

im's Issues

windows 启动报错 是什么原因呢

rest-web | wait-for-it.sh: im-mysql:3306 is available after 10 seconds
rest-web | wait-for-it.sh: waiting for im-redis:6379 without a timeout
rest-web | wait-for-it.sh: im-redis:6379 is available after 0 seconds
rest-web | wait-for-it.sh: waiting for im-rabbit:5672 without a timeout
rest-web | wait-for-it.sh: im-rabbit:5672 is available after 0 seconds
rest-web | JAVA_HOME: /opt/java/openjdk
rest-web | OpenJDK 64-Bit Server VM warning: Ignoring option PermSize; support was removed in 8.0
rest-web | OpenJDK 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
rest-web | 2020-08-23 22:55:10.399 rest [main] ERROR o.s.boot.SpringApplication - Application run failed
rest-web | java.lang.IllegalStateException: Logback configuration error detected:
rest-web | ERROR in ch.qos.logback.core.rolling.RollingFileAppender[file] - openFile(/tmp/IM_logs/rest.log,true) call failed. java.io.FileNotFoundException: /tmp/IM_logs/rest.
log (Is a directory)
rest-web | at org.springframework.boot.logging.logback.LogbackLoggingSystem.loadConfiguration(LogbackLoggingSystem.java:169) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]

rest-web | at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:82) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE
]
rest-web | at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:60) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at org.springframework.boot.logging.logback.LogbackLoggingSystem.initialize(LogbackLoggingSystem.java:117) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:293) ~[spring-boot-2.1.2.RELEASE.jar:2.1
.2.RELEASE]
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:266) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.REL
EASE]
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:229) ~[spring-boot-
2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:202) ~[spring-boot-2.1.2.RELEASE.jar:2
.1.2.RELEASE]
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.4.RELEA
SE.jar:5.1.4.RELEASE]
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.4.RELEASE
.jar:5.1.4.RELEASE]
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.4.RELEASE
.jar:5.1.4.RELEASE]
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127) ~[spring-context-5.1.4.RELEASE
.jar:5.1.4.RELEASE]
rest-web | at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:75) ~[spring-boot-2.1.2.RELEASE.jar:2.1
.2.RELEASE]
rest-web | at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEA
SE]
rest-web | at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:347) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at org.springframework.boot.SpringApplication.run(SpringApplication.java:306) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
rest-web | at com.github.yuanrw.im.rest.web.RestStarter.main(RestStarter.java:19) ~[rest-web-1.0.0.jar:na]
rest-web | Exception in thread "main" java.lang.IllegalStateException: Logback configuration error detected:
rest-web | ERROR in ch.qos.logback.core.rolling.RollingFileAppender[file] - openFile(/tmp/IM_logs/rest.log,true) call failed. java.io.FileNotFoundException: /tmp/IM_logs/rest.
log (Is a directory)
rest-web | at org.springframework.boot.logging.logback.LogbackLoggingSystem.loadConfiguration(LogbackLoggingSystem.java:169)
rest-web | at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:82)
rest-web | at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:60)
rest-web | at org.springframework.boot.logging.logback.LogbackLoggingSystem.initialize(LogbackLoggingSystem.java:117)
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:293)
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:266)
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:229)
rest-web | at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:202)
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
rest-web | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
rest-web | at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:75)
rest-web | at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
rest-web | at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:347)
rest-web | at org.springframework.boot.SpringApplication.run(SpringApplication.java:306)
rest-web | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
rest-web | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
rest-web | at com.github.yuanrw.im.rest.web.RestStarter.main(RestStarter.java:19)
rest-web | SERVICE_NAME started....
rest-web exited with code 0
transfer | nc: bad address 'rest-web'
transfer | nc: bad address 'rest-web'
transfer | nc: bad address '

im 聊天

学习下im聊天编程,谢谢分享

connector转发的Ack.AckMsg MsgType为READ消息无法被ack,connector会一直发送消息

connector发送的Ack.AckMsg 或者Chat.ChatMsg无法被客户端Ack,connector后面会一直发送

com.github.yuanrw.im.connector.service.ConnectorToClientService

public void doChatToClientOrTransferAndFlush(Chat.ChatMsg chat) {
        boolean onTheMachine = sendMsg(chat.getDestId(), chat.getId(),
            cid -> Chat.ChatMsg.newBuilder().mergeFrom(chat).setId(IdWorker.nextId(cid)).build());

        //send ack to from id
        if (onTheMachine) {
            ClientConn conn = clientConnContext.getConnByUserId(chat.getFromId());
            if (conn == null) {
                ChannelHandlerContext ctx = ConnectorTransferHandler.getOneOfTransferCtx(System.currentTimeMillis());
                ctx.writeAndFlush(getDelivered(ctx.channel().attr(Conn.NET_ID).get(), chat));
            } else {
                //need wait for ack
                Ack.AckMsg delivered = getDelivered(conn.getNetId(), chat);
                ServerAckWindow.offer(conn.getUserId(), delivered.getId(), delivered, m -> conn.getCtx().writeAndFlush(m));
            }
        }
    }

private boolean sendMsg(String destId, Long msgId, Function<Serializable, Message> generateMsg) {
        Conn conn = clientConnContext.getConnByUserId(destId);
        if (conn == null) {
            ChannelHandlerContext ctx = ConnectorTransferHandler.getOneOfTransferCtx(System.currentTimeMillis());
            ctx.writeAndFlush(generateMsg.apply(ctx.channel().attr(Conn.NET_ID).get()));
            return false;
        } else {
            //the user is connected to this machine
            //won 't save chat histories
            Message message = generateMsg.apply(conn.getNetId());
            ServerAckWindow.offer(conn.getNetId(), msgId, message, m -> conn.getCtx().writeAndFlush(m));
            return true;
        }
    }

doChatToClientOrTransferAndFlush()发送delivered ack时,ServerAckWindow.offer的第一个参数是conn.getNetId()
sendMsg()的ServerAckWindow.offer的msgId参数应该是message的新id吗?

com.github.yuanrw.im.client.handler.ClientConnectorHandler

public void channelActive(ChannelHandlerContext ctx) throws Exception {
        this.ctx = ctx;
        serverAckWindow = new ServerAckWindow(IdWorker.uuid(), 10, Duration.ofSeconds(5));
        clientAckWindow = new ClientAckWindow(5);
        clientMsgListener.online();
    }

这里生成了connectId,com.github.yuanrw.im.client.ImClient也生成了connnectId,两个不一样,后面ChatApi发送消息时拿不到ServerAckWindow实例

关于系统的消息ID的生成策略与使用ClientAckWindow判断消息顺序疑问?

com.github.yuanrw.im.common.util.IdWorker

    public static Long nextId(Serializable connectorId) {
        return sessionMap.computeIfAbsent(connectorId,
            key -> new AtomicLong(0)).incrementAndGet();
    }

dalao,
这个ID生成的策略是不是还没完成呀?

这个根据ID判断消息是否顺序的,是不是要根据自己ID的生成策略,然后才能继续编写?

com.github.yuanrw.im.common.domain.ack.ClientAckWindow

    private boolean isContinuous(Long msgId) {
        //如果是本次会话的第一条消息
        if (first.compareAndSet(true, false)) {
            return true;
        } else {
            //不是第一条消息,则按照公式算(如果同时有好几条第一条消息,除了真正的第一条,其他会返回false)
            return msgId - lastId.get() == 1;
        }
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.