<filename>controller/mn_socket.py
import threading
import socket
import globals 
from netstatistics import ApStatisticsManager, StaStatisticsManager 
from utilities import socket_context
import socket 

LAST_BYTE_COUNT = 'last_byte_count'
ACTUAL_BYTE_COUNT = 'actual_byte_count'
UPLOAD = 'upload'
DOWNLOAD = 'download'


class MNSocket():
    sta_statistics = StaStatisticsManager() 

    def __init__(self, host, port, request_timer, semaphore):
        self.host = host
        self.port = port
        self.semaphore = semaphore
        #self.request_timer = request_timer


    def mn_send(prepared_message):
        def wrapper_function(self, *args, **kwargs):
            msg = prepared_message(self, *args, **kwargs)
            if msg == None: return

            if self.semaphore == 'sta' :
                with globals.sta_socket_semaphore:  
                    try:
                        self.sock = socket.socket()
                        self.sock.settimeout(0.5)
                        self.sock.connect((self.host, self.port))

                        self.sock.send(msg.encode('utf-8'))
                        msg = self.sock.recv(1024).decode('utf-8')
                        self.sock.close()
                    except (socket.timeout, EOFError) as e:
                        print(e)
                        return"<>"
                    return msg.replace("[", "").replace("]", "")
            else: 
                with globals.socket_semaphore as s:
                    try:
                        self.sock = socket.socket()
                        self.sock.settimeout(0.5)
                        self.sock.connect((self.host, self.port))

                        self.sock.send(msg.encode('utf-8'))
                        msg = self.sock.recv(1024).decode('utf-8')
                        self.sock.close()
                    except (socket.timeout, EOFError) as e:
                        print(e)
                        return"<>"
                    return msg.replace("[", "").replace("]", "")
        return wrapper_function

    @mn_send
    def get_ap_associations(self, ap_name):
        return "get." + ap_name + ".wintfs[0].associatedStations"

    @mn_send
    def get_sta_ip(self, sta_name):
        if sta_name == None: return 
        return "get." + sta_name + ".wintfs[0].ip"

    @mn_send
    def get_sta_mac(self, sta_name):
        if sta_name == None: return 
        return "get." + sta_name + ".wintfs[0].mac"

    @mn_send
    def get_sta_channel(self, sta_name):
        if sta_name == None: return 
        return "get." + sta_name + ".wintfs[0].channel"

    @mn_send
    def get_sta_rssi(self, sta_name):
        if sta_name == None: return 
        return "get." + sta_name + ".wintfs[0].rssi"

    @mn_send
    def get_sta_association(self, sta_name):
        if sta_name == None: return 
        return "get." + sta_name + ".wintfs[0].associatedTo"

    @mn_send
    def calulate_specific_rssi(self, sta_name, ap_name):
        if sta_name == None: return 
        return "set." + sta_name + ".set_specific_rssi(" +ap_name+")"  

    @mn_send
    def get_specific_rssi_value(self, sta_name):
        if sta_name == None: return 
        return "get."+ sta_name + ".wintfs[0].specific_rssi" 

    def get_specific_rssi(self, sta_name, ap_name):
        self.calulate_specific_rssi(sta_name,ap_name)
        return self.get_specific_rssi_value(sta_name).replace("(","").replace(")","").replace("'","").split(",")


    def get_associations(self, access_point):
        associations = {}
        ap = access_point
        name = ap["ports"][0]["name"].rsplit("-", 1)[-2]
        # getting and parsing information from mininet
        if len(self.get_ap_associations(name).split('<')) > 1:
            associations[name] = list(map(lambda x: x.rsplit(" ", 1)[-1].rsplit(
                "-", 1)[-2], self.get_ap_associations(name).replace(">", "").replace("<", "").split(",")))
        return associations

    def get_associated_stations_info(self, access_point):
        stations_info = {}
        ap = access_point
        # getting and parsing information from mininet
        if len(self.get_ap_associations(ap["name"]).split('<')) > 1:
            stations = list(map(lambda x: x.rsplit(" ", 1)[-1].rsplit(
                "-", 1)[-2], self.get_ap_associations(ap_name).replace(">", "").replace("<", "").split(",")))

            for sta in stations:
                if ap["name"] in stations_info:
                    stations_info[ap["name"]][sta] = self.get_station_info(
                        sta)
                else:
                    stations_info[ap["name"]] = {}
                    stations_info[ap["name"]][sta] = self.get_station_info(
                        sta)
        else:
            stations_info[ap["name"]] = {}
        return stations_info
    
    def get_station_info(self, station):
        if station == None: return
        info = {}
        info['name'] = station
        info['rssi'] = self.get_sta_rssi(station)
        info['ip'] = self.get_sta_ip(station)
        info['mac'] = self.get_sta_mac(station)
        info['channel'] = self.get_sta_channel(station)
        info['associated_to'] = self.get_sta_association(station).split("-")[0]
        #info['s_bytes'], info['s_throughput'] = self.sta_statistics.get_station_statistics(
        #   info['mac'], UPLOAD)
        #info['d_bytes'], info['d_throughput'] = self.sta_statistics.get_station_statistics(
        #    info['mac'], DOWNLOAD)
        #print(info)
        return info

    @mn_send
    def handover(self, station, new_ap):
       return "set."+ station + ".do_handover(" + new_ap + ")"