vahidhedayati / grails-wschat-plugin

Grails websocket chat Plugin provides a multi-chat room add-on to an existing grails based site. provides: Private Messaging/WebRTC/Offline PM + room booking/reservations. Websocket TicTactoe. Add Live Chat to your Grails application
http://grails.org/plugin/wschat
Apache License 2.0
22 stars 10 forks source link

Production websocket url problem #4

Closed moniman closed 9 years ago

moniman commented 9 years ago

Hi

I try to use this plugin in production but there is a problem :

WebSocket connection to 'ws://myapp.cloudapp.net/myapp/WsChatEndpoint/' failed: Error during WebSocket handshake: Unexpected response code: 404 wschat-ac58e935523f5b266b80d011c011e99d.js:39 WebSocket is already in CLOSING or CLOSED state.

My url is juste myapp.cloudapp.net without the app name (myapp).

I think this line is the problem :

var webSocket=new WebSocket("ws://${hostname}/${meta(name:'app.name')}/WsChatEndpoint/${room}");

https://github.com/vahidhedayati/grails-wschat-plugin/blob/7355c10403eae5cbbd4317e0e4fe3db434ab02a0/grails-app/views/wsChat/_chat.gsp#L169

May you add a groovy variable like wschat.removeAppName=true

vahidhedayati commented 9 years ago

Hi Moniman

Thanks for reporting the issue, I am in the midst of client code updates so the current code (update is buggy to say the least - but not actual chat related ) client chat which you are not using.

Anyways I have tweaked some stuff released it as 1.11-SNAPSHOT1

Please let me know if you have any issues, there are still updates left for removing app name but again this should all be related to automated chat client (new stuff) that you are not using in a typical chat room....

To disable app name (Not tested hopefully all you need to do is add following to config.groovy:

wschat.add.appName='no'

moniman commented 9 years ago

Hi vahidhedayati,

Thanks for your work !

wschat.add.appName='no' works fine

But when generate a war (grails war) I have this error :

Compiling 25 GSP files for package [wschat] .Error

GSP Compilation error in file /WEB-INF/plugins/wschat-1.11-SNAPSHOT1/grails-app/views/wsChat/camsend.gsp at line 50: Grails tag [g:javascript] was not closed Error |

And I have a question about users. Did this plugin works with spring security plugin ?

vahidhedayati commented 9 years ago

Apologies, 1.11-SNAPSHOT3 please try this

vahidhedayati commented 9 years ago

Sorry missed the question.

In short no it has not been set with any security.

Instead relies on

session.wschatuser

So if you wanted to authenticate users and once they are authenticated set this value maybe to their firstname_surname in your app, then you would find if they accessed /wsChat/chat would log them in as that value.

https://github.com/vahidhedayati/grails-wschat-plugin/wiki/Custom-calling-plugin-disabled-login

https://github.com/vahidhedayati/grails-wschat-plugin/wiki/Custom-calls

https://github.com/vahidhedayati/grails-wschat-plugin/wiki/Merging-plugin-with-your-own-custom-calls

moniman commented 9 years ago

Hi vahidhedayati

Thanks for your new release and happy new year !

Unfortunately, app name has still this endpoint url :
ws://dbp-test1.cloudapp.net/myapp/WsChatEndpoint/myroom.

And in my config : wschat.add.appName='no'

vahidhedayati commented 9 years ago

Hi Moniman

Thank you and a happy new year to you to

I am going to look into this now, can you please tell me how you are accessing it ? Is this using the front end method i.e. going via normal routine of providing a username and logging in or is it via the taglib

<chat:connect method

ok noticed its missing from /chat method - bizarre - must have not declared it as a variable in the map to start with .....

Please try : wschat-1.13-SNAPSHOT and let me know :)

In regards to authentication, did you manage to figure out a solution for yourself ?

I am using this at work and have a site wrapper that calls plugin and then uses apache shiro to authenticate against internal AD

The reason for not binding lets say default shiro / spring security was simply because there maybe an existing authentication mechanism in place that works lets say like above against AD or user may have a local DB on site or in some cases it might not need at all - like the other problem posted. I think auth for the other user Grandec would be troublesome.

If you like I can upload a sample site using apache shiro against a sample AD auth. I already have an example shiro AD site : https://github.com/vahidhedayati/customshiro but if you like I can upload the more customised chat version bootstrapped already etc.

moniman commented 9 years ago

Hi vahidhedayati,

I acces to the chat with this url : /wsChat/chat

Since the 1.14, I have this exception :

java.lang.RuntimeException: It looks like you are missing some calls to the r:layoutResources tag. After rendering your page the following have not been rendered: [defer] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:408) at org.springsource.loaded.ri.ReflectiveInterceptor.jlrConstructorNewInstance(ReflectiveInterceptor.java:1002) at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77) at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:102) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190) at org.grails.plugin.resource.DevModeSanityFilter.doFilter(DevModeSanityFilter.groovy:54) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.switchuser.SwitchUserFilter.doFilter(SwitchUserFilter.java:181) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) at com.the6hours.grails.springsecurity.facebook.FacebookAuthRedirectFilter.doFilter(FacebookAuthRedirectFilter.groovy:46) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter.doFilter(OAuth2AuthenticationProcessingFilter.java:140) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:69) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658) at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)

moniman commented 9 years ago

For authentification, I have an idea

UrlMapping : "/chat"(controller: "home", action: "chat") "/chat/room"(controller: "wsChat", action: "chat") "/wsChat"(view: "/error/404") "/wsChat/chat"(view: "/error/404")

HomeController : @Secured(['ROLE_USER']) def chat() { session.wschatuser = springSecurityService.getCurrentUser().username redirect(controller: "wsChat", action: "chat") }

moniman commented 9 years ago

and with 1.13 version, on my test server, I have this error in chrome console

Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state. wschat-aace7fb43a8f9ad1eb97086424d90b8e.js:46 sendMessage wschat-aace7fb43a8f9ad1eb97086424d90b8e.js:46 (anonymous function) room:596 m.event.dispatch jquery.min-ac124bf54878ec7f20b578d3e627d6a8.js:3 r.handle jquery.min-ac124bf54878ec7f20b578d3e627d6a8.js:3

vahidhedayati commented 9 years ago

sorry only read the last one,

The message you are seeing in 1.14.. have you enabled security on it i.e. has anything changed ?

I have had a look at the index + chat pages and it does attempt to load in the layout tag if not xhr request.

you doing anything different like an ajax remote request to /wsChat/chat page ?

when you go to /wsChat/chat is it through the normal wsChat/index method that then redirects after you give a chat name ?

Let me know and I will try to see if anything is wrong in the code... i haven't noticed it as yet..

In regards to security / and or a totally different method of trying the same thing to see what the result is - would be to :

try tag lib call

To see what this does.. With this method your chat page could be on any gsp folder/location you wish and youcould then give out a totally different url / and security against it - a further gsp / controller check for user validity before serving your page that will just call the taglib and pass in the username..

I think includeStyle on that gsp page should now be sufficient and you may not need includeAllStyle..

This is how I have done it UrlMappings.groovy

"/" {
            controller = "chatter"
            action = "index"
         }

ChatterController

def index() {
        def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
        def curl= g.createLink(controller: 'chatter', action: 'index', absolute: 'true' )

        if (session.user) {
            def dbSupport=grailsApplication.config.wschat.dbsupport ?: 'yes'
            def chatuser=userService.returnRealUser(session.user)
            chatuser=chatuser.trim().replace(' ', '_').replace('.', '_')
            //session.wschatuser=chatuser
            def dbrooms
            def room=grailsApplication.config.wschat.rooms[0]
            if (dbSupport.toString().toLowerCase().equals('yes')) {
                dbrooms=ChatRoomList?.get(0)?.room
            }
            if (dbrooms) {
                room=dbrooms
            } else if (!room && !dbrooms) {
                room='wschat'
            }

            //session.wschatroom=room

            [chatuser:chatuser, room:room]
        }else{
            session.lastURL=curl
            flash.message="You must be logged in to use this feature"

        }
    }

views/chatter/index.gsp:

<html>
<head>
<meta name="layout" content="main" />
<title><g:message code="myapp.title" default="My Chat" /></title>
</head>
<body>
<div class="container">
<br>
    <g:if test="${flash.message}">
        <div class="message" role="status">${flash.message}</div>
    </g:if>

<div id="homeBox">

</div>

<g:if test="${!session.user }">
    <g:render template="/auth/loginForm" model="[did: 'homeBox']"/>
</g:if>
<g:else>

<g:render template="/navbar"/>  
<div class="container">
<br><br>
    <chat:connect chatuser="${chatuser}" room="${room }"/>
    </div>
</g:else>
</div>

</body>
</html>

and it was working fine under 2.4.4 with this way of calling it (Tested at work on production), with this method this is now a page within this existing application that I am running and has all the layout as per my own site.....

This site in question is an existing bootstrapped site so I did not need to call the extra tags:

<chat:includeAllStyle/> or <chat:includeStyle/>
before calling 
<chat:connect/>

If you followed above example you may need to add the chat:includeStyle/ at the top of index.gsp somewhere...

The 1.13 looks like it was related to rooms list being sent... I Think there were a load of issues with 1.13 user/room list hoping its now sorted.

moniman commented 9 years ago

Hi vahidhedayati

I edit this post because the stacktrace is due to ":resources:1.2.13"

I added this plugin for try another plugin.

Now I remove it and it work good on my localhost.

I'll try to server and I will tell you !

moniman commented 9 years ago

There is still an error on server :

with firebug :

InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable ...ocket.send("DISCO:-"+user),$("#chatMessages").append(user+" disconnecting from s... wschat-...0b8e.js (ligne 46)

Firefox can't establish a connection to the server at ws://myapp.net/WsChatEndpoint/chatroom. var webSocket=new WebSocket(uri);

with chome : Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.

my config : wschat.title='Chat' wschat.heading='Official Chat' environments { development { wschat.hostname="localhost:8080/myapp" } production { wschat.hostname="myapp.net" } } wschat.timeout=0 wschat.camtimeout=0 wschat.dbsupport='YES' wschat.defaultperm='user' wschat.rooms = ['chatroom'] wschat.showtitle="YES" wschat.add.appName='no' wschat.disable.login = "yes" wschat.dbsupport='YES' wschat.dbstore=true wschat.dbstore_pm_messages=true wschat.dbstore_room_messages=true wschat.dbstore_user_messages=true stunServers { iceServers=[ [url: 'stun:stun.l.google.com:19302'] ] }

And UrlMapping "/chat/room"(controller: "wsChat", action: "chat")

vahidhedayati commented 9 years ago

Hi MoniMan,

I have tried your config and except the environment/add.appName config, it works fine for me in development mode.

I am wondering if this could be related to the significant domainClass changes that occured during 1.11- current.

The changes actually means your best off removing any db tables related to wsChat - if possible test on a fresh db to see if it makes any difference..

Btw is there any stack traces on the backend app when this happens to you?

In regards to resources plugin... this was the old method pre assets, wondering what it was for. I know the last time I tried the plugin kickstart-with-bootstrap it had this dependency which is why in the end I ended up using the styling of this plugin and doing it my own way

I have now uploaded my prod project of the kchat wrapper which uses shiro auth against AD, I have manually added bootstrap and reused the style of kickstart-with-bootstrap.

https://github.com/vahidhedayati/kchat

If that was the plugin you were trying to make work - then maybe you can use above projest as the example to get the styling to work under latest grails.

vahidhedayati commented 9 years ago

Did you get it working ? If you have already filled up a load of db info and either setting db to create or creating the tables from scratch is going to cause lots of issues let me know. I should be able to write a few lines of mysql to manually update the missing relations that would be required as part of the upgrade... as in the few lines you could then manually run yourself on your own mysql db

moniman commented 9 years ago

Hi !

Sorry for the late (holidays)

It' not works.

With firebug : Firefox can't establish a connection to the server at ws://myapp.com/WsChatEndpoint/boulangers. var webSocket=new WebSocket(uri);

Realy stange, works on localhost and not on Azure VM.

I removed all tables before try with 1.14

What can I do to help you ?

EDIT : I don't touch the db I'll see it tomorrow

vahidhedayati commented 9 years ago

Hi Moniman I have released 1.14-SNAPSHOT1, please try this and with this version enable the following config item:

wschat.debug="on"

Now try running this in prod and your test.

  1. You will see lots of messages on your actual app console - or tomcat logs - showing messages incomming/outgoing.
  2. Open development console / web console on your browser and you should see the connection + any messages coming in .

hopefully with this - comparing the logs of working against / your prod not working - we should be able to identify where abouts its going wrong ..

Regards Vahid

moniman commented 9 years ago

Hi. Sorry for late. I'm now not working on the grails project. Maybe in 2 or 3 weeks. but I understand the problem : The grails aplication is hosted in Azure and behind a nginx I don't know why, it's not work in the Vm but work on a tomcat on my computer.

vahidhedayati commented 9 years ago

but was the older code working before in production ?

vahidhedayati commented 9 years ago

I presume this is all sorted. Will close it - reopen it or create a new case if you still are having issues

vahidhedayati commented 8 years ago

Spring security has now been added to Grails 3 version of the plugin: watch video 12 wschat 3.0.9 release.

If this is what you are after and are still on grails 2 well it can be added to grails 2, its just all consuming a lot of my time at the moment so if that is the case I can look at it in the next few weeks