Server : 3 ClientManager - 17chuchu/AutomaticBicycleInterface GitHub Wiki

Table of Contents

ClientManager.py

ClientManager is a child class of WebSocket. It is used to connect to client's react web-application that serves as an interface for a video stream and a controller for a bike. ClientManager.py is located in server/ServerApplication/component/MeansManager.py

Initializing

Run a Thread that will keep this class running. This code is located at server/ServerApplication/urls.py.

ClientManager.py.initManager()  # line 18

Port

ClientManager is a web socket server so it needs a port. You can customize its port number here.

meansport = 7001.  # line 20

Client To String

This function will transform the Client model in models.py into a dictionary of string.

@staticmethod  # line 92
    def clienttoString(client):
        info = dict()
        info["id"] = client.id
        info["autoritytag"] = client.autoritytag
        info["username"] = client.username
        info["password"] = ""
        info["email"] = client.email
        return json.dumps(info)

Validate Token

This function will check if the token is valid or not. If this token has been created for 5 minute, it will be invalid.

@staticmethod  # line 102
def validateToken(token):
    diff = datetime.datetime.now() - ClientManager.__tokenTimer[token]
    form = diff.total_seconds()
    return diff >= 300

Refresh Token

This function will refresh a token. It will always be called when a user does some action. For example, request for a video stream or ask for control of a bike.

@staticmethod. # line 108
def refreshToken(token):
    ClientManager.__tokenTimer[token] = datetime.datetime.now()

Login

This function will validate the username and password sent by a user. Then give the user a new token to access other services.

@staticmethod # line 112
def login(request):
    data = json.loads(request)

    # User can log in with either email or username
    if ("username" in data):  # Find a client with this username.
        userlist = Client.objects.filter(username=data["username"], password=data["password"])
    elif ("email" in data):   # Find a client with this email.
        userlist = Client.objects.filter(email=data["email"], password=data["password"])
    else:
        return ClientComment.generateLoginComment("Login Unsuccessful.")


    if (len(userlist) != 0):
        loginUser = userlist[0]
    else:
        return ClientComment.generateLoginComment("Login Unsuccessful.")

    if (loginUser.id in ClientManager.__loginUser):  # If the user already login, assign new token to the user. (In case one user login at the same time, only the newest user will be valid)
        authToken = ClientManager.__loginUser[loginUser.id]
    else:
        authToken = str(uuid.uuid4()).replace("-", "")  # Generate new token.
        ClientManager.__loginUser[authToken] = loginUser.id  # Load the token into the dictionary.

    token = ClientComment.generateLoginComment(authToken)
    ClientManager.refreshToken(authToken)  # Refresh the loaded token.
    userlist[0].password = ""  # Empty the user's password before sending. (Security measure)
    token['info'] = ClientManager.clienttoString(userlist[0])  # Turn user's data into a dictionary of string.

    return token # Return the data.

Visitor Login

In case a user don't want to login. That user will be automaically logged in as a visitor.

@staticmethod  # line 143
def loginVisitor(request):
    data = json.loads(request)
    if("visitorid" in data):
        authToken = str(uuid.uuid4()).replace("-", "")  # Generate a new token without having to verify anything.
        ClientManager.__loginUser[authToken] = "id"+str(uuid.uuid4())  # Save that token with new randomize id. (The id is not important because every survice only need )
        ClientManager.refreshToken(authToken)
        token = ClientComment.generateLoginComment(authToken)
        return token
    return None

Check Bike

Check if the bike you are looking for is connected to the server or not.

@staticmethod  # line 155
def checkbike(request):
    data = json.loads(request)
    pack = dict()
    pack["isBikeOnline"] = "Offline"
    pack["bikeid"] = data["bikeid"]

    if("bikeid" in data):  # If the bike is connected give it "Online" status.
        if(data["bikeid"] in BicycleManager.bicycleid):
            pack["isBikeOnline"] = "Online"

    comment = ClientComment.generateCheckBikeComment(pack)
    return comment

Ask For Video

This function will send the room id (unique id) of a room that a client needs to join in order to receive the video stream.

@staticmethod. # line 169
def askforvideo(request):
    data = json.loads(request)

    data['token'] = ClientManager.clientroom[data['bikeid']]  # Give the client room id based on an id of the targeted bike.
    return ClientComment.generateAskForVideo(data)

Bind To Bike

Bind the user to bike. This function will validate the token before sending it to BikeManager.py.

@staticmethod  # line = 190
def bindtobike(request,token):
    data = json.loads(request)
    if(token in ClientManager.__loginUser):
        result = BicycleManager.bindToBike(data['status'],data['bikeid'],ClientManager.__loginUser[token])
        if(type(result) == float):  # If the bike can not be joined. Result will be float, which is the amount of seconds that you need to wait.
            return ClientComment.generateAskForControl(float(result))

Give Direction

Send user inputs to the selected bike, which has to be sent to BikeManager.py

@staticmethod  # line = 183
def givedirection(request,token):
    data = json.loads(request)
    if (token in ClientManager.__loginUser):  # If the given token is valid, send the input to BicycleManager.
        BicycleManager.sendDirection(data["direction"],data["bikeid"],ClientManager.__loginUser[token])

ClientComment.py

ClientComment is a class that provides a template to create packages of information to be sent to and receive from clents. ClientComment.py is located in server/ServerApplication/component/Comment/ClientComment.py

class ClientComment:
    Login = 1         # These integers are used to identify what survice that the package is sent for.
    CheckBike = 2
    AskForVideo = 3
    GiveDirection = 4
    AskForControl = 5
    Visitorlogin = 6

    @staticmethod
    def generateLoginComment(comment):
        data = dict()
        data['code'] = ClientComment.Login  # For above integers.
        data['pack'] = comment  # For the information that need to be sent with this package.
        return data