> On Apr 29, 2015, at 12:33 AM, Jessica Tsui <[email protected]> wrote:
> 
> Hi, it's me again. I am still working on the kivy app, and now I am trying to 
> add a function to the app - the server side has two seconds to decide if he 
> wants to alter the original data sent from one client to other clients. If he 
> would like to do so, he has to press a button. If he does not press the 
> button in 2 seconds, the original data will be sent to other clients 
> automatically.
> 
> Right now I am trying to achieve that with the following code - by calling 
> the MultiClientEcho().dataReceived(msg, "censored") line in the function as 
> if MultiClientEcho received another data, however once i click the button, 
> the program crashed and said (MultiClientEcho().dataReceived(msg, "censored")
>  TypeError: __init__() takes exactly 3 arguments (1 given))

The first problem here is that "MultiEchoClient()" means "create a new 
MultiEchoClient".  Since MultiEchoClient.__init__ takes "factory" and "app" 
parameters, you tried to create it with 1 parameter (just "self", which is 
passed implicitly) instead of the required 3 (self, factory, app).

The second problem, once you've addressed that, is that you almost certainly 
don't want to create a new MultiEchoClient :).  It's not clear to me which 
MultiEchoClient you are trying to send this message to.

The third problem is that you should never call dataReceived yourself.  
dataReceived is a method invoked by Twisted to tell your protocol that data has 
arrived.

The fourth problem is that you're treating dataReceived as delivering a 
discrete message.  It doesn't; it delivers a segment of some data in the stream 
coming from a client.  This is our most popular FAQ; basically, you need to use 
a NetstringReceiver or something to ensure you're getting complete messages in 
dataReceived: 
https://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#Whyisprotocol.dataReceivedcalledwithonlypartofthedataIcalledtransport.writewith
 
<https://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#Whyisprotocol.dataReceivedcalledwithonlypartofthedataIcalledtransport.writewith>

Hopefully once you've addressed all these it will work more like you want it to 
:).

> I wonder how can I fix this and achieve the function I am aiming at?

I've put other comments inline in the code below.
> import kivy
> from kivy.app import App
> from kivy.uix.label import Label
> from kivy.uix.scatter import Scatter
> from kivy.uix.boxlayout import BoxLayout
> from kivy.uix.scrollview import ScrollView
> from kivy.uix.button import Button
> from kivy.graphics.vertex_instructions import Rectangle
> from kivy.graphics.context_instructions import Color
> from kivy.graphics.instructions import Instruction
> from kivy.base import runTouchApp
> from kivy.lang import Builder
> import socket
You don't actually use "socket" anywhere in this module so you don't need to 
import it :).
> from kivy.core.window import Window
> import pygame
> import random
> from kivy.support import install_twisted_reactor
> install_twisted_reactor()
> from twisted.internet import protocol, defer
> from time import sleep
> from twisted.internet import reactor, task
> from twisted.protocols.basic import LineReceiver
> from twisted.internet.protocol import Protocol, Factory
> 
> censored = 0
> 
> class MultiClientEcho(protocol.Protocol):
>     def __init__(self, factory, app):
>         self.factory = factory
>         self.app = app
> 
>     def connectionMade(self):
>         self.factory.clients.append(self)
> 
>     def dataReceived(self, data):
> 
>         storedmessage = self.factory.app.handle_message(data)
> 
>         global censored
> 
Rather than making this a global variable, consider putting it (as with "app" 
and with "clients") onto the factory, so you can instantiate multiple 
MultiClientEchoFactory instances in one process.
>         def f(data):
>                 for client in self.factory.clients:
This is a bit too much indentation - you should stick to 4 spaces per indent 
for stylistic reasons :).
>                     client.transport.write(data)
>                     print "this will run in 1 sec after it's scheduled: %s" % 
> data
> 
>         if censored == 0 and storedmessage:
>                 reactor.callLater(2, f, data)
You're not hanging on to the result of this callLater call, which means you are 
giving up any way of stopping this call from happening in the future.  If you 
want to allow the caller to cancel it, note that reactor.callLater returns an 
IDelayedCall, which has a "cancel()" method that stops it from happening if it 
hasn't happened yet.  See the API documentation here; 
https://twistedmatrix.com/documents/15.1.0/api/twisted.internet.interfaces.IReactorTime.callLater.html
 
<https://twistedmatrix.com/documents/15.1.0/api/twisted.internet.interfaces.IReactorTime.callLater.html>
 
>                 # client.transport.write(data)
>         elif censored == 1:
>                 reactor.callLater(0, f, 'censored')
>                 censored == 0
I think maybe you mean "censored = 0" here? "censored == 0" just means "compare 
censored to 0" which will create a True or False value but otherwise do 
nothing; in this context, it pretty much means "do nothing".
> 
>     def connectionLost(self, reason):
>         self.factory.clients.remove(self)
> 
> 
> class MultiClientEchoFactory(protocol.Factory):
>     protocol = MultiClientEcho
> 
>     def __init__(self, app):
>         self.clients = []
>         self.app = app
> 
>     def buildProtocol(self, addr):
>         return MultiClientEcho(self, self.app)
> 
> 
> class ServerApp(App):
>     def build(self):
>         self.label = Label(text="server started\n")
> 
> 
>         self.approve_btn = Button(text="approve")
>         # self.approve_btn.bind(on_release=self.send_message)
>         self.banned_btn = Button(text="banned")
>         self.banned_btn.bind(on_release=self.banned_message)
>         self.layout = BoxLayout(orientation='vertical', spacing=10)
> 
>         reactor.listenTCP(8000, MultiClientEchoFactory(self))
> 
Rather than calling listenTCP directly, you should be using some kind of 
Endpoint here; TCP4ServerEndpoint if you just want to hard code port 8000, or 
serverFromString if you want to allow your user to customize it.  See this 
document: https://twistedmatrix.com/documents/15.1.0/core/howto/endpoints.html 
<https://twistedmatrix.com/documents/15.1.0/core/howto/endpoints.html>        
self.layout.add_widget(self.label)
>         self.layout.add_widget(self.banned_btn)
> 
>         return self.layout
> 
>     def banned_message(self, msg):
>         global censored
>         censored = 1
>         self.label.text += "censored\n"
>         MultiClientEcho().dataReceived(msg, "censored")
>         print censored
>         return censored
> 
>     def handle_message(self, msg):
>         self.label.text += "%s\n" % msg
>         return msg
> 
> 
> if __name__ == '__main__':
>     ServerApp().run()
> 
> for i in range(0,1):
>     print 1-i
>     sleep(0.1)
> 
> 
> 

Thanks again for using Twisted!

-g

_______________________________________________
Twisted-Python mailing list
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to