예제 #1
0
    def __init__(self):
        pg.init()
        pg.display.set_caption("Platformer")

        self.running = True
        self.win = pg.display.set_mode((WIDTH, HEIGHT))
        self.platforms = Platforms()
        self.player = Player()
        self.bgEnts = BgEnts()
        self.clock = pg.time.Clock()
        self.clock.tick()
예제 #2
0
def init(p1_actions):
  global player
  for i in range(height //100):
    for j in range(width // 100):
      plat = Platforms(random.randint(5, (width - 50) // 10) *10, 120 * i, 70, 40)
      platforms.add(plat)
  player = Player((platforms.sprites()))[-1].rect.centerx, platforms.sprites()[-1].rect.centery-300, p1_actions, sprite_list.add(player)
예제 #3
0
def init():
    for i in range(height // 100):
        for j in range(width // 420):
            plat = Platforms(
                (random.randint(5, (width - 50) // 10) * 10, 120 * i),
                'images/grassHalf.png', 70, 40)
            platforms.add(plat)
예제 #4
0
    def __init__(self, system_settings, websocket, snmp_websocket, **kwargs):
        super(SleepyMeshBase, self).__init__(**kwargs)

        if 'last_syncs' not in self._defaults:
            self._defaults.update({'last_syncs': list()})

        # Internal Members #
        self._mesh_awake = True
        self._sync_type = 'timeout'

        self._save_in_progress = False

        self._sync_average = None
        self._delay_average = None

        # Instances #
        # TODO: Eliminate as many dependencies as possible
        self.system_settings = system_settings
        self.websocket = websocket
        self.snmp_websocket = snmp_websocket

        self.modbus_server = ModbusServer()
        self.snmp_server = SNMPTrapServer(self)
        self.update_interfaces = UpdateInterfaces(self)
        self.update_in_progress = self.update_interfaces.update_in_progress

        self.bridge = Bridge(self.system_settings)
        self.uploader = Uploader(self)

        self.nodes = Nodes(self.system_settings)
        self.platforms = Platforms(self.nodes)
        self.networks = Networks(self)

        self.error = BaseError(self.system_settings)

        if self.system_settings.modbus_enable:
            system_settings_dict = self.system_settings.attr_dict()
            # LOGGER.debug('Modbus Attribute Dictionary: ' + str(system_settings_dict))
            self.modbus_server.start(system_settings_dict)

        if self.system_settings.snmp_enable:
            self.snmp_server.start()

            # Overload Node Error Methods (SNMP Error Methods)#
            NodeError.send_snmp = self.snmp_server.send_snmp
            NodeError.clear_snmp = self.snmp_server.clear_snmp
예제 #5
0
def init(p1_actions):
    global player
    for i in range(height // 100):
        for j in range(width // 420):
            plat = Platforms((random.randint(5, (width - 50) // 10) * 10,  120 * i), './basic/images/grassHalf.png', 70, 40)
            platforms.add(plat)
    player = Player((platforms.sprites()[-1].rect.centerx, platforms.sprites()[-1].rect.centery-300), p1_actions)
    sprite_list.add(player)
예제 #6
0
class Main:
    def __init__(self):
        pg.init()
        pg.display.set_caption("Platformer")

        self.running = True
        self.win = pg.display.set_mode((WIDTH, HEIGHT))
        self.platforms = Platforms()
        self.player = Player()
        self.bgEnts = BgEnts()
        self.clock = pg.time.Clock()
        self.clock.tick()

    # For key press and close button functionality
    def check_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.running = False

    # Update things
    def update(self):
        self.bgEnts.update()
        self.player.update(self.platforms.rects)

    # Draw things
    def render(self):
        self.win.fill(BLACK)
        self.bgEnts.render()
        self.platforms.render(self.win, self.player)
        self.player.render(self.win)
        pg.display.update()

    # The main loop
    def loop(self):
        while self.running:
            self.check_events()
            self.update()
            self.render()
            physics.dt = self.clock.tick(FPS) / 1000
        pg.quit()
        sys.exit()
예제 #7
0
def init(p1_actions):
    # new above  ********************************************************************
    for i in range(height // 100):
        for j in range(width // 420):
            plat = Platforms(
                (random.randint(5, (width - 50) // 10) * 10, 120 * i),
                'images/grassHalf.png', 70, 40)
            platforms.add(plat)
        # new follows *************************************************
    player = Player((platforms.sprites()[-1].rect.centerx,
                     platforms.sprites()[-1].rect.centery - 300), p1_actions)
    sprite_list.add(player)
예제 #8
0
 def new_game(self, game_level = 1):
     running = True
     platforms = []
     for i in Screen.PLATFORM_LOCATIONS[(game_level-1) % 5]:
         platforms.append(Platforms(self.surface, *i))
     platform_rects = [i.rect for i in platforms]
     player = Player(self.surface)
     collectables = Collectables(self.surface)
     ship = Ship(self.surface)
     enemies = []
     self.reset(running, player, ship, platforms, platform_rects, enemies, collectables, game_level)
     if game_level == 1 :
         music.load(Screen.GAME_MUSIC)
         music.play(-1)
예제 #9
0
class JumpGame(Animation):

    def getplatforms(num,L,L2,width1,width2,height1,height2):
        #beginning platforms
        count,ok,newlist = 0,True,L2
        while count < num:
            check = Platforms(random.randint(width1,width2),\
                random.randint(height1,height2))
            for platform in L:
                #go through every platform to check overlap
                if platform.checkoverlap(check.x,check.y):
                    ok = False
                    break
                #check other list to check overlap
            if ok == True:
                for platform in L2:
                    if platform.checkoverlap(check.x,check.y):
                        ok = False
                        break
                #if no overlaps, add platform to list
            if ok:
                newlist.append(check)
                count+=1
            ok = True #reset, increment by one
        return newlist

    def latergetplatforms(L,L2,width1,width2,height):
        #add platforms during the game
        count,ok,newlist = 0,True,L2
        while count < 1:
            check = Platforms(random.randint(width1,width2),\
                height)
            #check platforms in list for overlap
            for platform in L:
                if platform.checkoverlap(check.x,check.y):
                    ok = False
                    break
            if ok == True:
                #check platforms in other list for overlap
                for platform in L2:
                    if platform.checkoverlap(check.x,check.y):
                        ok = False
                        break
            if ok:
                newlist.append(check)
                count+=1
            ok = True #increment by one, reset
        return newlist

    def init(self):
        self.mode = "mainmenu"

        self.module = Module(self.width//2,self.height//2+10)
        self.essentialplatforms = [Platforms(self.width//2,self.height-20),\
        Platforms(random.randint(0,350),self.height-80),\
        Platforms(random.randint(0,350),self.height-140),\
        Platforms(random.randint(0,350),self.height-200),\
        Platforms(random.randint(0,350),self.height-260),\
        Platforms(random.randint(0,350),self.height-320),\
        Platforms(random.randint(0,350),self.height-380)]
        #essential platforms for prevention of getting "stuck"
        self.platforms = []
        self.platforms = JumpGame.getplatforms(10,self.essentialplatforms,\
            self.platforms,0,350,20,370)
        #additional platforms scattered around.
        self.aliens = []
        self.projectiles = []
        self.enemyaircraft = []
        self.enemyprojectiles = []
        self.powerups = []

        self.startmodule = MainMenuModule(self.width//2+self.width//4+7,\
            self.height//2+50)
        self.startplatform = Platforms(self.width//2+self.width//4-10,\
            self.height - 30)

        self.instructionsmodule = MainMenuModule(self.width//10,105)
        self.instructionsalien = Alien(self.width//18,160)

        self.instructionsaircraft = EnemyAircraft(self.width//15+30,100)

        self.ground = 350

        self.maxplatforms = 10
        self.maxaliens = 2
        self.maxenemyaircrafts = 1 #max is for overload prevention
        self.maxenemyprojectiles = 7
        self.maxpowerups = 2
        self.deployable = True
        self.hitcount = 5
        self.aircrafthit = False


        self.movejump = True
        self.storage = None
        self.background = \
        PhotoImage(\
        file="/Users/Edward/Desktop/TermProject/Images/background1.gif")
        #https://media.giphy.com/media/8xK1CusSFTI0U/giphy.gif
        self.score = 0
        self.once = False #for updating aliens
        self.gameover = False
        self.fuel = False
        self.fuelscore = None
        self.protection = False
        self.protectionscore = None
        self.fuelprotection = False #for when on fuel
        self.donespeed = None
        self.extrajumps = 3
        self.extrajumpscore = 0
        self.canshoot = True
        self.canshoottime = 0
        self.oldcanshoottime = 0
        self.ringcolor = "gold"

        self.dx = 0
        self.dy = -10

        ###RACE
        self.computer = Computer(self.width//2,self.height//2+10)
        self.currentplatform = None
        self.targetplatform = None
        self.oldtargetplatform = None
        self.movement = None
        self.first = False
        self.stopmoving = False
        self.racescore = 0
        self.youwin = False
        self.youlose = False
        self.finishline = True
        self.finish = []


####################################
# mode dispatcher
####################################

#directory for all mousePressed, keyPressed, timerFired, and reDrawAlls
    def mousePressed(self,event):
        if (self.mode == "mainmenu"):
            JumpGame.mainmenuMousePressed(self,event)
        elif (self.mode == "spacejump"):
            JumpGame.spacejumpMousePressed(self,event)
        elif (self.mode == "instructions"):
            JumpGame.instructionsMousePressed(self,event)
        elif (self.mode == "instructionstwo"):
            JumpGame.instructionstwoMousePressed(self,event)
        elif(self.mode == "training"):
            JumpGame.trainingMousePressed(self,event)
        elif(self.mode == "race"):
            JumpGame.raceMousePressed(self,event)


    def keyPressed(self,event):
        if (self.mode == "mainmenu"):
            JumpGame.mainmenuKeyPressed(self,event)
        elif (self.mode == "spacejump"):
            JumpGame.spacejumpKeyPressed(self,event)
        elif (self.mode == "instructions"):
            JumpGame.instructionsKeyPressed(self,event)
        elif (self.mode == "instructions2:"):
            JumpGame.instructionstwoKeyPressed(self,event)
        elif (self.mode == "training"):
            JumpGame.trainingKeyPressed(self,event)
        elif(self.mode=="race"):
            JumpGame.raceKeyPressed(self,event)

    def timerFired(self):
        if (self.mode == "mainmenu"):
            JumpGame.mainmenuTimerFired(self)
        elif (self.mode == "spacejump"):
            JumpGame.spacejumpTimerFired(self)
        elif (self.mode == "instructions"):
            JumpGame.instructionsTimerFired(self)
        elif (self.mode == "instructionstwo"):
            JumpGame.instructionstwoTimerFired(self)
        elif (self.mode == "training"):
            JumpGame.trainingTimerFired(self)
        elif (self.mode == "race"):
            JumpGame.raceTimerFired(self)

    def redrawAll(self):
        if (self.mode == "mainmenu"):
            JumpGame.mainmenuRedrawAll(self)
        elif (self.mode == "spacejump"):
            JumpGame.spacejumpRedrawAll(self)
        elif (self.mode == "instructions"):
            JumpGame.instructionsRedrawAll(self)
        elif (self.mode == "instructionstwo"):
            JumpGame.instructionstwoRedrawAll(self)
        elif (self.mode == "training"):
            JumpGame.trainingRedrawAll(self)
        elif (self.mode == "race"):
            JumpGame.raceRedrawAll(self)

###### main menu ######


    def mainmenuMousePressed(self,event):
        # if click is in range, then change mode.
        if event.x > self.width//2-30 and event.x < self.width//2+30 and\
        event.y > self.height//2-15 and event.y < self.height//2+15:
            self.mode = "spacejump"
        elif event.x > self.width//2-45 and event.x < self.width//2+45 and\
        event.y>self.height//2+30 and event.y<self.height//2+60:
            self.mode = "instructions"
        elif event.x >= self.width//2-40 and event.x <= self.width//2+40 and\
        event.y>=self.height//2+75 and event.y<=self.height//2+105:
            self.mode = "training"
        elif event.x >= self.width//2-30 and event.x <= self.width//2+30 and\
        event.y>=self.height//2+120 and event.y<=self.height//2+150:
            self.mode = "race"


    def mainmenuKeyPressed(self,event):
        pass

    def mainmenuTimerFired(self):
        #for decoration, aesthetics 
        if self.startplatform.collide(self.startmodule.x,self.startmodule.x\
            +self.startmodule.width,self.startmodule.y+self.startmodule.height):
            self.startmodule.jump(self.startmodule.y+self.startmodule.height)
        self.startmodule.update(self.width,self.height)


    def mainmenuRedrawAll(self):
        self.canvas.create_image(0,0,anchor="nw",image=self.background)
        self.canvas.create_text(self.width//2,75,text="Space Jump",font=\
            "Arial 54",fill="white")
        self.canvas.create_rectangle(self.width//2-30,self.height//2-15,\
            self.width//2+30,self.height//2+15,fill="brown")
        self.canvas.create_text(self.width//2,self.height//2,text="Play")
        self.canvas.create_rectangle(self.width//2-45,self.height//2+30,\
            self.width//2+45,self.height//2+60,fill="brown")
        self.canvas.create_text(self.width//2,self.height//2+45,text=\
            "Instructions")
        self.canvas.create_rectangle(self.width//2-40,self.height//2+75,\
            self.width//2+40,self.height//2+105,fill="brown")
        self.canvas.create_text(self.width//2,self.height//2+90,\
            text="Training")
        self.canvas.create_rectangle(self.width//2-30,self.height//2+120,\
            self.width//2+30,self.height//2+150,fill="brown")
        self.canvas.create_text(self.width//2,self.height//2+135,\
            text="Race")
        self.startplatform.draw(self.canvas)
        self.startmodule.draw(self.canvas)
        


####### SPACE JUMP ##########
    def spacejumpMousePressed(self,event):
        #calculate slope
        x1 = event.x
        y1 = event.y
        x2 = self.module.x+self.module.width//4+8
        y2 = self.module.y-10
        #difference yields general direction
        dx = (x1-x2)/20
        #dy always makes bullet go up
        dy = -10

        if y1 < self.module.y - 10:
            self.dx = dx
            self.dy = dy
            



    def spacejumpKeyPressed(self,event):
        if event.keysym == "Left":
            if self.module.speed > 0:
                self.module.speed = -1
            if self.module.speed >= -self.module.maxspeed:
                self.module.speed -= 2 #increase speed left
        elif event.keysym == "Right":
            if self.module.speed < 0:
                self.module.speed = 1
            if self.module.speed <= self.module.maxspeed:
                self.module.speed += 2 #increase speed right
        elif event.keysym == "Up":
            if not self.gameover and self.canshoot:
                self.projectiles.append(Projectile(self.module.x+\
                    self.module.width//4+8,self.module.y-10,self.dx,\
                    self.dy))
                self.canshoot = False
                self.oldcanshoottime = 0
                self.canshoottime = 0
        elif event.keysym == "Down":
            if self.module.upspeed > 0 and self.extrajumps > 0:
                self.module.jump(self.module.y)
                self.extrajumps -= 1
        if event.keysym == "b":
            
            JumpGame.init(self)

    def spacejumpTimerFired(self):
        if self.module.y+self.module.height>=self.height+12:
            self.gameover = True
        self.once = False
        if not self.gameover:
            #determine when fuel and protection end:
            if self.fuel and self.score-self.fuelscore >= 450:
                self.fuel = False
                self.ringcolor = "white"
                self.donespeed = self.module.upspeed
            if self.fuelprotection and not self.fuel and self.module.upspeed>=0:
                self.fuelprotection = False
                self.ringcolor = "gold"
            if self.protection and self.score-self.protectionscore>=1500:
                self.ringcolor="white"
            if self.protection and self.score-self.protectionscore>=2000:
                self.protection = False
                self.ringcolor = "gold"
            
            negatupspeed = -self.module.upspeed #increment speed for everything

            #check for collide in essential platforms
            for eplatform in self.essentialplatforms:
                if eplatform.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y+self.module.height):
                    #only jump if the module is moving downwards
                    if self.module.upspeed>0:
                        self.module.jump(self.module.y+self.module.height)
                #remove essential platforms if they move off the screen
                if eplatform.y >= self.height + 15:
                    self.essentialplatforms.remove(eplatform)
                    #add back new one no matter what
                    self.essentialplatforms = JumpGame.latergetplatforms(\
                        self.platforms,self.essentialplatforms,0,350,-15)

            #check for collide in regular platforms
            for platform in self.platforms:
                if platform.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y+self.module.height):
                    if self.module.upspeed > 0:
                        self.module.jump(self.module.y+self.module.height)
               

                #if platform moves off the screen, remove it from the list
                if platform.y >= self.height-15:
                    self.platforms.remove(platform)
                    if len(self.platforms) < self.maxplatforms:
                        #only add if length of list less than max.
                        self.platforms = JumpGame.latergetplatforms(\
                            self.essentialplatforms,self.platforms\
                            ,0,350,-15)

            #if module is passed the halfway mark
            if self.module.tempy<=self.height//2 and self.module.upspeed<0:
                #everything on the screen except for module moves accordingly
                #to the increment negatupspeed
                for eplatform in self.essentialplatforms:
                    eplatform.y += negatupspeed
                    self.score+=1
                for platform in self.platforms:
                    platform.y += negatupspeed
                for powerup in self.powerups:
                    powerup.y += negatupspeed
                    if powerup.y+powerup.height >= self.height:
                        self.powerups.remove(powerup)
                        #remove powerup from list if off the screen
                if self.aliens != [] and not self.once:
                    for alien in self.aliens:
                        alien.y += negatupspeed
                        if alien.y >= self.height:
                            self.aliens.remove(alien)
                            #remove alien if off screen
                    self.once = True

            #regarding aliens, jump on aliens/die from alien
            for alien in self.aliens:
                if alien.topcollide(self.module.x,self.module.x+self.module.\
                    width,self.module.y) and not self.protection and not \
                    self.fuelprotection:
                    #hit it from the bottom
                    self.gameover = True
                if alien.bottomcollide(self.module.x,self.module.x+self.module.\
                    width,self.module.y+self.module.height):
                    if self.module.upspeed > 0:
                        self.module.jump(self.module.y+self.module.height)
                        self.aliens.remove(alien)
                        #hit it from the top


            #projectiles
            for projectile in self.projectiles:
                #update projectile coordinates
                projectile.x += projectile.dx
                projectile.y += projectile.dy
                if projectile.y <= 0 or projectile.x <= 0 or \
                projectile.x >= self.width:
                #remove projectiles if off the screen
                    self.projectiles.remove(projectile)

            #if bullet hits alien, remove bullet and remove alien.
            for projectile in self.projectiles:
                for alien in self.aliens:
                    if alien.topcollide(projectile.x-projectile.r,projectile.x\
                        +projectile.r,projectile.y-projectile.r):
                        self.aliens.remove(alien)
                        self.projectiles.remove(projectile)

            #if bullet hits aircraft, remove bullet
            for projectile in self.projectiles:
                if self.enemyaircraft != []:
                    if self.enemyaircraft[0].collide(projectile.x-\
                        projectile.r,projectile.x+projectile.r,\
                        projectile.y-projectile.r):
                        self.hitcount -= 1
                        #5 hits to kill aircraft
                        self.aircrafthit = True
                        self.projectiles.remove(projectile)
                        if self.hitcount == 0:
                            self.enemyaircraft.pop()
                            self.hitcount = 5

            #powerups
            for powerup in self.powerups:
                if powerup.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y) or powerup.collide(\
                    self.module.x,self.module.x+self.module.width,\
                    self.module.y + self.module.height) and not \
                    self.fuelprotection:
                    self.powerups.remove(powerup)
                    #if collide with module, remove powerup,
                    #powerup effect in place.
                    self.ringcolor="gold"
                    if powerup.kind == "fuel":
                        self.fuelscore = self.score
                        self.fuelprotection = True
                        self.fuel = True
                    if powerup.kind == "protection":
                        self.protectionscore = self.score
                        self.protection = True

            #enemy aircraft and it's projectiles
            if self.enemyaircraft != []:
                #enemy aircraft moves according to the module's coordinates.
                if abs(self.enemyaircraft[0].x+self.enemyaircraft[0].width//2\
                    -self.module.x+self.module.width//2) < 3:
                    self.enemyaircraft[0].dx = 0
                elif self.enemyaircraft[0].x+self.enemyaircraft[0].width//2<\
                self.module.x+self.module.width//2:
                    self.enemyaircraft[0].dx = 5
                elif self.enemyaircraft[0].x+self.enemyaircraft[0].width//2>=\
                self.module.x+self.module.width//2:
                    self.enemyaircraft[0].dx = -5
                self.enemyaircraft[0].x += self.enemyaircraft[0].dx
                
                self.enemyaircraft[0].adjust(self.width)

            if self.enemyaircraft != [] and\
            len(self.enemyprojectiles) < self.maxenemyprojectiles and \
            random.randint(1,15)==6:
                #shoots bullets at random times
                self.enemyprojectiles.append(EnemyProjectile(\
                    self.enemyaircraft[0].x+self.enemyaircraft[0].width//2,\
                    self.enemyaircraft[0].y+self.enemyaircraft[0].height))

            #eprojectile collide
            for eprojectile in self.enemyprojectiles:
                eprojectile.y += eprojectile.dy
                if self.module.collide(eprojectile.x,eprojectile.x+\
                    eprojectile.width,eprojectile.y+eprojectile.height) and \
                    not self.protection and not self.fuelprotection:
                    self.enemyprojectiles.remove(eprojectile)
                    #if bullet hits you, game over.
                    self.gameover = True
                if eprojectile.y >= self.height:
                    self.enemyprojectiles.remove(eprojectile)

            #HIGHER YOU GO, MORE EXTRA JUMPS
            if self.score - self.extrajumpscore >= 3000:
                self.extrajumps += 1
                self.extrajumpscore = self.score

            #ADD aliens
            if self.score > 300 and len(self.aliens) < self.maxaliens and\
            random.randint(1,50) == 5:
                self.aliens.append(Alien(random.randint(0,self.width-30),\
                    -15))

            #CONTROL PROJECTILE SPAM
            self.module.update(self.width,self.height,self.fuel,\
                self.fuelprotection)
            self.canshoottime += 1
            if self.canshoottime - self.oldcanshoottime >= 4:
                self.canshoot = True

            #ADD ENEMY AIRCRAFT
            if self.score > 300 and len(self.enemyaircraft) <\
             self.maxenemyaircrafts and random.randint(1,250)==24:
                self.enemyaircraft.append(EnemyAircraft(10,10))
                #self.deployable = False

            #ADD POWERUP
            if self.score > 300 and len(self.powerups) <\
            self.maxpowerups and random.randint(1,100)==2:
                kind = random.randint(1,10) #randomly select kind of powerup
                #some being more frequent than others.
                if kind > 3:
                    self.powerups.append(Protection(random.randint(0,350),-15,\
                        "protection"))
                elif kind <=3:
                    self.powerups.append(Fuel(random.randint(0,350),-15,"fuel"))

            #for determining how many platforms will be on the screen at a 
            #certain score. In other words, determines difficulty

            if self.score > 1000 and self.score < 2000:
                self.maxplatforms = 9

            if self.score >=2000 and self.score <4000:
                self.maxplatforms = 8

            if self.score >= 4000 and self.score<5000:
                self.maxplatforms = 7

            if self.score>=5000 and self.score<6000:
                self.maxplatforms=6

            if self.score>=6000 and self.score<7000:
                self.maxplatforms=5

            if self.score>=7000:
                self.maxplatforms=4

    def spacejumpRedrawAll(self):
        #draws everything
        self.canvas.create_rectangle(-5,-5,500,500,fill="black")
        self.canvas.create_image(0,0,anchor="nw",image=self.background)
        for eplatform in self.essentialplatforms:
            eplatform.draw(self.canvas)
        for platform in self.platforms:
            platform.draw(self.canvas)
        for powerup in self.powerups:
            powerup.draw(self.canvas)
        for alien in self.aliens:
            alien.draw(self.canvas)
        for projectile in self.projectiles:
            projectile.draw(self.canvas)
        if not self.aircrafthit:
            for aircraft in self.enemyaircraft:
                aircraft.draw(self.canvas)
        self.aircrafthit = False
        for eprojectile in self.enemyprojectiles:
            eprojectile.draw(self.canvas)
        if self.protection or self.fuelprotection:
            self.canvas.create_oval(self.module.x-15,self.module.y-15,\
                self.module.x+self.module.width+15,self.module.y+\
                self.module.height+15,outline=self.ringcolor,width=7)
        self.module.draw(self.canvas)
        self.canvas.create_rectangle(0,0,self.width+20,30,fill="black")
        self.canvas.create_line(0,27,self.width+20,27,fill="white",\
            width = 3)
        self.canvas.create_text(5,5,anchor="nw",text="Score : "+\
            str(self.score),fill="white")
        self.canvas.create_text(100,5,anchor="nw",text="Extra Jumps: " + \
            str(self.extrajumps),fill="white")
        if self.gameover:
            self.canvas.create_image(self.module.x-5,self.module.y-55,\
                anchor="nw",image=self.module.deadphoto)
            self.canvas.create_rectangle(self.width//2-100,30,self.width//2+\
                100,130,fill="black",outline="white",width=3)

            self.canvas.create_text(self.width//2,70,\
                text="GAME OVER",fill="red",font="Arial 26")

            self.canvas.create_text(self.width//2,100,\
                text="Press (b) to escape",fill="white",\
                font="Arial 16")
            

### INSTRUCTIONS1 ###

#just design stuff

    def instructionsMousePressed(self,event):
        
        if event.x>=340 and event.x<=385 and event.y>=360 and event.y<=385:
            self.mode="instructionstwo"

    def instructionsKeyPressed(self,event):
        if event.keysym == "b":
            JumpGame.init(self)

    def instructionsTimerFired(self):
        pass

    def instructionsRedrawAll(self):
        self.canvas.create_image(0,0,anchor="nw",image=self.background)
        self.canvas.create_text(10,10,anchor="nw",\
            text="You're out in space \n\t and you've ran out of fuel......",\
            fill="white",font="Arial 18")
        self.canvas.create_text(self.width//2,60,anchor="n",\
            text="How to Play",fill="white",font="Arial 28")
        
        self.canvas.create_line(10,95,10,390,fill="white")
        self.canvas.create_line(10,95,390,95,fill="white")
        self.canvas.create_line(390,95,390,390,fill="white")
        self.canvas.create_line(10,390,390,390,fill="white")
        self.instructionsmodule.draw(self.canvas)
        self.canvas.create_text(self.width//4,105,anchor="nw",text=\
            "That's you, press left and right arrow keys\nto set direction",\
            fill="white")
        self.instructionsalien.draw(self.canvas)
        self.canvas.create_text(self.width//4,160,anchor="nw",text=\
            "Avoid aliens at all costs,\nunless you are able to jump on them",\
            fill="white")
        self.canvas.create_rectangle(self.width//14,240,self.width//14+50,255,\
        fill="gray")
        self.canvas.create_text(self.width//4,240,anchor="nw",\
            text="Jump on these to survive",fill="white")



        self.canvas.create_rectangle(self.width//10,290,self.width//10+25,290+\
            25,fill="cyan")
        self.canvas.create_oval(self.width//10,290,self.width//10+25,290+\
            25,fill="green")
        self.canvas.create_text(self.width//10+12,290+12,\
            text="P")

        self.canvas.create_rectangle(self.width//10,320,self.width//10+25,320+\
            25,fill="brown")
        self.canvas.create_oval(self.width//10,320,self.width//10+25,320+\
            25,fill="green")
        self.canvas.create_text(self.width//10+12,320+12,\
            text="F")
        self.canvas.create_text(self.width//4,300,text=\
"These are powerups. Try to get them.\nThey will help you \
stay alive\nor increase your score",\
        anchor="nw",fill="white")

        self.canvas.create_rectangle(340,360,385,385,fill="white",\
            outline="white")
        self.canvas.create_text(362,372,text="Next")

        

####INSTRUCTIONS TWO####

#just design stuff

    def instructionstwoMousePressed(self,event):
        if event.x>=10 and event.x<=55 and event.y>=355 and event.y<=390:
            self.mode = "instructions"
        if event.x>=340 and event.x<=385 and event.y>=360 and event.y<=385:
            JumpGame.init(self)

    def instructionstwpKeyPressed(self,event):
        if event.keysym == "b":
            JumpGame.init(self)

    def instructionstwoTimerFired(self):
        pass

    def instructionstwoRedrawAll(self):
        self.canvas.create_image(0,0,anchor="nw",image=self.background)
        self.canvas.create_text(10,10,anchor="nw",\
            text="You're out in space \n\t and you've ran out of fuel......",\
            fill="white",font="Arial 18")
        self.canvas.create_text(self.width//2,60,anchor="n",\
            text="How to Play",fill="white",font="Arial 28")
        self.canvas.create_line(10,95,10,390,fill="white")
        self.canvas.create_line(10,95,390,95,fill="white")
        self.canvas.create_line(390,95,390,390,fill="white")
        self.canvas.create_line(10,390,390,390,fill="white")
        
        self.instructionsaircraft.draw(self.canvas)
        self.canvas.create_text(self.width//2,140,\
            text="Be careful of the spaceships.\nThey will shoot at you.",\
            fill = "white",anchor="nw")

        self.canvas.create_text(self.width//2+4,260,text=\
    "To shoot, press the up key. You can control the\
    \ndirection of your shot by clicking in\nthe direction you prefer.",\
    fill="white")
        self.canvas.create_text(self.width//2+5,319,text=\
            "Your score increases the higher you go.",fill="white",\
            font="Arial 14")
        self.canvas.create_text(self.width//2+5,350,\
            text="Good luck!",fill="white",font="Arial 20")
        


        self.canvas.create_rectangle(15,360,60,385,fill="white",\
            outline="white")
        self.canvas.create_text(37,372,text="Back")

        self.canvas.create_rectangle(340,360,385,385,fill="white",\
            outline="white")
        self.canvas.create_text(362,372,text="Menu")




#### TRAINING MODE #######

    def trainingMousePressed(self,event):
        pass

    def trainingKeyPressed(self,event):
        if event.keysym == "Left":
            if self.module.speed > 0:
                self.module.speed = -1
            if self.module.speed >= -self.module.maxspeed:
                self.module.speed -= 2
        elif event.keysym == "Right":
            if self.module.speed < 0:
                self.module.speed = 1
            if self.module.speed <= self.module.maxspeed:
                self.module.speed += 2
        elif event.keysym == "Down":
            if self.module.upspeed > 0 and self.extrajumps > 0:
                self.module.jump(self.module.y)
                self.extrajumps -= 1
        if event.keysym == "b":
            JumpGame.init(self)
        

    def trainingTimerFired(self):
        if self.module.y+self.module.height>=self.height+12:
            #if module goes below the screen, game over
            self.gameover = True
        self.once = False
        if not self.gameover:
            negatupspeed = -self.module.upspeed #increment for everything

            for eplatform in self.essentialplatforms:
                #check collision
                if eplatform.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y+self.module.height):
                    if self.module.upspeed>0:
                        self.module.jump(self.module.y+self.module.height)
                if eplatform.y >= self.height + 15:
                    self.essentialplatforms.remove(eplatform)
                    self.essentialplatforms = JumpGame.latergetplatforms(\
                        self.platforms,self.essentialplatforms,0,350,-15)

            for platform in self.platforms:
                #check collision
                if platform.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y+self.module.height):
                    if self.module.upspeed > 0:
                        self.module.jump(self.module.y+self.module.height)


                    
            
                if platform.y >= self.height+15:
                    #if platform below screen, remove platform
                    self.platforms.remove(platform)
                    if len(self.platforms) < self.maxplatforms:
                        self.platforms = JumpGame.latergetplatforms(\
                            self.essentialplatforms,self.platforms\
                            ,0,350,-15)

            
            if self.module.tempy<=self.height//2 and self.module.upspeed<0:
                #add by increments
                for eplatform in self.essentialplatforms:
                    eplatform.y += negatupspeed
                    self.score += 1
                for platform in self.platforms:
                    platform.y += negatupspeed
                    

            self.module.update(self.width,self.height,False,False)

            #set max platforms for difficulty according to score

            if self.score > 200 and self.score < 400:
                self.maxplatforms = 9

            if self.score >=400 and self.score <600:
                self.maxplatforms = 7

            if self.score >= 600 and self.score<800:
                self.maxplatforms = 5

            if self.score>=800 and self.score<1000:
                self.maxplatforms=4

            if self.score>=1000 and self.score<1200:
                self.maxplatforms=3

            if self.score>=1200 and self.score<1400:
                self.maxplatforms=2

            if self.score>=1400:
                self.maxplatforms=2
        

    def trainingRedrawAll(self):
        self.canvas.create_rectangle(-5,-5,500,500,fill="black")
        self.canvas.create_image(0,0,anchor="nw",image=self.background)
        for platform in self.platforms:
            platform.draw(self.canvas)
        for eplatform in self.essentialplatforms:
            eplatform.draw(self.canvas)
        self.module.draw(self.canvas)#,self.gameover)
        self.canvas.create_rectangle(0,0,self.width+20,30,fill="black")
        self.canvas.create_line(0,27,self.width+20,27,fill="white",\
            width = 3)
        self.canvas.create_text(5,5,anchor="nw",text="Score : "+\
            str(self.score),fill="white")
        self.canvas.create_text(100,5,anchor="nw",text="Extra Jumps: " + \
            str(self.extrajumps),fill="white")
        if self.gameover:
            self.canvas.create_image(self.module.x-5,self.module.y-55,\
                anchor="nw",image=self.module.deadphoto)
            self.canvas.create_rectangle(self.width//2-100,30,self.width//2+\
                100,130,fill="black",outline="white",width=3)

            self.canvas.create_text(self.width//2,70,\
                text="GAME OVER",fill="red",font="Arial 26")

            self.canvas.create_text(self.width//2,100,\
                text="Press (b) to escape",fill="white",\
                font="Arial 16")

###RACING MODE

    def raceMousePressed(self,event):
        pass

    def raceKeyPressed(self,event):
        if event.keysym == "Left":
            if self.module.speed > 0:
                self.module.speed = -1
            if self.module.speed >= -self.module.maxspeed:
                self.module.speed -= 2
        elif event.keysym == "Right":
            if self.module.speed < 0:
                self.module.speed = 1
            if self.module.speed <= self.module.maxspeed:
                self.module.speed += 2
        elif event.keysym == "Down":
            if self.module.upspeed > 0 and self.extrajumps > 0:
                self.module.jump(self.module.y)
                self.extrajumps -= 1
        if event.keysym == "b":
            JumpGame.init(self)

    def raceTimerFired(self):
        if self.module.y+self.module.height>=self.height+12:
            self.gameover = True
            self.youlose = True
        if self.score >= 1800 and self.finishline:
            self.finish.append(Finish(0,-200,self.width))
            self.finishline = False
        if self.finish != []:
            if self.module.y <= self.finish[0].y:
                self.gameover = True
                self.youwin = True
            elif self.computer.y <= self.finish[0].y:
                self.gameover = True
                self.youlose = True

        

        if self.racescore>=4000:
            self.gameover = True
            self.youlose = True
        
        if not self.gameover:
            negatupspeed = -self.module.upspeed

            #check collision for both computer and you
            for eplatform in self.essentialplatforms:
                if eplatform.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y+self.module.height):
                    if self.module.upspeed>0:
                        self.module.jump(self.module.y+self.module.height)

                #computer collision
                if eplatform.collide(self.computer.x,self.computer.x+\
                    self.computer.width,self.computer.y+self.computer.height):
                    if self.computer.upspeed > 0:
                        self.computer.jump(self.computer.y+self.computer.height)
                        #set previously jumped on platform to currentplatform
                        self.currentplatform=eplatform
                        self.first,self.stopmoving = True,False
                        #set speed to 0 to stabalize
                        self.computer.speed = 0
                        for eplatform in self.essentialplatforms:
                            #find next target in terms of platforms
                            if eplatform.y<self.currentplatform.y and \
                            self.currentplatform.y-eplatform.y<=200:
                                self.targetplatform = eplatform
                                break

                #remove platforms if off screen
                if eplatform.y >= self.height + 15:
                    self.essentialplatforms.remove(eplatform)
                    self.essentialplatforms = JumpGame.latergetplatforms(\
                        self.platforms,self.essentialplatforms,0,350,-15)

            #check collide with regular platforms for yourself and computer
            for platform in self.platforms:
                if platform.collide(self.module.x,self.module.x+\
                    self.module.width,self.module.y+self.module.height):
                    if self.module.upspeed > 0:
                        self.module.jump(self.module.y+self.module.height)
                #computer collide
                if platform.collide(self.computer.x,self.computer.x+\
                    self.computer.width,self.computer.y+self.computer.height):
                    if self.computer.upspeed > 0:
                        self.computer.jump(self.computer.y+self.computer.height)
                        #set platform jumped off of to currentplatform
                        self.currentplatform = platform
                        self.first,self.stopmoving = True,False
                        #speed 0 to stabalize
                        self.computer.speed = 0
                        for eplatform in self.essentialplatforms:
                            if eplatform.y<self.currentplatform.y and \
                            self.currentplatform.y-eplatform.y<=200:
                            #look for next target in terms of platforms.
                                self.targetplatform = eplatform
                                break
                        
            #remove regular platform if off the screen
                if platform.y >= self.height+15:
                    self.platforms.remove(platform)
                    if len(self.platforms) < self.maxplatforms:
                        self.platforms = JumpGame.latergetplatforms(\
                            self.essentialplatforms,self.platforms\
                            ,0,350,-15)

            #if computer is bottom off screen
            if self.computer.y>=self.height+self.width//2:
                if random.randint(1,10)<11:
                    self.computer.y = self.height+160
                    self.computer.jump(self.computer.y+self.computer.height)
                    for eplatform in self.essentialplatforms:
                        #find target accordingly
                        if eplatform.y<self.computer.y+self.computer.height and\
                         self.computer.y+self.computer.height-eplatform.y<=250:
                            self.targetplatform = eplatform
                            break


            if self.module.tempy<=self.height//2 and self.module.upspeed<0:
                #add increments accordingly
                if self.finish != []:
                    self.finish[0].y += negatupspeed
                for eplatform in self.essentialplatforms:
                    eplatform.y += negatupspeed
                    self.score += 1
                for platform in self.platforms:
                    platform.y += negatupspeed
                self.computer.y += negatupspeed

            #If computer ahead, keep track of time with racescore
            if self.computer.y+self.computer.height<25:
                self.racescore += 5
            if self.computer.upspeed<0:
                self.racescore += 4
            #if computer in bounds, reset racescore to your score
            if self.computer.y<self.module.y and \
            self.module.y-self.computer.y<225:
                self.racescore = self.score + 100
            elif self.computer.y>self.module.y and \
            self.computer.y-self.module.y<300:
                self.racescore = self.score - 100

            if self.first:

                #determine distance between currentplatform and targetplatform
                if self.targetplatform != None and \
                self.targetplatform.x > self.currentplatform.x:
                    distance1 = self.targetplatform.x - self.currentplatform.x
                    distance2 = (self.width-self.targetplatform.x)+\
                    self.currentplatform.x
                    
                    
                elif self.targetplatform != None and self.targetplatform.x <=\
                 self.currentplatform.x:
                    distance1 = (self.width-self.currentplatform.x)+\
                    self.targetplatform.x
                    distance2 = self.currentplatform.x-self.targetplatform.x

                if distance1 <= distance2:
                    self.movement = "right"

                elif distance2 < distance1:
                    self.movement = "left"


                if self.movement == "right" and not self.stopmoving:
                    if self.computer.speed <= 0:
                        self.computer.speed = 4
                    if self.computer.speed <= self.computer.maxspeed:
                        self.computer.speed += 2

                if self.movement == "left" and not self.stopmoving:
                    if self.computer.speed > 0:
                        self.computer.speed = -4
                    if self.computer.speed >= -self.module.maxspeed:
                        self.computer.speed -= 2

                if  self.targetplatform != None and self.computer.x+\
                    self.computer.width//2>=self.targetplatform.x and\
                    self.computer.x+self.computer.width//2<=\
                    self.targetplatform.x+self.targetplatform.width\
                    and self.computer.y<=self.targetplatform.y:
                    #set computer speed to 0 once directly on top of target
                    #platform to ensure succesful landing
                    
                    self.computer.speed = 0
                    

            #update both

            self.computer.update(self.width,self.height,False,False)
            self.module.update(self.width,self.height,False,False)

            #set difficulty based off of how many platforms are on the screen

            if self.score > -1 and self.score < 300:
                self.maxplatforms = 9

            if self.score >=300 and self.score <600:
                self.maxplatforms = 8

            if self.score >= 600 and self.score<900:
                self.maxplatforms = 7

            if self.score>=900 and self.score<1200:
                self.maxplatforms=6

            if self.score>=1200 and self.score<1500:
                self.maxplatforms=5

            if self.score>=1500:
                self.maxplatforms=4


    def raceRedrawAll(self):
        self.canvas.create_rectangle(-5,-5,500,500,fill="black")
        self.canvas.create_image(0,0,anchor="nw",image=self.background)
        if self.finish != []:
            self.finish[0].draw(self.canvas)
        for platform in self.platforms:
            platform.draw(self.canvas)
        for eplatform in self.essentialplatforms:
            eplatform.draw(self.canvas)
        self.computer.draw(self.canvas)
        self.module.draw(self.canvas)
        self.canvas.create_rectangle(0,0,self.width+20,30,fill="black")
        self.canvas.create_line(0,27,self.width+20,27,fill="white",\
            width = 3)
        self.canvas.create_text(5,5,anchor="nw",text="Score : "+\
            str(self.score),fill="white")
        self.canvas.create_text(100,5,anchor="nw",text="Extra Jumps: " + \
            str(self.extrajumps),fill="white")
        if self.gameover and self.youwin:
            
            self.canvas.create_rectangle(self.width//2-100,30,self.width//2+\
                100,130,fill="black",outline="white",width=3)

            self.canvas.create_text(self.width//2,70,\
                text="YOU WIN",fill="green",font="Arial 26")

            self.canvas.create_text(self.width//2,100,\
                text="Press (b) to escape",fill="white",\
                font="Arial 16")

        if self.gameover and self.youlose:
            self.canvas.create_image(self.module.x-5,self.module.y-55,\
                anchor="nw",image=self.module.deadphoto)
            self.canvas.create_rectangle(self.width//2-100,30,self.width//2+\
                100,130,fill="black",outline="white",width=3)

            self.canvas.create_text(self.width//2,70,\
                text="YOU LOSE",fill="red",font="Arial 26")

            self.canvas.create_text(self.width//2,100,\
                text="Press (b) to escape",fill="white",\
                font="Arial 16")
예제 #10
0
    def __init__(self, webroot=DEFAULT_WEB_ROOT, users={},
                 topic_replace_list=[], **kwargs):
        """ Creates a `VolttronCentralAgent` object to manage instances.

         Each instances that is registered must contain a running
         `VolttronCentralPlatform`.  Through this conduit the
         `VolttronCentralAgent` is able to communicate securly and
         efficiently.

        :param config_path:
        :param kwargs:
        :return:
        """
        _log.info("{} constructing...".format(self.__class__.__name__))

        super(VolttronCentralAgent, self).__init__(enable_web=True, **kwargs)

        # Create default configuration to be used in case of problems in the
        # packaged agent configuration file.
        self._default_config = dict(
            webroot=os.path.abspath(webroot),
            users=users,
            topic_replace_list=topic_replace_list
        )

        self.vip.config.set_default("config", self._default_config)

        # Start using config store.
        self.vip.config.subscribe(self._configure,
                                  actions=["NEW", "UPDATE"],
                                  pattern="config")



        #
        # # During the configuration update/new/delete action this will be
        # # updated to the current configuration.
        # self.runtime_config = None
        #
        # # Start using config store.
        # self.vip.config.set_default("config", config)
        # self.vip.config.subscribe(self.configure_main,
        #                           actions=['NEW', 'UPDATE', 'DELETE'],
        #                           pattern="config")
        #
        # # Use config store to update the settings of a platform's configuration.
        # self.vip.config.subscribe(self.configure_platforms,
        #                           actions=['NEW', 'UPDATE', 'DELETE'],
        #                           pattern="platforms/*")
        #
        # # mapping from the real topic into the replacement.
        # self.replaced_topic_map = {}
        #
        # # mapping from md5 hash of address to the actual connection to the
        # # remote instance.
        # self.vcp_connections = {}
        #
        # # Current sessions available to the
        # self.web_sessions = None
        #
        # # Platform health based upon device driver publishes
        # self.device_health = defaultdict(dict)
        #
        # # Used to hold scheduled reconnection event for vcp agents.
        # self._vcp_reconnect_event = None
        #
        # # the registered socket endpoints so we can send out management
        # # events to all the registered session.
        self._websocket_endpoints = set()

        self._platforms = Platforms(self)

        self._platform_scan_event = None

        # Sessions that have been authentication with the system.
        self._authenticated_sessions = None
예제 #11
0
class VolttronCentralAgent(Agent):
    """ Agent for managing many volttron instances from a central web ui.

    During the


    """

    def __init__(self, webroot=DEFAULT_WEB_ROOT, users={},
                 topic_replace_list=[], **kwargs):
        """ Creates a `VolttronCentralAgent` object to manage instances.

         Each instances that is registered must contain a running
         `VolttronCentralPlatform`.  Through this conduit the
         `VolttronCentralAgent` is able to communicate securly and
         efficiently.

        :param config_path:
        :param kwargs:
        :return:
        """
        _log.info("{} constructing...".format(self.__class__.__name__))

        super(VolttronCentralAgent, self).__init__(enable_web=True, **kwargs)

        # Create default configuration to be used in case of problems in the
        # packaged agent configuration file.
        self._default_config = dict(
            webroot=os.path.abspath(webroot),
            users=users,
            topic_replace_list=topic_replace_list
        )

        self.vip.config.set_default("config", self._default_config)

        # Start using config store.
        self.vip.config.subscribe(self._configure,
                                  actions=["NEW", "UPDATE"],
                                  pattern="config")



        #
        # # During the configuration update/new/delete action this will be
        # # updated to the current configuration.
        # self.runtime_config = None
        #
        # # Start using config store.
        # self.vip.config.set_default("config", config)
        # self.vip.config.subscribe(self.configure_main,
        #                           actions=['NEW', 'UPDATE', 'DELETE'],
        #                           pattern="config")
        #
        # # Use config store to update the settings of a platform's configuration.
        # self.vip.config.subscribe(self.configure_platforms,
        #                           actions=['NEW', 'UPDATE', 'DELETE'],
        #                           pattern="platforms/*")
        #
        # # mapping from the real topic into the replacement.
        # self.replaced_topic_map = {}
        #
        # # mapping from md5 hash of address to the actual connection to the
        # # remote instance.
        # self.vcp_connections = {}
        #
        # # Current sessions available to the
        # self.web_sessions = None
        #
        # # Platform health based upon device driver publishes
        # self.device_health = defaultdict(dict)
        #
        # # Used to hold scheduled reconnection event for vcp agents.
        # self._vcp_reconnect_event = None
        #
        # # the registered socket endpoints so we can send out management
        # # events to all the registered session.
        self._websocket_endpoints = set()

        self._platforms = Platforms(self)

        self._platform_scan_event = None

        # Sessions that have been authentication with the system.
        self._authenticated_sessions = None

    def _configure(self, config_name, action, contents):
        """
        The main configuration for volttron central.  This is where validation
        will occur.

        Note this method is called:

            1. When the agent first starts (with the params from packaged agent
               file)
            2. When 'store' is called through the volttron-ctl config command
               line with 'config' as the name.

        Required Configuration:

        The volttron central requires a user mapping.

        :param config_name:
        :param action:
        :param contents:
        """
        config = self._default_config.copy()

        config.update(contents)

        users = config.get("users", None)

        if self._authenticated_sessions:
            self._authenticated_sessions.clear()

        if users is None:
            users = {}
            _log.warn("No users are available for logging in!")

        # Unregister all routes for vc and then re-add down below.
        self.vip.web.unregister_all_routes()

        self._authenticated_sessions = SessionHandler(Authenticate(users))

        self.vip.web.register_endpoint(r'/vc/jsonrpc', self.jsonrpc)

        self.vip.web.register_websocket(r'/vc/ws',
                                        self.open_authenticate_ws_endpoint,
                                        self._ws_closed,
                                        self._ws_received)

        self.vip.web.register_path(r'^/vc/.*',
                                   config.get('webroot'))

        # Start scanning for new platforms connections as well as for
        # disconnects that happen.
        self._scan_platform_connect_disconnect()

    @staticmethod
    def _get_next_time_seconds(seconds=10):
        now = get_aware_utc_now()
        next_time = now + datetime.timedelta(seconds=seconds)
        return next_time

    def _handle_platform_connection(self, platform_vip_identity):
        _log.info("Handling new platform connection {}".format(
            platform_vip_identity))

        platform = self._platforms.add_platform(platform_vip_identity)

    def _handle_platform_disconnect(self, platform_vip_identity):
        _log.warn("Handling disconnection of connection from identity: {}".format(
            platform_vip_identity
        ))
        # TODO send alert that there was a platform disconnect.
        self._platforms.disconnect_platform(platform_vip_identity)

    def _scan_platform_connect_disconnect(self):
        """
        Scan the local bus for peers that start with 'vcp-'.  Handle the
        connection and disconnection events here.
        """
        if self._platform_scan_event is not None:
            # This won't hurt anything if we are canceling ourselves.
            self._platform_scan_event.cancel()

        # Identities of all platform agents that are connecting to us should
        # have an identity of platform.md5hash.
        connected_platforms = set([x for x in self.vip.peerlist().get(timeout=5)
                                   if x.startswith('vcp-')])

        disconnected = self._platforms.get_platform_keys() - connected_platforms

        for vip_id in disconnected:
            self._handle_platform_disconnect(vip_id)

        not_known = connected_platforms - self._platforms.get_platform_keys()

        for vip_id in not_known:
            self._handle_platform_connection(vip_id)

        next_platform_scan = VolttronCentralAgent._get_next_time_seconds()

        # reschedule the next scan.
        self._platform_scan_event = self.core.schedule(
            next_platform_scan, self._scan_platform_connect_disconnect)


    def configure_platforms(self, config_name, action, contents):
        _log.debug('Platform configuration updated.')
        _log.debug('ACTION IS {}'.format(action))
        _log.debug('CONTENT IS {}'.format(contents))

    def open_authenticate_ws_endpoint(self, fromip, endpoint):
        """
        Callback method from when websockets are opened.  The endpoine must
        be '/' delimited with the second to last section being the session
        of a logged in user to volttron central itself.

        :param fromip:
        :param endpoint:
            A string representing the endpoint of the websocket.
        :return:
        """
        _log.debug("OPENED ip: {} endpoint: {}".format(fromip, endpoint))
        try:
            session = endpoint.split('/')[-2]
        except IndexError:
            _log.error("Malformed endpoint. Must be delimited by '/'")
            _log.error(
                'Endpoint must have valid session in second to last position')
            return False

        if not self._authenticated_sessions.check_session(session, fromip):
            _log.error("Authentication error for session!")
            return False

        _log.debug('Websocket allowed.')
        self._websocket_endpoints.add(endpoint)

        return True

    def _ws_closed(self, endpoint):
        _log.debug("CLOSED endpoint: {}".format(endpoint))
        try:
            self._websocket_endpoints.remove(endpoint)
        except KeyError:
            pass # This should never happen but protect against it anyways.

    def _ws_received(self, endpoint, message):
        _log.debug("RECEIVED endpoint: {} message: {}".format(endpoint,
                                                              message))

    @RPC.export
    def is_registered(self, address_hash=None, address=None):
        if address_hash is None and address is None:
            return False

        if address_hash is None:
            address_hash = PlatformHandler.address_hasher(address)

        return self._platforms.is_registered(address_hash)

    @RPC.export
    def get_publickey(self):
        """
        RPC method allowing the caller to retrieve the publickey of this agent.

        This method is available for allowing :class:`VolttronCentralPlatform`
        agents to allow this agent to be able to connect to its instance.

        :return: The publickey of this volttron central agent.
        :rtype: str
        """
        return self.core.publickey

    @RPC.export
    def unregister_platform(self, platform_uuid):
        _log.debug('unregister_platform')

        platform = self._registered_platforms.get(platform_uuid)
        if platform:
            connected = self._platform_connections.get(platform_uuid)
            if connected is not None:
                connected.call('unmanage')
                connected.kill()
            address = None
            for v in self._address_to_uuid.values():
                if v == platform_uuid:
                    address = v
                    break
            if address:
                del self._address_to_uuid[address]
            del self._platform_connections[platform_uuid]
            del self._registered_platforms[platform_uuid]
            self._registered_platforms.sync()
            context = 'Unregistered platform {}'.format(platform_uuid)
            return {'status': 'SUCCESS', 'context': context}
        else:
            msg = 'Unable to unregistered platform {}'.format(platform_uuid)
            return {'error': {'code': UNABLE_TO_UNREGISTER_INSTANCE,
                              'message': msg}}

    def _to_jsonrpc_obj(self, jsonrpcstr):
        """ Convert data string into a JsonRpcData named tuple.

        :param object data: Either a string or a dictionary representing a json document.
        """
        return jsonrpc.JsonRpcData.parse(jsonrpcstr)

    def jsonrpc(self, env, data):
        """ The main entry point for ^jsonrpc data

        This method will only accept rpcdata.  The first time this method
        is called, per session, it must be using get_authorization.  That
        will return a session token that must be included in every
        subsequent request.  The session is tied to the ip address
        of the caller.

        :param object env: Environment dictionary for the request.
        :param object data: The JSON-RPC 2.0 method to call.
        :return object: An JSON-RPC 2.0 response.
        """
        if env['REQUEST_METHOD'].upper() != 'POST':
            return jsonrpc.json_error('NA', INVALID_REQUEST,
                                      'Invalid request method, only POST allowed'
                                      )

        try:
            rpcdata = self._to_jsonrpc_obj(data)
            _log.info('rpc method: {}'.format(rpcdata.method))
            if rpcdata.method == 'get_authorization':
                args = {'username': rpcdata.params['username'],
                        'password': rpcdata.params['password'],
                        'ip': env['REMOTE_ADDR']}
                sess = self._authenticated_sessions.authenticate(**args)
                if not sess:
                    _log.info('Invalid username/password for {}'.format(
                        rpcdata.params['username']))
                    return jsonrpc.json_error(
                        rpcdata.id, UNAUTHORIZED,
                        "Invalid username/password specified.")
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))
                self.vip.web.register_websocket(
                    "/vc/ws/{}/management".format(sess),
                    self.open_authenticate_ws_endpoint,
                    self._ws_closed,
                    self._received_data)
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))

                gevent.sleep(1)
                return jsonrpc.json_result(rpcdata.id, sess)

            token = rpcdata.authorization
            ip = env['REMOTE_ADDR']
            _log.debug('REMOTE_ADDR: {}'.format(ip))
            session_user = self._authenticated_sessions.check_session(token, ip)
            _log.debug('SESSION_USER IS: {}'.format(session_user))
            if not session_user:
                _log.debug("Session Check Failed for Token: {}".format(token))
                return jsonrpc.json_error(rpcdata.id, UNAUTHORIZED,
                                          "Invalid authentication token")
            _log.debug('RPC METHOD IS: {}'.format(rpcdata.method))

            # Route any other method that isn't
            result_or_error = self._route_request(session_user,
                                                  rpcdata.id, rpcdata.method,
                                                  rpcdata.params)

        except AssertionError:
            return jsonrpc.json_error(
                'NA', INVALID_REQUEST, 'Invalid rpc data {}'.format(data))
        except Unreachable:
            return jsonrpc.json_error(
                rpcdata.id, UNAVAILABLE_PLATFORM,
                "Couldn't reach platform with method {} params: {}".format(
                    rpcdata.method,
                    rpcdata.params))
        except Exception as e:

            return jsonrpc.json_error(
                'NA', UNHANDLED_EXCEPTION, e
            )

        return self._get_jsonrpc_response(rpcdata.id, result_or_error)

    def _get_jsonrpc_response(self, id, result_or_error):
        """ Wrap the response in either a json-rpc error or result.

        :param id:
        :param result_or_error:
        :return:
        """
        if isinstance(result_or_error, dict):
            if 'jsonrpc' in result_or_error:
                return result_or_error

        if result_or_error is not None and isinstance(result_or_error, dict):
            if 'error' in result_or_error:
                error = result_or_error['error']
                _log.debug("RPC RESPONSE ERROR: {}".format(error))
                return jsonrpc.json_error(id, error['code'], error['message'])
        return jsonrpc.json_result(id, result_or_error)

    def _get_agents(self, instance_uuid, groups):
        """ Retrieve the list of agents on a specific platform.

        :param instance_uuid:
        :param groups:
        :return:
        """
        _log.debug('_get_agents')
        connected_to_pa = self._platform_connections[instance_uuid]

        agents = connected_to_pa.agent.vip.rpc.call(
            'platform.agent', 'list_agents').get(timeout=30)

        for a in agents:
            if 'admin' in groups:
                if "platformagent" in a['name'] or \
                                "volttroncentral" in a['name']:
                    a['vc_can_start'] = False
                    a['vc_can_stop'] = False
                    a['vc_can_restart'] = True
                else:
                    a['vc_can_start'] = True
                    a['vc_can_stop'] = True
                    a['vc_can_restart'] = True
            else:
                # Handle the permissions that are not admin.
                a['vc_can_start'] = False
                a['vc_can_stop'] = False
                a['vc_can_restart'] = False

        _log.debug('Agents returned: {}'.format(agents))
        return agents

    def _setupexternal(self):
        _log.debug(self.vip.ping('', "PING ROUTER?").get(timeout=3))

    def _configure_agent(self, endpoint, message):
        _log.debug('Configure agent: {} message: {}'.format(endpoint, message))

    def _received_data(self, endpoint, message):
        print('Received from endpoint {} message: {}'.format(endpoint, message))
        self.vip.web.send(endpoint, message)

    def set_setting(self, session_user, params):
        """
        Sets or removes a setting from the config store.  If the value is None
        then the item will be removed from the store.  If there is an error in
        saving the value then a jsonrpc.json_error object is returned.

        :param session_user: Unused
        :param params: Dictionary that must contain 'key' and 'value' keys.
        :return: A 'SUCCESS' string or a jsonrpc.json_error object.
        """
        if 'key' not in params or not params['key']:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid parameter key not set')
        if 'value' not in params:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid parameter key not set')

        config_key = "settings/{}".format(params['key'])
        value = params['value']

        if value is None:
            try:
                self.vip.config.delete(config_key)
            except KeyError:
                pass
        else:
            # We handle empt string here because the config store doesn't allow
            # empty strings to be set as a config store.  I wasn't able to
            # trap the ValueError that is raised on the server side.
            if value == "":
                return jsonrpc.json_error(params['message_id'],
                                          INVALID_PARAMS,
                                          'Invalid value set (empty string?)')
            self.vip.config.set(config_key, value)

        return 'SUCCESS'

    def get_setting(self, session_user, params):
        """
        Retrieve a value from the passed setting key.  The params object must
        contain a "key" to return from the settings store.

        :param session_user: Unused
        :param params: Dictionary that must contain a 'key' key.
        :return: The value or a jsonrpc error object.
        """
        config_key = "settings/{}".format(params['key'])
        try:
            value = self.vip.config.get(config_key)
        except KeyError:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid key specified')
        else:
            return value

    def get_setting_keys(self, session_user, params):
        """
        Returns a list of all of the settings keys so the caller can know
        what settings to request.

        :param session_user: Unused
        :param params: Unused
        :return: A list of settings available to the caller.
        """

        prefix = "settings/"
        keys = [x[len(prefix):] for x in self.vip.config.list()
                if x.startswith(prefix)]
        return keys or []

    def _handle_bacnet_props(self, session_user, params):
        platform_uuid = params.pop('platform_uuid')
        id = params.pop('message_id')
        _log.debug('Handling bacnet_props platform: {}'.format(platform_uuid))

        configure_topic = "{}/configure".format(session_user['token'])
        ws_socket_topic = "/vc/ws/{}".format(configure_topic)

        if configure_topic not in self._websocket_endpoints:
            self.vip.web.register_websocket(ws_socket_topic,
                                            self.open_authenticate_ws_endpoint,
                                            self._ws_closed, self._ws_received)

        def start_sending_props():
            response_topic = "configure/{}".format(session_user['token'])
            # Two ways we could have handled this is to pop the identity off
            # of the params and then passed both the identity and the response
            # topic.  Or what I chose to do and to put the argument in a
            # copy of the params.
            cp = params.copy()
            cp['publish_topic'] = response_topic
            cp['device_id'] = int(cp['device_id'])
            platform = self._platforms.get_platform(platform_uuid)
            _log.debug('PARAMS: {}'.format(cp))
            platform.call("publish_bacnet_props", **cp)

        gevent.spawn_later(2, start_sending_props)

    def _handle_bacnet_scan(self, session_user, params):
        platform_uuid = params.pop('platform_uuid')
        id = params.pop('message_id')
        _log.debug('Handling bacnet_scan platform: {}'.format(platform_uuid))

        if not self._platforms.is_registered(platform_uuid):
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))

        scan_length = params.pop('scan_length', 5)

        try:
            scan_length = float(scan_length)
            params['scan_length'] = scan_length
            platform = self._platforms.get_platform(platform_uuid)
            iam_topic = "{}/iam".format(session_user['token'])
            ws_socket_topic = "/vc/ws/{}".format(iam_topic)
            self.vip.web.register_websocket(ws_socket_topic,
                                            self.open_authenticate_ws_endpoint,
                                            self._ws_closed, self._ws_received)

            def start_scan():
                # We want the datatype (iam) to be second in the response so
                # we need to reposition the iam and the session id to the topic
                # that is passed to the rpc function on vcp
                iam_session_topic = "iam/{}".format(session_user['token'])
                platform.call("start_bacnet_scan", iam_session_topic, **params)

                def close_socket():
                    _log.debug('Closing bacnet scan for {}'.format(
                        platform_uuid))
                    gevent.spawn_later(2,
                                       self.vip.web.unregister_websocket,
                                       iam_session_topic)

                gevent.spawn_later(scan_length, close_socket)

            # By starting the scan a second later we allow the websocket
            # client to subscribe to the newly available endpoint.
            gevent.spawn_later(2, start_scan)
        except ValueError:
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))
        except KeyError:
            return jsonrpc.json_error(id, UNAUTHORIZED,
                                      "Invalid user session token")

    def _enable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error enable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to enable setup mode")
        auth_file = AuthFile()
        entries = auth_file.find_by_credentials(".*")
        if len(entries) > 0:
            return "SUCCESS"

        entry = AuthEntry(credentials="/.*/",
                          comments="Un-Authenticated connections allowed here",
                          user_id="unknown")
        auth_file.add(entry)
        return "SUCCESS"

    def _disable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error disable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to disable setup mode")
        auth_file = AuthFile()
        auth_file.remove_by_credentials("/.*/")
        return "SUCCESS"

    def _handle_management_endpoint(self, session_user, params):
        ws_topic = "/vc/ws/{}/management".format(session_user.get('token'))
        self.vip.web.register_websocket(ws_topic,
                                        self.open_authenticate_ws_endpoint,
                                        self._ws_closed, self._ws_received)
        return ws_topic

    def send_management_message(self, type, data={}):
        """
        Send a message to any socket that has connected to the management
        socket.

        The payload sent to the client is like the following::

            {
                "type": "UPDATE_DEVICE_STATUS",
                "data": "this is data that was passed"
            }

        :param type:
            A string defining a unique type for sending to the websockets.
        :param data:
            An object that str can be called on.

        :type type: str
        :type data: serializable
        """
        management_sockets = [s for s in self._websocket_endpoints
                              if s.endswith("management")]
        # Nothing to send if we don't have any management sockets open.
        if len(management_sockets) <= 0:
            return

        if data is None:
            data = {}

        payload = dict(
            type=type,
            data=str(data)
        )

        payload = jsonapi.dumps(payload)
        for s in management_sockets:
            self.vip.web.send(s, payload)

    def _route_request(self, session_user, id, method, params):
        """ Handle the methods volttron central can or pass off to platforms.

        :param session_user:
            The authenticated user's session info.
        :param id:
            JSON-RPC id field.
        :param method:
        :param params:
        :return:
        """
        _log.debug(
            'inside _route_request {}, {}, {}'.format(id, method, params))

        def err(message, code=METHOD_NOT_FOUND):
            return {'error': {'code': code, 'message': message}}

        self.send_management_message(method)

        method_split = method.split('.')
        # The last part of the jsonrpc method is the actual method to be called.
        method_check = method_split[-1]

        # These functions will be sent to a platform.agent on either this
        # instance or another.  All of these functions have the same interface
        # and can be collected into a dictionary rather than an if tree.
        platform_methods = dict(
            # bacnet related
            start_bacnet_scan=self._handle_bacnet_scan,
            publish_bacnet_props=self._handle_bacnet_props,
            # config store related
            store_agent_config="store_agent_config",
            get_agent_config="get_agent_config",
            list_agent_configs="get_agent_config_list",
            # management related

            list_agents="get_agent_list",
            get_devices="get_devices",
            status_agents="status_agents"
        )

        # These methods are specifically to be handled by the platform not any
        # agents on the platform that is why we have the length requirement.
        #
        # The jsonrpc method looks like the following
        #
        #   platform.uuid.<dynamic entry>.method_on_vcp
        if method_check in platform_methods:

            platform_uuid = None
            if isinstance(params, dict):
                platform_uuid = params.pop('platform_uuid', None)

            if platform_uuid is None:
                if method_split[0] == 'platforms' and method_split[1] == 'uuid':
                    platform_uuid = method_split[2]

            if not platform_uuid:
                return err("Invalid platform_uuid specified as parameter"
                           .format(platform_uuid),
                           INVALID_PARAMS)

            if not self._platforms.is_registered(platform_uuid):
                return err("Unknown or unavailable platform {} specified as "
                           "parameter".format(platform_uuid),
                           UNAVAILABLE_PLATFORM)

            try:
                _log.debug('Calling {} on platform {}'.format(
                    method_check, platform_uuid
                ))
                class_method = platform_methods[method_check]
                platform = self._platforms.get_platform(platform_uuid)
                # Determine whether the method to call is on the current class
                # or on the platform object.
                if isinstance(class_method, basestring):
                    method_ref = getattr(platform, class_method)
                else:
                    method_ref = class_method
                    # Put the platform_uuid in the params so it can be used
                    # inside the method
                    params['platform_uuid'] = platform_uuid

            except AttributeError or KeyError:
                return jsonrpc.json_error(id, INTERNAL_ERROR,
                                          "Attempted calling function "
                                          "{} was unavailable".format(
                                              class_method
                                          ))

            except ValueError:
                return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                          "Couldn't connect to platform "
                                          "{}".format(platform_uuid))
            else:
                # pass the id through the message_id parameter.
                if not params:
                    params = dict(message_id=id)
                else:
                    params['message_id'] = id

                # Methods will all have the signature
                #   method(session, params)
                #
                return method_ref(session_user, params)

        vc_methods = dict(
            register_management_endpoint=self._handle_management_endpoint,
            list_platforms=self._platforms.get_platform_list,
            list_performance=self._platforms.get_performance_list,

            # Settings
            set_setting=self.set_setting,
            get_setting=self.get_setting,
            get_setting_keys=self.get_setting_keys,

            # Setup mode
            enable_setup_mode=self._enable_setup_mode,
            disable_setup_mode=self._disable_setup_mode
        )

        if method in vc_methods:
            if not params:
                params = dict(message_id=id)
            else:
                params['message_id'] = id
            response = vc_methods[method](session_user, params)
            _log.debug("Response is {}".format(response))
            return response  # vc_methods[method](session_user, params)

        if method == 'register_instance':
            if isinstance(params, list):
                return self._register_instance(*params)
            else:
                return self._register_instance(**params)
        elif method == 'unregister_platform':
            return self.unregister_platform(params['instance_uuid'])

        elif 'historian' in method:
            has_platform_historian = PLATFORM_HISTORIAN in \
                                     self.vip.peerlist().get(timeout=30)
            if not has_platform_historian:
                return err(
                    'The VOLTTRON Central platform historian is unavailable.',
                    UNAVAILABLE_AGENT)
            _log.debug('Trapping platform.historian to vc.')
            _log.debug('has_platform_historian: {}'.format(
                has_platform_historian))
            if 'historian.query' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'query', **params).get(timeout=30)
            elif 'historian.get_topic_list' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'get_topic_list').get(timeout=30)

        # This isn't known as a proper method on vc or a platform.
        if len(method_split) < 3:
            return err('Unknown method {}'.format(method))
        if method_split[0] != 'platforms' or method_split[1] != 'uuid':
            return err('Invalid format for instance must start with '
                       'platforms.uuid')
        instance_uuid = method_split[2]
        _log.debug('Instance uuid is: {}'.format(instance_uuid))
        if not self._platforms.is_registered(instance_uuid):
            return err('Unknown platform {}'.format(instance_uuid))
        platform_method = '.'.join(method_split[3:])
        _log.debug("Platform method is: {}".format(platform_method))
        platform = self._platforms.get_platform(instance_uuid)
        if not platform:
            return jsonrpc.json_error(id,
                                      UNAVAILABLE_PLATFORM,
                                      "cannot connect to platform."
                                      )

        if platform_method.startswith('install'):
            if 'admin' not in session_user['groups']:
                return jsonrpc.json_error(
                    id, UNAUTHORIZED,
                    "Admin access is required to install agents")

        return platform.route_to_agent_method(id, platform_method, params)

    def _validate_config_params(self, config):
        """
        Validate the configuration parameters of the default/updated parameters.

        This method will return a list of "problems" with the configuration.
        If there are no problems then an empty list is returned.

        :param config: Configuration parameters for the volttron central agent.
        :type config: dict
        :return: The problems if any, [] if no problems
        :rtype: list
        """
        problems = []
        webroot = config.get('webroot')
        if not webroot:
            problems.append('Invalid webroot in configuration.')
        elif not os.path.exists(webroot):
            problems.append(
                'Webroot {} does not exist on machine'.format(webroot))

        users = config.get('users')
        if not users:
            problems.append('A users node must be specified!')
        else:
            has_admin = False

            try:
                for user, item in users.items():
                    if 'password' not in item.keys():
                        problems.append('user {} must have a password!'.format(
                            user))
                    elif not item['password']:
                        problems.append('password for {} is blank!'.format(
                            user
                        ))

                    if 'groups' not in item.keys():
                        problems.append('missing groups key for user {}'.format(
                            user
                        ))
                    elif not isinstance(item['groups'], list):
                        problems.append('groups must be a list of strings.')
                    elif not item['groups']:
                        problems.append(
                            'user {} must belong to at least one group.'.format(
                                user))

                    # See if there is an adminstator present.
                    if not has_admin and isinstance(item['groups'], list):
                        has_admin = 'admin' in item['groups']
            except AttributeError:
                problems.append('invalid user node.')

            if not has_admin:
                problems.append("One user must be in the admin group.")

        return problems
예제 #12
0
파일: agent.py 프로젝트: yizenrg/volttron
    def __init__(self, config_path, **kwargs):
        """ Creates a `VolttronCentralAgent` object to manage instances.

         Each instances that is registered must contain a running
         `VolttronCentralPlatform`.  Through this conduit the
         `VolttronCentralAgent` is able to communicate securly and
         efficiently.

        :param config_path:
        :param kwargs:
        :return:
        """
        _log.info("{} constructing...".format(self.__class__.__name__))

        super(VolttronCentralAgent, self).__init__(enable_web=True, **kwargs)
        # Load the configuration into a dictionary
        config = utils.load_config(config_path)

        # Required users
        users = config.get('users', None)

        # Expose the webroot property to be customized through the config
        # file.
        webroot = config.get('webroot', DEFAULT_WEB_ROOT)
        if webroot.endswith('/'):
            webroot = webroot[:-1]

        topic_replace_list = config.get('topic-replace-list', [])

        # Create default configuration to be used in case of problems in the
        # packaged agent configuration file.
        self.default_config = dict(webroot=os.path.abspath(webroot),
                                   users=users,
                                   topic_replace_list=topic_replace_list)

        # During the configuration update/new/delete action this will be
        # updated to the current configuration.
        self.runtime_config = None

        # Start using config store.
        self.vip.config.set_default("config", config)
        self.vip.config.subscribe(self.configure_main,
                                  actions=['NEW', 'UPDATE', 'DELETE'],
                                  pattern="config")

        # Use config store to update the settings of a platform's configuration.
        self.vip.config.subscribe(self.configure_platforms,
                                  actions=['NEW', 'UPDATE', 'DELETE'],
                                  pattern="platforms/*")

        # mapping from the real topic into the replacement.
        self.replaced_topic_map = {}

        # mapping from md5 hash of address to the actual connection to the
        # remote instance.
        self.vcp_connections = {}

        # Current sessions available to the
        self.web_sessions = None

        # Platform health based upon device driver publishes
        self.device_health = defaultdict(dict)

        # Used to hold scheduled reconnection event for vcp agents.
        self._vcp_reconnect_event = None

        # the registered socket endpoints so we can send out management
        # events to all the registered session.
        self._websocket_endpoints = set()

        self._platforms = Platforms(self)

        self._platform_scan_event = None
        self._connected_platforms = dict()
예제 #13
0
class Exporter:

    global platforms
    platforms = Platforms()

    def __init__(self, datpath=None):

        # set default encoding to utf8 for parsing and logging
        # utf-8 characters in console and files
        #
        reload(sys)
        sys.setdefaultencoding('utf8')

        configure_logging(install_root_handler=False)
        logging.basicConfig(filename='export.log',
                            filemode='a',
                            format='%(levelname)s: %(message)s',
                            level=logging.INFO)

        self.datpath = datpath

        if datpath:

            # parse the xml dat file
            #
            self.gamestree = ET.parse(self.datpath).getroot()

            # identify platform
            #
            if self.gamestree.find('.//platform') is None:
                logging.error('No platform element found!')
                logging.error('Add a <platform/> xml element in the dat file.')
                logging.error(
                    'e.g.	<header>..<platform>Genesis</platform/>..</header>')
                return
            else:
                self.platform = self.gamestree.find('.//platform').text
                logging.info('Platform:' + self.platform)

            platformId = platforms.getId(self.platform)
            if platformId is None:
                logging.error('Platform ' + self.platform + ' not supported.')
                return

            # strip whitespace and remove text within parenetheses
            # from game names.
            # load adictionary with game name as key and a list
            # of the regions it released
            #
            # e.g. the folloging xml entry
            #
            # <game name="NBA Live 95 (USA, Europe)">
            #     <description>NBA Live 95 (USA, Europe)</description>
            #     <release name="NBA Live 95 (USA, Europe)" region="EUR"/>
            #     <release name="NBA Live 95 (USA, Europe)" region="USA"/>
            #     <rom name="NBA Live 95 (USA, Europe).md" size="2097152" crc="66018ABC" />
            # </game>
            #
            # is loaded in the games{} dictionary as:
            # {'NBA Live 95': ['EUR', 'USA']}
            #

            self.games = defaultdict(list)
            self.romnames = defaultdict(list)
            urls = []

            for g in self.gamestree.findall('game'):

                if not g.attrib.get('cloneof'):

                    # For Mame ( Arcade ) platform, read the name of the game
                    # from <description> tag.
                    # That is because MAME dat files, in the name attribute store
                    # the romname instead of the game title.
                    # This is an exception for the Arcade platform only.
                    #
                    if self.platform == 'Arcade':
                        name = self.normalizeName(g.find('./description').text)
                    else:
                        name = self.normalizeName(g.attrib.get('name'))
                    name = name.encode('utf-8')

                    if not name in self.games.keys():

                        romname = ''
                        rom = g.find('./rom/[1]')
                        if rom != None:
                            romname = rom.attrib.get('name')
                        self.romnames[name].append(romname)

                        releases = g.findall('release')
                        if releases:
                            for r in releases:
                                self.games[name].append(r.attrib.get('region'))
                        else:
                            self.games[name].append('Worldwide')

            for g in self.games:

                logging.debug('Submitting title:' + g + ':' +
                              str(self.games[g][0]))

                urls.append('http://mobygames.com/search/quick' + '?q=' + g +
                            '&p=' + platformId + '&search=Go'
                            '&sFilter=1'
                            '&sG=on'
                            '&search_title=' + urllib.quote(g) +
                            '&search_platform=' + urllib.quote(self.platform) +
                            '&search_region=' +
                            urllib.quote(self.games[g][0]) + '&romname=' +
                            urllib.quote(self.romnames[g][0]))

            process = CrawlerProcess(get_project_settings())
            process.crawl(MobygamesSpider, start_urls=urls)
            process.start()

        else:

            logging.warning('No dat file.')

    # strip all text in parentheses
    #
    def normalizeName(self, value):
        value = self.remove_parentheses(value)
        value = self.remove_brackets(value)
        return value.strip()

    # remove parentheses and text inside them
    def remove_parentheses(self, x):
        if '(' in x and ')' in x:
            x = re.sub('\(.*?\)', '', x)
        return x

    # remove brackets and text inside them
    def remove_brackets(self, x):
        if '[' in x and ']' in x:
            x = re.sub('\[.*?\]', '', x)
        return x
예제 #14
0
    def init(self):
        self.mode = "mainmenu"

        self.module = Module(self.width//2,self.height//2+10)
        self.essentialplatforms = [Platforms(self.width//2,self.height-20),\
        Platforms(random.randint(0,350),self.height-80),\
        Platforms(random.randint(0,350),self.height-140),\
        Platforms(random.randint(0,350),self.height-200),\
        Platforms(random.randint(0,350),self.height-260),\
        Platforms(random.randint(0,350),self.height-320),\
        Platforms(random.randint(0,350),self.height-380)]
        #essential platforms for prevention of getting "stuck"
        self.platforms = []
        self.platforms = JumpGame.getplatforms(10,self.essentialplatforms,\
            self.platforms,0,350,20,370)
        #additional platforms scattered around.
        self.aliens = []
        self.projectiles = []
        self.enemyaircraft = []
        self.enemyprojectiles = []
        self.powerups = []

        self.startmodule = MainMenuModule(self.width//2+self.width//4+7,\
            self.height//2+50)
        self.startplatform = Platforms(self.width//2+self.width//4-10,\
            self.height - 30)

        self.instructionsmodule = MainMenuModule(self.width//10,105)
        self.instructionsalien = Alien(self.width//18,160)

        self.instructionsaircraft = EnemyAircraft(self.width//15+30,100)

        self.ground = 350

        self.maxplatforms = 10
        self.maxaliens = 2
        self.maxenemyaircrafts = 1 #max is for overload prevention
        self.maxenemyprojectiles = 7
        self.maxpowerups = 2
        self.deployable = True
        self.hitcount = 5
        self.aircrafthit = False


        self.movejump = True
        self.storage = None
        self.background = \
        PhotoImage(\
        file="/Users/Edward/Desktop/TermProject/Images/background1.gif")
        #https://media.giphy.com/media/8xK1CusSFTI0U/giphy.gif
        self.score = 0
        self.once = False #for updating aliens
        self.gameover = False
        self.fuel = False
        self.fuelscore = None
        self.protection = False
        self.protectionscore = None
        self.fuelprotection = False #for when on fuel
        self.donespeed = None
        self.extrajumps = 3
        self.extrajumpscore = 0
        self.canshoot = True
        self.canshoottime = 0
        self.oldcanshoottime = 0
        self.ringcolor = "gold"

        self.dx = 0
        self.dy = -10

        ###RACE
        self.computer = Computer(self.width//2,self.height//2+10)
        self.currentplatform = None
        self.targetplatform = None
        self.oldtargetplatform = None
        self.movement = None
        self.first = False
        self.stopmoving = False
        self.racescore = 0
        self.youwin = False
        self.youlose = False
        self.finishline = True
        self.finish = []
예제 #15
0
    def __init__(self):

        # Settings

        pygame.mixer.init()

        pygame.mixer.music.load('latenight.ogg')
        pygame.mixer.music.play(0)

        self.WIDTH = 640
        self.HEIGHT = 360

        # Config
        self.tps_max = 100

        # Initialization
        pygame.init()
        font = pygame.font.SysFont("Arial", 18)
        self.resolution = (self.screen_width,
                           self.screen_height) = (self.WIDTH, self.HEIGHT)
        self.screen = pygame.display.set_mode(self.resolution,
                                              pygame.RESIZABLE)

        self.tps_clock = pygame.time.Clock()
        self.tps_delta = 0.0
        self.scroll = Vector2(0, 0)

        self.map = Map(self)
        self.player = Player(
            self
        )  # przy inicjalizacji przekazuje playerowi wszystko Player(self)
        self.enemy = Enemy(self)
        self.weapon = Weapon(self)
        self.fire = Fire(self)
        self.physics = Physics(self)
        self.platforms = Platforms(self)
        self.collision = Collision(self)
        self.sprite = Sprite(self)
        self.menu = Menu(self)
        self.file_loader = FileLoader(self)

        self.sprite.load_images()

        def create_fonts(font_sizes_list):
            "Creates different fonts with one list"
            fonts = []
            for size in font_sizes_list:
                fonts.append(pygame.font.SysFont("Arial", size))
            return fonts

        def render(fnt, what, color, where):
            "Renders the fonts as passed from display_fps"
            text_to_show = fnt.render(what, 0, pygame.Color(color))
            self.screen.blit(text_to_show, where)

        def display_fps():
            "Data that will be rendered and blitted in _display"
            render(fonts[0],
                   what=str(int(self.tps_clock.get_fps())),
                   color="white",
                   where=(0, 0))

        fonts = create_fonts([32, 16, 14, 8])
        while True:

            # Events
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit(0)
                elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:  ############# klik i cos sie dzieje raz
                    sys.exit(0)

            # Ticking
            self.tps_delta += self.tps_clock.tick(
            ) / 1000.0  # zamieniam MS na sekundy
            while self.tps_delta > 1 / self.tps_max:
                self.tick()
                self.tps_delta -= 1 / self.tps_max

            # Rendering/Drawing
            self.screen.fill((0, 0, 0))
            self.draw()
            display_fps()
            pygame.display.flip()
예제 #16
0
    def __init__(self, config_path, **kwargs):
        """ Creates a `VolttronCentralAgent` object to manage instances.

         Each instances that is registered must contain a running
         `VolttronCentralPlatform`.  Through this conduit the
         `VolttronCentralAgent` is able to communicate securly and
         efficiently.

        :param config_path:
        :param kwargs:
        :return:
        """
        _log.info("{} constructing...".format(self.__class__.__name__))

        super(VolttronCentralAgent, self).__init__(enable_web=True, **kwargs)
        # Load the configuration into a dictionary
        config = utils.load_config(config_path)

        # Required users
        users = config.get('users', None)

        # Expose the webroot property to be customized through the config
        # file.
        webroot = config.get('webroot', DEFAULT_WEB_ROOT)
        if webroot.endswith('/'):
            webroot = webroot[:-1]

        topic_replace_list = config.get('topic-replace-list', [])

        # Create default configuration to be used in case of problems in the
        # packaged agent configuration file.
        self.default_config = dict(
            webroot=os.path.abspath(webroot),
            users=users,
            topic_replace_list=topic_replace_list
        )

        # During the configuration update/new/delete action this will be
        # updated to the current configuration.
        self.runtime_config = None

        # Start using config store.
        self.vip.config.set_default("config", config)
        self.vip.config.subscribe(self.configure_main,
                                  actions=['NEW', 'UPDATE', 'DELETE'],
                                  pattern="config")

        # Use config store to update the settings of a platform's configuration.
        self.vip.config.subscribe(self.configure_platforms,
                                  actions=['NEW', 'UPDATE', 'DELETE'],
                                  pattern="platforms/*")

        # mapping from the real topic into the replacement.
        self.replaced_topic_map = {}

        # mapping from md5 hash of address to the actual connection to the
        # remote instance.
        self.vcp_connections = {}

        # Current sessions available to the
        self.web_sessions = None

        # Platform health based upon device driver publishes
        self.device_health = defaultdict(dict)

        # Used to hold scheduled reconnection event for vcp agents.
        self._vcp_reconnect_event = None

        # the registered socket endpoints so we can send out management
        # events to all the registered session.
        self._websocket_endpoints = set()

        self._platforms = Platforms(self)

        self._platform_scan_event = None
        self._connected_platforms = dict()
예제 #17
0
class VolttronCentralAgent(Agent):
    """ Agent for managing many volttron instances from a central web ui.

    During the


    """

    def __init__(self, config_path, **kwargs):
        """ Creates a `VolttronCentralAgent` object to manage instances.

         Each instances that is registered must contain a running
         `VolttronCentralPlatform`.  Through this conduit the
         `VolttronCentralAgent` is able to communicate securly and
         efficiently.

        :param config_path:
        :param kwargs:
        :return:
        """
        _log.info("{} constructing...".format(self.__class__.__name__))

        super(VolttronCentralAgent, self).__init__(enable_web=True, **kwargs)
        # Load the configuration into a dictionary
        config = utils.load_config(config_path)

        # Required users
        users = config.get('users', None)

        # Expose the webroot property to be customized through the config
        # file.
        webroot = config.get('webroot', DEFAULT_WEB_ROOT)
        if webroot.endswith('/'):
            webroot = webroot[:-1]

        topic_replace_list = config.get('topic-replace-list', [])

        # Create default configuration to be used in case of problems in the
        # packaged agent configuration file.
        self.default_config = dict(
            webroot=os.path.abspath(webroot),
            users=users,
            topic_replace_list=topic_replace_list
        )

        # During the configuration update/new/delete action this will be
        # updated to the current configuration.
        self.runtime_config = None

        # Start using config store.
        self.vip.config.set_default("config", config)
        self.vip.config.subscribe(self.configure_main,
                                  actions=['NEW', 'UPDATE', 'DELETE'],
                                  pattern="config")

        # Use config store to update the settings of a platform's configuration.
        self.vip.config.subscribe(self.configure_platforms,
                                  actions=['NEW', 'UPDATE', 'DELETE'],
                                  pattern="platforms/*")

        # mapping from the real topic into the replacement.
        self.replaced_topic_map = {}

        # mapping from md5 hash of address to the actual connection to the
        # remote instance.
        self.vcp_connections = {}

        # Current sessions available to the
        self.web_sessions = None

        # Platform health based upon device driver publishes
        self.device_health = defaultdict(dict)

        # Used to hold scheduled reconnection event for vcp agents.
        self._vcp_reconnect_event = None

        # the registered socket endpoints so we can send out management
        # events to all the registered session.
        self._websocket_endpoints = set()

        self._platforms = Platforms(self)

        self._platform_scan_event = None
        self._connected_platforms = dict()

    @staticmethod
    def _get_next_time_seconds(seconds=10):
        now = get_aware_utc_now()
        next_time = now + datetime.timedelta(seconds=seconds)
        return next_time

    def _handle_platform_connection(self, platform_vip_identity):
        _log.info("Handling new platform connection {}".format(
            platform_vip_identity))

        platform = self._platforms.add_platform(platform_vip_identity)

    def _handle_platform_disconnect(self, platform_vip_identity):
        _log.warn("Handling disconnection of connection from identity: {}".format(
            platform_vip_identity
        ))
        # TODO send alert that there was a platform disconnect.
        self._platforms.disconnect_platform(platform_vip_identity)

    def _scan_for_platforms(self):
        """
        Scan the local bus for peers that start with 'vcp-'.  Handle the
        connection and disconnection events here.
        """
        if self._platform_scan_event is not None:
            # This won't hurt anything if we are canceling ourselves.
            self._platform_scan_event.cancel()

        # Identities of all platform agents that are connecting to us should
        # have an identity of platform.md5hash.
        connected_platforms = set([x for x in self.vip.peerlist().get(timeout=5)
                                   if x.startswith('vcp-')])

        disconnected = self._platforms.get_platform_keys() - connected_platforms

        for vip_id in disconnected:
            self._handle_platform_disconnect(vip_id)

        not_known = connected_platforms - self._platforms.get_platform_keys()

        for vip_id in not_known:
            self._handle_platform_connection(vip_id)

        next_platform_scan = VolttronCentralAgent._get_next_time_seconds()

        # reschedule the next scan.
        self._platform_scan_event = self.core.schedule(
            next_platform_scan, self._scan_for_platforms)

    def configure_main(self, config_name, action, contents):
        """
        The main configuration for volttron central.  This is where validation
        will occur.

        Note this method is called:

            1. When the agent first starts (with the params from packaged agent
               file)
            2. When 'store' is called through the volttron-ctl config command
               line with 'config' as the name.

        Required Configuration:

        The volttron central requires a user mapping.

        :param config_name:
        :param action:
        :param contents:
        """

        _log.debug('Main config updated')
        _log.debug('ACTION IS {}'.format(action))
        _log.debug('CONTENT IS {}'.format(contents))
        if action == 'DELETE':
            # Remove the registry and keep the service running.
            self.runtime_config = None
            # Now stop the exposition of service.
        else:
            self.runtime_config = self.default_config.copy()
            self.runtime_config.update(contents)

            problems = self._validate_config_params(self.runtime_config)

            if len(problems) > 0:
                _log.error(
                    "The following configuration problems were detected!")
                for p in problems:
                    _log.error(p)
                sys.exit(INVALID_CONFIGURATION_CODE)
            else:
                _log.info('volttron central webroot is: {}'.format(
                    self.runtime_config.get('webroot')
                ))

                users = self.runtime_config.get('users')
                self.web_sessions = SessionHandler(Authenticate(users))

            _log.debug('Querying router for addresses and serverkey.')
            q = Query(self.core)

            external_addresses = q.query('addresses').get(timeout=5)
            self.runtime_config['local_external_address'] = external_addresses[0]

        self.vip.web.register_websocket(r'/vc/ws',
                                        self.open_authenticate_ws_endpoint,
                                        self._ws_closed,
                                        self._ws_received)
        self.vip.web.register_endpoint(r'/jsonrpc', self.jsonrpc)
        self.vip.web.register_path(r'^/.*',
                                   self.runtime_config.get('webroot'))

        # Start scanning for new platforms connections as well as for
        # disconnects that happen.
        self._scan_for_platforms()

    def configure_platforms(self, config_name, action, contents):
        _log.debug('Platform configuration updated.')
        _log.debug('ACTION IS {}'.format(action))
        _log.debug('CONTENT IS {}'.format(contents))

    def open_authenticate_ws_endpoint(self, fromip, endpoint):
        """
        Callback method from when websockets are opened.  The endpoine must
        be '/' delimited with the second to last section being the session
        of a logged in user to volttron central itself.

        :param fromip:
        :param endpoint:
            A string representing the endpoint of the websocket.
        :return:
        """
        _log.debug("OPENED ip: {} endpoint: {}".format(fromip, endpoint))
        try:
            session = endpoint.split('/')[-2]
        except IndexError:
            _log.error("Malformed endpoint. Must be delimited by '/'")
            _log.error(
                'Endpoint must have valid session in second to last position')
            return False

        if not self.web_sessions.check_session(session, fromip):
            _log.error("Authentication error for session!")
            return False

        _log.debug('Websocket allowed.')
        self._websocket_endpoints.add(endpoint)

        return True

    def _ws_closed(self, endpoint):
        _log.debug("CLOSED endpoint: {}".format(endpoint))
        try:
            self._websocket_endpoints.remove(endpoint)
        except KeyError:
            pass # This should never happen but protect against it anyways.

    def _ws_received(self, endpoint, message):
        _log.debug("RECEIVED endpoint: {} message: {}".format(endpoint,
                                                              message))

    @RPC.export
    def is_registered(self, address_hash=None, address=None):
        if address_hash is None and address is None:
            return False

        if address_hash is None:
            address_hash = PlatformHandler.address_hasher(address)

        return self._platforms.is_registered(address_hash)

    @RPC.export
    def get_publickey(self):
        """
        RPC method allowing the caller to retrieve the publickey of this agent.

        This method is available for allowing :class:`VolttronCentralPlatform`
        agents to allow this agent to be able to connect to its instance.

        :return: The publickey of this volttron central agent.
        :rtype: str
        """
        return self.core.publickey

    @RPC.export
    def unregister_platform(self, platform_uuid):
        _log.debug('unregister_platform')

        platform = self._registered_platforms.get(platform_uuid)
        if platform:
            connected = self._platform_connections.get(platform_uuid)
            if connected is not None:
                connected.call('unmanage')
                connected.kill()
            address = None
            for v in self._address_to_uuid.values():
                if v == platform_uuid:
                    address = v
                    break
            if address:
                del self._address_to_uuid[address]
            del self._platform_connections[platform_uuid]
            del self._registered_platforms[platform_uuid]
            self._registered_platforms.sync()
            context = 'Unregistered platform {}'.format(platform_uuid)
            return {'status': 'SUCCESS', 'context': context}
        else:
            msg = 'Unable to unregistered platform {}'.format(platform_uuid)
            return {'error': {'code': UNABLE_TO_UNREGISTER_INSTANCE,
                              'message': msg}}

    def _to_jsonrpc_obj(self, jsonrpcstr):
        """ Convert data string into a JsonRpcData named tuple.

        :param object data: Either a string or a dictionary representing a json document.
        """
        return jsonrpc.JsonRpcData.parse(jsonrpcstr)

    def jsonrpc(self, env, data):
        """ The main entry point for ^jsonrpc data

        This method will only accept rpcdata.  The first time this method
        is called, per session, it must be using get_authorization.  That
        will return a session token that must be included in every
        subsequent request.  The session is tied to the ip address
        of the caller.

        :param object env: Environment dictionary for the request.
        :param object data: The JSON-RPC 2.0 method to call.
        :return object: An JSON-RPC 2.0 response.
        """
        if env['REQUEST_METHOD'].upper() != 'POST':
            return jsonrpc.json_error('NA', INVALID_REQUEST,
                                      'Invalid request method, only POST allowed'
                                      )

        try:
            rpcdata = self._to_jsonrpc_obj(data)
            _log.info('rpc method: {}'.format(rpcdata.method))
            if rpcdata.method == 'get_authorization':
                args = {'username': rpcdata.params['username'],
                        'password': rpcdata.params['password'],
                        'ip': env['REMOTE_ADDR']}
                sess = self.web_sessions.authenticate(**args)
                if not sess:
                    _log.info('Invalid username/password for {}'.format(
                        rpcdata.params['username']))
                    return jsonrpc.json_error(
                        rpcdata.id, UNAUTHORIZED,
                        "Invalid username/password specified.")
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))
                self.vip.web.register_websocket(
                    "/vc/ws/{}/management".format(sess),
                    self.open_authenticate_ws_endpoint,
                    self._ws_closed,
                    self._received_data)
                _log.info('Session created for {}'.format(
                    rpcdata.params['username']))

                gevent.sleep(1)
                return jsonrpc.json_result(rpcdata.id, sess)

            token = rpcdata.authorization
            ip = env['REMOTE_ADDR']
            _log.debug('REMOTE_ADDR: {}'.format(ip))
            session_user = self.web_sessions.check_session(token, ip)
            _log.debug('SESSION_USER IS: {}'.format(session_user))
            if not session_user:
                _log.debug("Session Check Failed for Token: {}".format(token))
                return jsonrpc.json_error(rpcdata.id, UNAUTHORIZED,
                                          "Invalid authentication token")
            _log.debug('RPC METHOD IS: {}'.format(rpcdata.method))

            # Route any other method that isn't
            result_or_error = self._route_request(session_user,
                                                  rpcdata.id, rpcdata.method,
                                                  rpcdata.params)

        except AssertionError:
            return jsonrpc.json_error(
                'NA', INVALID_REQUEST, 'Invalid rpc data {}'.format(data))
        except Unreachable:
            return jsonrpc.json_error(
                rpcdata.id, UNAVAILABLE_PLATFORM,
                "Couldn't reach platform with method {} params: {}".format(
                    rpcdata.method,
                    rpcdata.params))
        except Exception as e:

            return jsonrpc.json_error(
                'NA', UNHANDLED_EXCEPTION, e
            )

        return self._get_jsonrpc_response(rpcdata.id, result_or_error)

    def _get_jsonrpc_response(self, id, result_or_error):
        """ Wrap the response in either a json-rpc error or result.

        :param id:
        :param result_or_error:
        :return:
        """
        if isinstance(result_or_error, dict):
            if 'jsonrpc' in result_or_error:
                return result_or_error

        if result_or_error is not None and isinstance(result_or_error, dict):
            if 'error' in result_or_error:
                error = result_or_error['error']
                _log.debug("RPC RESPONSE ERROR: {}".format(error))
                return jsonrpc.json_error(id, error['code'], error['message'])
        return jsonrpc.json_result(id, result_or_error)

    def _get_agents(self, instance_uuid, groups):
        """ Retrieve the list of agents on a specific platform.

        :param instance_uuid:
        :param groups:
        :return:
        """
        _log.debug('_get_agents')
        connected_to_pa = self._platform_connections[instance_uuid]

        agents = connected_to_pa.agent.vip.rpc.call(
            'platform.agent', 'list_agents').get(timeout=30)

        for a in agents:
            if 'admin' in groups:
                if "platformagent" in a['name'] or \
                                "volttroncentral" in a['name']:
                    a['vc_can_start'] = False
                    a['vc_can_stop'] = False
                    a['vc_can_restart'] = True
                else:
                    a['vc_can_start'] = True
                    a['vc_can_stop'] = True
                    a['vc_can_restart'] = True
            else:
                # Handle the permissions that are not admin.
                a['vc_can_start'] = False
                a['vc_can_stop'] = False
                a['vc_can_restart'] = False

        _log.debug('Agents returned: {}'.format(agents))
        return agents

    def _setupexternal(self):
        _log.debug(self.vip.ping('', "PING ROUTER?").get(timeout=3))

    def _configure_agent(self, endpoint, message):
        _log.debug('Configure agent: {} message: {}'.format(endpoint, message))

    def _received_data(self, endpoint, message):
        print('Received from endpoint {} message: {}'.format(endpoint, message))
        self.vip.web.send(endpoint, message)

    def set_setting(self, session_user, params):
        """
        Sets or removes a setting from the config store.  If the value is None
        then the item will be removed from the store.  If there is an error in
        saving the value then a jsonrpc.json_error object is returned.

        :param session_user: Unused
        :param params: Dictionary that must contain 'key' and 'value' keys.
        :return: A 'SUCCESS' string or a jsonrpc.json_error object.
        """
        if 'key' not in params or not params['key']:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid parameter key not set')
        if 'value' not in params:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid parameter key not set')

        config_key = "settings/{}".format(params['key'])
        value = params['value']

        if value is None:
            try:
                self.vip.config.delete(config_key)
            except KeyError:
                pass
        else:
            # We handle empt string here because the config store doesn't allow
            # empty strings to be set as a config store.  I wasn't able to
            # trap the ValueError that is raised on the server side.
            if value == "":
                return jsonrpc.json_error(params['message_id'],
                                          INVALID_PARAMS,
                                          'Invalid value set (empty string?)')
            self.vip.config.set(config_key, value)

        return 'SUCCESS'

    def get_setting(self, session_user, params):
        """
        Retrieve a value from the passed setting key.  The params object must
        contain a "key" to return from the settings store.

        :param session_user: Unused
        :param params: Dictionary that must contain a 'key' key.
        :return: The value or a jsonrpc error object.
        """
        config_key = "settings/{}".format(params['key'])
        try:
            value = self.vip.config.get(config_key)
        except KeyError:
            return jsonrpc.json_error(params['message_id'],
                                      INVALID_PARAMS,
                                      'Invalid key specified')
        else:
            return value

    def get_setting_keys(self, session_user, params):
        """
        Returns a list of all of the settings keys so the caller can know
        what settings to request.

        :param session_user: Unused
        :param params: Unused
        :return: A list of settings available to the caller.
        """

        prefix = "settings/"
        keys = [x[len(prefix):] for x in self.vip.config.list()
                if x.startswith(prefix)]
        return keys or []

    def _handle_bacnet_props(self, session_user, params):
        platform_uuid = params.pop('platform_uuid')
        id = params.pop('message_id')
        _log.debug('Handling bacnet_props platform: {}'.format(platform_uuid))

        configure_topic = "{}/configure".format(session_user['token'])
        ws_socket_topic = "/vc/ws/{}".format(configure_topic)

        if configure_topic not in self._websocket_endpoints:
            self.vip.web.register_websocket(ws_socket_topic,
                                            self.open_authenticate_ws_endpoint,
                                            self._ws_closed, self._ws_received)

        def start_sending_props():
            response_topic = "configure/{}".format(session_user['token'])
            # Two ways we could have handled this is to pop the identity off
            # of the params and then passed both the identity and the response
            # topic.  Or what I chose to do and to put the argument in a
            # copy of the params.
            cp = params.copy()
            cp['publish_topic'] = response_topic
            cp['device_id'] = int(cp['device_id'])
            platform = self._platforms.get_platform(platform_uuid)
            _log.debug('PARAMS: {}'.format(cp))
            platform.call("publish_bacnet_props", **cp)

        gevent.spawn_later(2, start_sending_props)

    def _handle_bacnet_scan(self, session_user, params):
        platform_uuid = params.pop('platform_uuid')
        id = params.pop('message_id')
        _log.debug('Handling bacnet_scan platform: {}'.format(platform_uuid))

        if not self._platforms.is_registered(platform_uuid):
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))

        scan_length = params.pop('scan_length', 5)

        try:
            scan_length = float(scan_length)
            params['scan_length'] = scan_length
            platform = self._platforms.get_platform(platform_uuid)
            iam_topic = "{}/iam".format(session_user['token'])
            ws_socket_topic = "/vc/ws/{}".format(iam_topic)
            self.vip.web.register_websocket(ws_socket_topic,
                                            self.open_authenticate_ws_endpoint,
                                            self._ws_closed, self._ws_received)

            def start_scan():
                # We want the datatype (iam) to be second in the response so
                # we need to reposition the iam and the session id to the topic
                # that is passed to the rpc function on vcp
                iam_session_topic = "iam/{}".format(session_user['token'])
                platform.call("start_bacnet_scan", iam_session_topic, **params)

                def close_socket():
                    _log.debug('Closing bacnet scan for {}'.format(
                        platform_uuid))
                    gevent.spawn_later(2,
                                       self.vip.web.unregister_websocket,
                                       iam_session_topic)

                gevent.spawn_later(scan_length, close_socket)

            # By starting the scan a second later we allow the websocket
            # client to subscribe to the newly available endpoint.
            gevent.spawn_later(2, start_scan)
        except ValueError:
            return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                      "Couldn't connect to platform {}".format(
                                          platform_uuid
                                      ))
        except KeyError:
            return jsonrpc.json_error(id, UNAUTHORIZED,
                                      "Invalid user session token")

    def _enable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error enable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to enable setup mode")
        auth_file = AuthFile()
        entries = auth_file.find_by_credentials(".*")
        if len(entries) > 0:
            return "SUCCESS"

        entry = AuthEntry(credentials="/.*/",
                          comments="Un-Authenticated connections allowed here",
                          user_id="unknown")
        auth_file.add(entry)
        return "SUCCESS"

    def _disable_setup_mode(self, session_user, params):
        id = params.pop('message_id')
        if 'admin' not in session_user['groups']:
            _log.debug('Returning json_error disable_setup_mode')
            return jsonrpc.json_error(
                id, UNAUTHORIZED,
                "Admin access is required to disable setup mode")
        auth_file = AuthFile()
        auth_file.remove_by_credentials("/.*/")
        return "SUCCESS"

    def _handle_management_endpoint(self, session_user, params):
        ws_topic = "/vc/ws/{}/management".format(session_user.get('token'))
        self.vip.web.register_websocket(ws_topic,
                                        self.open_authenticate_ws_endpoint,
                                        self._ws_closed, self._ws_received)
        return ws_topic

    def send_management_message(self, type, data={}):
        """
        Send a message to any socket that has connected to the management
        socket.

        The payload sent to the client is like the following::

            {
                "type": "UPDATE_DEVICE_STATUS",
                "data": "this is data that was passed"
            }

        :param type:
            A string defining a unique type for sending to the websockets.
        :param data:
            An object that str can be called on.

        :type type: str
        :type data: serializable
        """
        management_sockets = [s for s in self._websocket_endpoints
                              if s.endswith("management")]
        # Nothing to send if we don't have any management sockets open.
        if len(management_sockets) <= 0:
            return

        if data is None:
            data = {}

        payload = dict(
            type=type,
            data=str(data)
        )

        payload = jsonapi.dumps(payload)
        for s in management_sockets:
            self.vip.web.send(s, payload)

    def _route_request(self, session_user, id, method, params):
        """ Handle the methods volttron central can or pass off to platforms.

        :param session_user:
            The authenticated user's session info.
        :param id:
            JSON-RPC id field.
        :param method:
        :param params:
        :return:
        """
        _log.debug(
            'inside _route_request {}, {}, {}'.format(id, method, params))

        def err(message, code=METHOD_NOT_FOUND):
            return {'error': {'code': code, 'message': message}}

        self.send_management_message(method)

        method_split = method.split('.')
        # The last part of the jsonrpc method is the actual method to be called.
        method_check = method_split[-1]

        # These functions will be sent to a platform.agent on either this
        # instance or another.  All of these functions have the same interface
        # and can be collected into a dictionary rather than an if tree.
        platform_methods = dict(
            # bacnet related
            start_bacnet_scan=self._handle_bacnet_scan,
            publish_bacnet_props=self._handle_bacnet_props,
            # config store related
            store_agent_config="store_agent_config",
            get_agent_config="get_agent_config",
            list_agent_configs="get_agent_config_list",
            # management related

            list_agents="get_agent_list",
            get_devices="get_devices",
            status_agents="status_agents"
        )

        # These methods are specifically to be handled by the platform not any
        # agents on the platform that is why we have the length requirement.
        #
        # The jsonrpc method looks like the following
        #
        #   platform.uuid.<dynamic entry>.method_on_vcp
        if method_check in platform_methods:

            platform_uuid = None
            if isinstance(params, dict):
                platform_uuid = params.pop('platform_uuid', None)

            if platform_uuid is None:
                if method_split[0] == 'platforms' and method_split[1] == 'uuid':
                    platform_uuid = method_split[2]

            if not platform_uuid:
                return err("Invalid platform_uuid specified as parameter"
                           .format(platform_uuid),
                           INVALID_PARAMS)

            if not self._platforms.is_registered(platform_uuid):
                return err("Unknown or unavailable platform {} specified as "
                           "parameter".format(platform_uuid),
                           UNAVAILABLE_PLATFORM)

            try:
                _log.debug('Calling {} on platform {}'.format(
                    method_check, platform_uuid
                ))
                class_method = platform_methods[method_check]
                platform = self._platforms.get_platform(platform_uuid)
                # Determine whether the method to call is on the current class
                # or on the platform object.
                if isinstance(class_method, basestring):
                    method_ref = getattr(platform, class_method)
                else:
                    method_ref = class_method
                    # Put the platform_uuid in the params so it can be used
                    # inside the method
                    params['platform_uuid'] = platform_uuid

            except AttributeError or KeyError:
                return jsonrpc.json_error(id, INTERNAL_ERROR,
                                          "Attempted calling function "
                                          "{} was unavailable".format(
                                              class_method
                                          ))

            except ValueError:
                return jsonrpc.json_error(id, UNAVAILABLE_PLATFORM,
                                          "Couldn't connect to platform "
                                          "{}".format(platform_uuid))
            else:
                # pass the id through the message_id parameter.
                if not params:
                    params = dict(message_id=id)
                else:
                    params['message_id'] = id

                # Methods will all have the signature
                #   method(session, params)
                #
                return method_ref(session_user, params)

        vc_methods = dict(
            register_management_endpoint=self._handle_management_endpoint,
            list_platforms=self._platforms.get_platform_list,
            list_performance=self._platforms.get_performance_list,

            # Settings
            set_setting=self.set_setting,
            get_setting=self.get_setting,
            get_setting_keys=self.get_setting_keys,

            # Setup mode
            enable_setup_mode=self._enable_setup_mode,
            disable_setup_mode=self._disable_setup_mode
        )

        if method in vc_methods:
            if not params:
                params = dict(message_id=id)
            else:
                params['message_id'] = id
            response = vc_methods[method](session_user, params)
            _log.debug("Response is {}".format(response))
            return response  # vc_methods[method](session_user, params)

        if method == 'register_instance':
            if isinstance(params, list):
                return self._register_instance(*params)
            else:
                return self._register_instance(**params)
        elif method == 'unregister_platform':
            return self.unregister_platform(params['instance_uuid'])

        elif 'historian' in method:
            has_platform_historian = PLATFORM_HISTORIAN in \
                                     self.vip.peerlist().get(timeout=30)
            if not has_platform_historian:
                return err(
                    'The VOLTTRON Central platform historian is unavailable.',
                    UNAVAILABLE_AGENT)
            _log.debug('Trapping platform.historian to vc.')
            _log.debug('has_platform_historian: {}'.format(
                has_platform_historian))
            if 'historian.query' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'query', **params).get(timeout=30)
            elif 'historian.get_topic_list' in method:
                return self.vip.rpc.call(
                    PLATFORM_HISTORIAN, 'get_topic_list').get(timeout=30)

        # This isn't known as a proper method on vc or a platform.
        if len(method_split) < 3:
            return err('Unknown method {}'.format(method))
        if method_split[0] != 'platforms' or method_split[1] != 'uuid':
            return err('Invalid format for instance must start with '
                       'platforms.uuid')
        instance_uuid = method_split[2]
        _log.debug('Instance uuid is: {}'.format(instance_uuid))
        if not self._platforms.is_registered(instance_uuid):
            return err('Unknown platform {}'.format(instance_uuid))
        platform_method = '.'.join(method_split[3:])
        _log.debug("Platform method is: {}".format(platform_method))
        platform = self._platforms.get_platform(instance_uuid)
        if not platform:
            return jsonrpc.json_error(id,
                                      UNAVAILABLE_PLATFORM,
                                      "cannot connect to platform."
                                      )

        if platform_method.startswith('install'):
            if 'admin' not in session_user['groups']:
                return jsonrpc.json_error(
                    id, UNAUTHORIZED,
                    "Admin access is required to install agents")

        return platform.route_to_agent_method(id, platform_method, params)

    def _validate_config_params(self, config):
        """
        Validate the configuration parameters of the default/updated parameters.

        This method will return a list of "problems" with the configuration.
        If there are no problems then an empty list is returned.

        :param config: Configuration parameters for the volttron central agent.
        :type config: dict
        :return: The problems if any, [] if no problems
        :rtype: list
        """
        problems = []
        webroot = config.get('webroot')
        if not webroot:
            problems.append('Invalid webroot in configuration.')
        elif not os.path.exists(webroot):
            problems.append(
                'Webroot {} does not exist on machine'.format(webroot))

        users = config.get('users')
        if not users:
            problems.append('A users node must be specified!')
        else:
            has_admin = False

            try:
                for user, item in users.items():
                    if 'password' not in item.keys():
                        problems.append('user {} must have a password!'.format(
                            user))
                    elif not item['password']:
                        problems.append('password for {} is blank!'.format(
                            user
                        ))

                    if 'groups' not in item.keys():
                        problems.append('missing groups key for user {}'.format(
                            user
                        ))
                    elif not isinstance(item['groups'], list):
                        problems.append('groups must be a list of strings.')
                    elif not item['groups']:
                        problems.append(
                            'user {} must belong to at least one group.'.format(
                                user))

                    # See if there is an adminstator present.
                    if not has_admin and isinstance(item['groups'], list):
                        has_admin = 'admin' in item['groups']
            except AttributeError:
                problems.append('invalid user node.')

            if not has_admin:
                problems.append("One user must be in the admin group.")

        return problems
예제 #18
0
class SleepyMeshBase(DatabaseDict):
    def __init__(self, system_settings, websocket, snmp_websocket, **kwargs):
        super(SleepyMeshBase, self).__init__(**kwargs)

        if 'last_syncs' not in self._defaults:
            self._defaults.update({'last_syncs': list()})

        # Internal Members #
        self._mesh_awake = True
        self._sync_type = 'timeout'

        self._save_in_progress = False

        self._sync_average = None
        self._delay_average = None

        # Instances #
        # TODO: Eliminate as many dependencies as possible
        self.system_settings = system_settings
        self.websocket = websocket
        self.snmp_websocket = snmp_websocket

        self.modbus_server = ModbusServer()
        self.snmp_server = SNMPTrapServer(self)
        self.update_interfaces = UpdateInterfaces(self)
        self.update_in_progress = self.update_interfaces.update_in_progress

        self.bridge = Bridge(self.system_settings)
        self.uploader = Uploader(self)

        self.nodes = Nodes(self.system_settings)
        self.platforms = Platforms(self.nodes)
        self.networks = Networks(self)

        self.error = BaseError(self.system_settings)

        if self.system_settings.modbus_enable:
            system_settings_dict = self.system_settings.attr_dict()
            # LOGGER.debug('Modbus Attribute Dictionary: ' + str(system_settings_dict))
            self.modbus_server.start(system_settings_dict)

        if self.system_settings.snmp_enable:
            self.snmp_server.start()

            # Overload Node Error Methods (SNMP Error Methods)#
            NodeError.send_snmp = self.snmp_server.send_snmp
            NodeError.clear_snmp = self.snmp_server.clear_snmp

    ## Public/Private Methods ##
    # Sleep/Wake Period Methods #
    def sleep_period(self):
        """ Fetches sleep period """
        return self.networks[0]['sleep']

    def _wake_period(self):
        """ Fetches wake period """
        return self.networks[0]['wake']

    def wake_period(self):
        """ Fetches wake period (or dynamic wake period if enabled) """
        static_wake_period = self._wake_period()
        output = static_wake_period

        if DYNAMIC_WAKE_PERIOD:
            if self._sync_average is not None:
                dynamic_wake_period = self._sync_average + SYNC_DEVIATION

                if dynamic_wake_period < static_wake_period:
                    output = dynamic_wake_period

        return output

    def save(self, db_content=None):
        """ Overloading default save method """
        self._save_in_progress = True

        # Save statistics data
        super(SleepyMeshBase, self).save(db_content)

        self.platforms.save()

        if self.system_settings.modbus_enable:
            self.modbus_server.save()

        if self.system_settings.snmp_enable:
            self.snmp_server.save()

        self._save_in_progress = False

    ## Private Methods ##
    # Last Sync Related Methods #
    def _update_last_sync(self):
        """ Updates last sync """
        last_sync = self.system_settings.time()
        self['last_syncs'].append(last_sync)
        if len(self['last_syncs']) > LAST_SYNCS_NUMBER:
            del self['last_syncs'][0]

    def _ct_ls(self):
        """ Returns current system time - last sync value """
        output = 0
        if len(self['last_syncs']):
            output = self.system_settings.time() - self['last_syncs'][-1]

        return output

    def _ct_ls_str(self, ct_ls=None):
        """ Returns current system time - last sync string """
        if ct_ls is None:
            ct_ls = self._ct_ls()

        output = CT_LS + "{0:.3f}".format(ct_ls)

        return output
예제 #19
0
class ParentClone:

    global platforms
    platforms = Platforms()

    def __init__(self, datpath=None):

        self.datpath = datpath

        if datpath:

            # parse the xml dat file
            #
            self.gamestree = ET.parse(self.datpath).getroot()

            # identify platform
            #
            if self.gamestree.find('.//platform') is None:
                logging.error('No platform element found!')
                logging.error('Add a <platform/> xml element in the dat file.')
                logging.error(
                    'e.g.	<header>..<platform>Genesis</platform/>..</header>')
                return
            else:
                self.platform = self.gamestree.find('.//platform').text
                logging.info('Platform:' + self.platform)

            if platforms.getId(self.platform) is None:
                logging.error('Platform ' + self.platform + ' not supported.')
                return

            # strip whitespace and remove text within parenetheses
            # from game names.
            # load adictionary with game name as key and a list
            # of the regions it released
            #
            # e.g. the folloging xml entry
            #
            # <game name="NBA Live 95 (USA, Europe)">
            #     <description>NBA Live 95 (USA, Europe)</description>
            #     <release name="NBA Live 95 (USA, Europe)" region="EUR"/>
            #     <release name="NBA Live 95 (USA, Europe)" region="USA"/>
            #     <rom name="NBA Live 95 (USA, Europe).md" size="2097152" crc="66018ABC" />
            # </game>
            #
            # is loaded in the games{} dictionary as:
            # {'NBA Live 95': ['EUR', 'USA']}
            #
            self.games = defaultdict(list)

            for g in self.gamestree.findall('game'):
                if not g.attrib.get('cloneof'):
                    name = self.normalizeName(g.attrib.get('name'))
                    for r in g.findall('release'):
                        self.games[name].append(r.attrib.get('region'))

            process = CrawlerProcess(get_project_settings())
            process.crawl(
                'mobygames',
                url=
                'http://mobygames.com/search/quick?q=air diver&p=16&search=Go&sFilter=1&sG=on'
            )
            process.crawl(
                'mobygames',
                url=
                'http://mobygames.com/search/quick?q=sonic r&p=16&search=Go&sFilter=1&sG=on'
            )
            #			process.crawl(MobygamesSpider(url='http://mobygames.com/search/quick?q=air diver&p=16&search=Go&sFilter=1&sG=on'))
            process.start()
            # init env. configuration and runner
            #
            #configure_logging()
            #get_project_settings()
            #runner = CrawlerRunner()

            #runner.crawl(MobygamesSpider(title='air diver',platform='genesis', region='EUR'))

            #d = runner.join()
            #d.addBoth(lambda _: reactor.stop())

            # the script will block here until all
            # crawling jobs are finished
            #
            #reactor.run()

        else:
            logging.warning('No dat file.')

    # strip all text in parentheses
    #
    def normalizeName(self, value):
        value = re.sub(r'\([^)]*\)', '', value)
        return value.strip()
예제 #20
0
class Importer:

	global platforms
	platforms = Platforms()
        
	def __init__(self, datpath=None, boxpath=None):

		logging.basicConfig(
			filename='import.log',
			filemode = 'a',
			format='%(levelname)s: %(message)s',
			level=logging.DEBUG
		)

		settings = get_project_settings()                
		imgpath = settings['IMAGES_STORE']
		
		# paths of source and target file
		# source file is the exported one from the exporter.py
		# target file is LaunchBox.xml metadata file
		self.datpath = datpath
		self.boxpath = boxpath	
		
		# counters for found and not found games
		self.inc_found = 0		
		self.inc_notfound = 0
		
		# store titles of not found games
		self.notfound = []
		
		if datpath and boxpath:
							
			self.dattree =  ET.parse(self.datpath)
			self.dat = self.dattree.getroot()
										
			if self.dat.find('.//platform[1]') is None:
				logging.error('No platform element found!')
				logging.error('Add a <platform/> xml element in the dat file.')
				logging.error('e.g. <platform>Genesis</platform/>')
				return
			else:
				self.platform =  self.dat.find('.//platform/[1]').text
				self.platform = platforms.getLaunchBoxPlatform(self.platform)
				self.imagesdir = self.boxpath + 'Images/' + self.platform + '/'
				self.frontdir = self.imagesdir + 'Box - Front/'
				self.backdir = self.imagesdir + 'Box - Back/'
				self.screenshotdir = self.imagesdir + 'Screenshot - Gameplay/Snap/'
				self.mediadir = self.imagesdir + 'Media/'
				
				if not os.path.exists(self.frontdir):
					os.makedirs(self.frontdir)				
				if not os.path.exists(self.backdir):
					os.makedirs(self.backdir)				
				if not os.path.exists(self.frontdir):
					os.makedirs(self.screenshotdir)				
				if not os.path.exists(self.screenshotdir):
					os.makedirs(self.screenshotdir)				
				if not os.path.exists(self.mediadir):
					os.makedirs(self.mediadir)				

				logging.info('Platform:' + self.platform)
				logging.info('Images destination directory:' + self.imagesdir)
	                                                                      
			# backup LaunchBox Data file
			#		
			if self.boxpath:
				boxfile = self.boxpath + 'Data/Platforms/' + self.platform + '.xml'
				shutil.copyfile(boxfile, boxfile + '.bak')	
				logging.info('Data directory:' + self.boxpath)
				logging.info('Data file:' + boxfile)
				logging.info('Data backup file:' + boxfile + '.bak')
				
			# Parse LaunchBox games for Platform
			#
			self.boxtree =  ET.parse(boxfile)
			self.box = self.boxtree.getroot()
		                                                                                                                        
			# load game elements into dicts
			# with key == title, value game elemtn
			_datgames = self.dat.findall('game')
			_boxgames = self.box.findall('Game')
			self.datgames = defaultdict(list)
			self.boxgames = defaultdict(list)
			
			# load all games in the dat file in dictionary
			# by title
			#
			for g in _datgames:
				title = g.find('./title').text
				title = self.remove_prefix(title,"The ")
				title = self.remove_suffix(title,", The")
				title = self.remove_suffix(title,"The")
				title = self.normalizeName(title)
				title = filter(str.isalnum, title.encode('utf-8')).lower().strip()
				self.datgames[title] = g
			totalgames = len(self.datgames)	
			
			# load all launchbox games for the given platform
			# and that exist in the dat file
			#
			for g in _boxgames:
				if g.find('Platform').text == self.platform:
					title = g.find('./Title').text
					title = self.remove_prefix(title,"The ")
					title = self.remove_suffix(title,", The")
					title = self.remove_suffix(title,"The")
					title = self.normalizeName(title)
					title = filter(str.isalnum, title.encode('utf-8')).lower().strip()
					self.boxgames[title] = g
						
			# delete keys from dat games that do not
			# have a match in launchbox
			#
			delkeys = []
			for key in self.datgames:
				if key not in self.boxgames.keys():
					delkeys.append(key)
					self.notfound.append(self.datgames[key].find('./title').text)
					self.inc_notfound += 1
				else:
					self.inc_found += 1
			for key in delkeys:
				del self.datgames[key]
				
				 
			logging.info('Importing ' + str(self.inc_found) +'/' + str(totalgames) + ' games.')
			logging.info('Not found games:' + str(self.inc_notfound))
			logging.info('List of not found games:' + str(self.notfound))

			chars_to_remove = ['\\', '/', ':', '?', '\'', '"']
			rx = '[' + re.escape(''.join(chars_to_remove)) + ']'
			
			# Start the import
			#
			for key in self.datgames:
				logging.debug('Importing ' + self.datgames[key].find('./title').text )
				self.copyTag(key,'developer','Developer')
				self.copyTag(key,'publisher','Publisher')
				self.copyTag(key,'date','ReleaseDate')
				self.copyTag(key,'description','Notes')
				self.copyTag(key,'region','Region')
				self.copyTag(key,'source','Source')
				self.copyTag(key,'genre','Genre')
				self.copyTag(key,'group','Series')
				self.copyTag(key,'rating','Rating')
				
				gameId = self.boxgames[key].find('./ID').text
				
				# presentation custom field
				presentation = self.datgames[key].findall('./presentation//value')
				if len(presentation) > 0:
					for p in presentation:
						self.addCustomField(gameId,'Presentation',p.text)
						
				# perspective custom field
				perspective = self.datgames[key].findall('./perspective//value')
				if len(perspective) > 0:
					for p in perspective:
						self.addCustomField(gameId,'Perspective',p.text)
						
				# setting custom field
				setting = self.datgames[key].findall('./setting//value')
				if len(setting) > 0:
					for s in setting:
						self.addCustomField(gameId,'Setting',s.text)
						
				# pacing custom field
				pacing = self.datgames[key].findall('./pacing//value')
				if len(pacing) > 0:
					for p in pacing:
						self.addCustomField(gameId,'Pacing',p.text)

				# visual custom field
				visual = self.datgames[key].findall('./visual//value')
				if len(visual) > 0:
					for v in visual:					
						self.addCustomField(gameId,'Visual',v.text)
						
				# vehicular custom field
				vehicular = self.datgames[key].findall('./vehicular//value')
				if len(vehicular) > 0:
					for v in vehicular:
						self.addCustomField(gameId,'Vehicular',v.text)
						
				# gameplay custom field
				gameplay = self.datgames[key].findall('./gameplay//value')
				if len(gameplay) > 0:
					for g in gameplay:
						self.addCustomField(gameId,'Gameplay',g.text)

				# narrative custom field
				narrative = self.datgames[key].findall('./narrative//value')
				if len(narrative) > 0:
					for n in narrative:
						self.addCustomField(gameId,'Narrative',n.text)
						
				# educational custom field
				educational = self.datgames[key].findall('./educational//value')
				if len(educational) > 0:
					for e in educational:
						self.addCustomField(gameId,'Educational',e.text)
												
				# sport custom field
				sport = self.datgames[key].findall('./sport//value')
				if len(sport) > 0:
					for s in sport:
						self.addCustomField(gameId,'Sport',s.text)

				# exclusive custom field
				exclusive = self.datgames[key].findall('./exclusive')
				if len(exclusive) > 0:
					self.addCustomField(gameId,'Exclusive','Yes')
					
				# mature custom field
				mature = self.datgames[key].findall('./mature')
				if len(mature) > 0:
					self.addCustomField(gameId,'Mature','Yes')
				
				# licensed custom field
				licensed = self.datgames[key].findall('./licensed')
				if len(licensed) > 0:
					self.addCustomField(gameId,'Licensed Title','Yes')

				# addon custom field
				addon = self.datgames[key].findall('./addon//value')
				if len(addon) > 0:
					for a in addon:
						self.addCustomField(gameId,'Add-on',a.text)
										
				# user score -> star rating
				userRating = self.datgames[key].findall('./userScore/value')
				if len(userRating) > 0:
					userRating =int(math.ceil(float(userRating[0].text)))
					self.boxgames[key].find('./StarRating').text = str(userRating)
					
				# IMAGES
				images = self.datgames[key].findall('./images//value')
				screenshots = []
				media = []
				title = self.boxgames[key].find('./Title').text
				title = re.sub(rx, '_', title)
				for img in images:					
					url = img.find('./url').text
					path = imgpath +'/' +  img.find('./path').text					
					filename, file_extension = os.path.splitext(path)					
					if 'front-cover' in url:
						dest =  self.frontdir + title + file_extension
						shutil.copy(path,dest)
					elif 'back-cover' in url:
						dest =  self.backdir + title + file_extension
						shutil.copy(path,dest)
					elif 'screenshot' in url:
						screenshots.append(path)
					else:
						media.append(path)
						
				self.copyImages(title,media, self.mediadir)
				
				self.copyImages(title,screenshots, self.screenshotdir)
							
					
			self.boxtree.write(boxfile + '.import',encoding='utf-8')
			
		else:
			logging.warning('No dat and/or box file.')		
        

	# copies the text value inside a tag
    #
	def copyTag(self,key,source,target):
		game = self.datgames[key]
		_s = self.datgames[key].find('./' + source)
		if _s is not None:
			parent = self.boxgames[key]
			elem = parent.find('./' + target)
			if elem is not None:
				elem.text = _s.text
			else:
				elem = ET.SubElement(parent,target)
				elem.text = _s.text


	def addCustomField(self,gid,name,value):
		customfield = ET.SubElement(self.box,'CustomField')
		gidElem = ET.SubElement(customfield,'GameID')		
		gidElem.text = gid
		nameElem = ET.SubElement(customfield,'Name')
		nameElem.text = name
		valueElem = ET.SubElement(customfield,'Value')
		valueElem.text = value
	
	def copyImages(self,title,images,targetdir):
		if len(images) > 0:
			for idx, val in enumerate(images):						
				filename, file_extension = os.path.splitext(val)							
				if idx < 9:
					dest =  targetdir + title + '-0' + str(idx+1) + file_extension
				else:
					dest =  targetdir + title + '-' + str(idx+1) + file_extension
				shutil.copy(val,dest)
		    
	# strip all text in parentheses
	#
	def normalizeName(self,value):
		value = self.remove_parentheses(value)
		value = self.remove_brackets(value)
		return value.strip()


	
	# remove parentheses and text inside them
	def remove_parentheses(self,x):
		if '(' in x and ')' in x:
			x = re.sub('\(.*?\)','',x)
		return x



	# remove brackets and text inside them
	def remove_brackets(self,x):
		if '[' in x and ']' in x:
			x = re.sub('\[.*?\]','',x)
		return x



	# remove prefix from text x
	def remove_prefix(self,x, prefix):
		if x.startswith(prefix):
			x = x[len(prefix):]
		return x



	# remove suffix from text x
	def remove_suffix(self,x, suffix):
		if x.endswith(suffix):
			x = x[:-len(suffix):]
		return x
예제 #21
0
class ExporterFromList:

    global platforms
    platforms = Platforms()

    def __init__(self, titlesfile=None, platform=None, region=None):

        # set default encoding to utf8 for parsing and logging
        # utf-8 characters in console and files
        #
        reload(sys)
        sys.setdefaultencoding('utf8')

        configure_logging(install_root_handler=False)
        logging.basicConfig(filename='export.log',
                            filemode='a',
                            format='%(levelname)s: %(message)s',
                            level=logging.INFO)

        # identify platform
        #
        self.platform = platform
        if self.platform is None:
            logging.error('No platform found! Pass it as an argument.')
            return
        else:
            platformId = platforms.getId(self.platform)
            if platformId is None:
                logging.error('Platform ' + self.platform + ' not supported.')
                return

        self.titlesfile = titlesfile
        self.region = region
        if self.region is None:
            self.region = "Worldwide"

        if titlesfile:

            titles = []
            urls = []

            with open(self.titlesfile) as f:
                titles = f.read().splitlines()

            for title in titles:
                logging.debug('Submitting title:' + title)
                urls.append('http://mobygames.com/search/quick' + '?q=' +
                            title + '&p=' + platformId + '&search=Go'
                            '&sFilter=1'
                            '&sG=on'
                            '&search_title=' + urllib.quote(title) +
                            '&search_platform=' + urllib.quote(self.platform) +
                            '&search_region=' + urllib.quote(self.region))

            process = CrawlerProcess(get_project_settings())
            process.crawl(MobygamesSpider, start_urls=urls)
            process.start()
        else:
            logging.warning('No file.')

    # strip all text in parentheses
    #
    def normalizeName(self, value):
        value = self.remove_parentheses(value)
        value = self.remove_brackets(value)
        return value.strip()

    # remove parentheses and text inside them
    def remove_parentheses(self, x):
        if '(' in x and ')' in x:
            x = re.sub('\(.*?\)', '', x)
        return x

    # remove brackets and text inside them
    def remove_brackets(self, x):
        if '[' in x and ']' in x:
            x = re.sub('\[.*?\]', '', x)
        return x