controllers.coffee 10.2 KB
Newer Older
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1
path = require 'path'
2
fs = require 'fs'
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
3
child_process = require 'child_process'
4
crypto = require 'crypto'
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
5 6

mkdirp = require 'mkdirp'
7
rmdir = require 'rmdir'
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
8
gui = require 'nw.gui'
9
Datastore = require 'nw_nedb'
神楽坂玲奈's avatar
神楽坂玲奈 committed
10

神楽坂玲奈's avatar
0.0.4  
神楽坂玲奈 committed
11 12
tunnel = require './js/tunnel'

13 14 15
db =
  apps: new Datastore({ filename: path.join(gui.App.dataPath, 'apps.db'), autoload: true })
  local: new Datastore({ filename: path.join(gui.App.dataPath, 'local.db'), autoload: true })
神楽坂玲奈's avatar
神楽坂玲奈 committed
16
  profile: new Datastore({ filename: path.join(gui.App.dataPath, 'profile.db'), autoload: true })
神楽坂玲奈's avatar
0.0.4  
神楽坂玲奈 committed
17
  user: new Datastore({ filename: path.join(gui.App.dataPath, 'user.db'), autoload: true })
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
18
angular.module('maotama.controllers', [])
神楽坂玲奈's avatar
神楽坂玲奈 committed
19
.controller 'AppsListController', ['$scope', '$routeParams', '$http', '$location', ($scope, $routeParams, $http, $location)->
20 21 22 23 24 25 26
    $scope.orderProp = 'id';
    $http.get('apps.json').success (data)->
      db.apps.remove {}, { multi: true }, (err, numRemoved)->
        throw err if err
        db.apps.insert data, (err, newDocs)->
          throw err if err
          $scope.apps = data
神楽坂玲奈's avatar
神楽坂玲奈 committed
27 28 29 30 31
          if !$routeParams.app_id
            $location.path("/apps/#{data[0].id}");
            $scope.$apply()
          else
            $scope.$digest()
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
32

神楽坂玲奈's avatar
神楽坂玲奈 committed
33 34 35 36 37 38 39 40 41 42 43 44
    $scope.active = (app_id)->
      "active" if $routeParams.app_id == app_id
    $scope.category_active = (category)->
      if $scope.apps
        app = null
        for a in $scope.apps
          if a.id == $routeParams.app_id
            app = a
        if app
          if app.category == category
            "active"
]
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
45
.controller 'AppsShowController', ['$scope', '$routeParams', ($scope, $routeParams)->
神楽坂玲奈's avatar
0.0.4  
神楽坂玲奈 committed
46
    $scope.tunnel_servers = require './tunnel_servers.json'
47
    db.apps.findOne {id: $routeParams.app_id}, (err, doc)->
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
48
      throw err if err
49 50 51 52 53 54 55 56
      $scope.app = doc
      $scope.runtime =
        running: false
        installing: {}
      $scope.default_installation_path = path.join process.cwd(), 'apps', $scope.app.id

      db.local.findOne {id: $routeParams.app_id}, (err, doc)->
        $scope.local = doc ? {}
神楽坂玲奈's avatar
神楽坂玲奈 committed
57 58 59 60 61 62 63 64 65 66 67
        db.profile.findOne {id: $routeParams.app_id}, (err, doc)->
          if doc #and doc.achievements.length == $scope.app.achievements.length
            $scope.profile = doc
            $scope.$digest();
          else
            $scope.profile =
              id: $routeParams.app_id
              achievements: ([] for achievement in $scope.app.achievements) if $scope.app.achievements
            db.profile.insert $scope.profile, (err, newDoc)->
              throw err if err
              $scope.$digest();
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
68 69

    $scope.add = (installation)->
70 71
      $scope.local.installation = path.dirname installation
      db.local.update {
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
72 73 74
        id: $scope.app.id
      }, {
        $set: {
75
          installation: $scope.local.installation
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
76
        }
77 78
      }, {
        upsert: true
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
79 80 81 82
      }, (err, numReplaced, newDoc)->
        throw err if err
        $scope.$digest();
    $scope.install = ()->
83
      $scope.runtime.installing[$scope.app.id] =
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
84 85 86 87
        process: 0
        label: '正在连接'
      mkdirp path.join(process.cwd(), 'cache'), (err)->
        throw err if err
88
        aria2c = child_process.spawn 'bin/aria2c', ["--check-integrity", "--checksum=md5=#{$scope.app.download.checksum}", "--dir=cache", "--enable-color=false", "-c", $scope.app.download.url]
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
89 90 91 92 93
        aria2c.stdout.setEncoding('utf8');
        aria2c.stderr.setEncoding('utf8');
        aria2c.stdout.on 'data', (data)->
          console.log data
          #[#06c774 35MiB/298MiB(11%) CN:1 DL:62MiB ETA:4s]
94
          #[#d1b179 752KiB/298MiB(0%) CN:1 DL:109KiB ETA:46m17s]
95
          #[#4dd4a5 592KiB/298MiB(0%) CN:1 DL:43KiB ETA:1h57m19s]
96
          if matches = data.match(/\[(?:#\w+ )?([\w\.]+)\/([\w\.]+)\((\d+)%\) CN:(\d+) DL:([\w\.]+) ETA:(\w+)\]/)
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
97
            [d, downloaded, total, progress, connections, speed, eta] = matches
98 99
            $scope.runtime.installing[$scope.app.id].progress = progress
            $scope.runtime.installing[$scope.app.id].label = "#{progress}% #{speed}/s"
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
100 101 102 103 104
            $scope.$digest();

        aria2c.stderr.on 'data', (data)->
          console.log 'err: ', data
        aria2c.on 'close', (code)->
105
          if code != 0
106 107
            window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, "下载失败, 错误: #{code}"
            delete $scope.runtime.installing[$scope.app.id]
108 109
            $scope.$digest();
          else
110 111
            $scope.runtime.installing[$scope.app.id].progress = 100
            $scope.runtime.installing[$scope.app.id].label = '正在安装'
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
112
            $scope.$digest();
113 114 115 116 117 118 119 120 121 122 123

            downloaded = "cache/#{path.basename($scope.app.download.url)}";

            # 二次校验,如果aria2c被强制退出了,返回码也是0
            checksum = crypto.createHash('md5');
            file = fs.ReadStream(downloaded);
            file.on 'data', (d)->
              checksum.update(d)

            file.on 'end', ()->
              if checksum.digest('hex') != $scope.app.download.checksum
124 125
                window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, "校验错误"
                delete $scope.runtime.installing[$scope.app.id]
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
                $scope.$digest();
              else
                p = path.join "apps/#{$scope.app.id}"
                mkdirp p, (err)->
                  throw err if err
                  console.log ["x", "-y", "-o#{p}", downloaded]
                  console.log p7zip = child_process.spawn 'bin/7za', ["x", "-y", "-o#{p}", "cache/#{path.basename($scope.app.download.url)}"]
                  p7zip.stdout.setEncoding('utf8');
                  p7zip.stderr.setEncoding('utf8');
                  p7zip.stdout.on 'data', (data)->
                    console.log data
                  p7zip.stderr.on 'data', (data)->
                    console.log 'err: ', data
                  p7zip.on 'close', (code)->
                    if code != 0
141 142
                      window.LOCAL_NW.desktopNotifications.notify $scope.app.icon,  $scope.app.name, "安装失败, 错误: #{code}"
                      delete $scope.runtime.installing[$scope.app.id]
143 144
                      $scope.$digest();
                    else
145 146
                      delete $scope.runtime.installing[$scope.app.id]
                      window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, '安装完成'
神楽坂玲奈's avatar
神楽坂玲奈 committed
147
                      $scope.add path.join(p, $scope.app.main)
148 149 150 151 152 153 154 155 156 157 158 159
    $scope.uninstall = ()->
      $scope.runtime.uninstalling = true
      db.local.remove {
        id: $scope.app.id
      }, (err, numRemoved)->
        throw err if err
        rmdir $scope.local.installation, ( err, dirs, files )->
          console.log dirs
          console.log files
          console.log 'all files are removed'
          $scope.local = {}
          $scope.$digest()
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
160 161

    $scope.run = ()->
162 163 164 165 166 167 168 169 170 171 172 173
      $scope.runtime.running = true
      game = child_process.spawn $scope.app.main, [],
        cwd: $scope.local.installation
      game.stdout.setEncoding('utf8');
      game.stdout.on 'data', (data)->
        console.log data
        if matches = data.match /<maotama>(.+)<\/maotama>/
          for command in $(matches[1])
            switch command.tagName
              when 'ACHIEVEMENT'
                achievement = $scope.app.achievements[$(command).attr('type')]
                achievement_item = achievement.items[$(command).attr('id')]
神楽坂玲奈's avatar
神楽坂玲奈 committed
174 175 176 177

                $scope.profile.achievements[$(command).attr('type')] ?= {}
                return if $scope.profile.achievements[$(command).attr('type')][$(command).attr('id')]

178
                window.LOCAL_NW.desktopNotifications.notify achievement_item.icon, "获得#{achievement.name}: #{achievement_item.name}", achievement_item.description
神楽坂玲奈's avatar
神楽坂玲奈 committed
179 180 181 182 183 184 185 186 187
                $scope.profile.achievements[$(command).attr('type')][$(command).attr('id')] =
                  created_at: new Date()
                  updated_at: new Date()
                  count: 1
                db.profile.update {
                  id: $scope.app.id
                }, $scope.profile, (err, numReplaced, newDoc)->
                  throw err if err
                  $scope.$digest();
188 189 190 191
              else
                window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, "unknown command", matches[1]
      game.on 'close', (code)->
        $scope.runtime.running = false
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
192
        $scope.$digest();
神楽坂玲奈's avatar
神楽坂玲奈 committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

    $scope.achievement_unlocked_count = (category)->
      $scope.profile.achievements[category].length
    $scope.achievement_total_count = (category)->
      $scope.app.achievements[category].items.length
    $scope.achievement_last_unlocked = (category)->
      last = null
      last_index = null
      for index, achievement of $scope.profile.achievements[category]
        if !last or result.created_at < last.created_at
          last = achievement
          last_index = index
      $scope.app.achievements[category].items[index]

    $scope.achievement_locked = (category, index)->
      if $scope.profile.achievements[category][index]
        ''
      else
        'locked'

神楽坂玲奈's avatar
0.0.4  
神楽坂玲奈 committed
213 214 215 216 217 218 219 220 221 222
    $scope.tunnel = (server = $scope.tunnel_servers[0])->
      $scope.runtime.tunnel_server = server
      $scope.runtime.tunneling = true
      $scope.runtime.tunnel = null

      tunnel.listen 10800, server.url, (address)->
        $scope.runtime.tunneling = false
        $scope.runtime.tunnel = address
        $scope.$digest()

神楽坂玲奈's avatar
神楽坂玲奈 committed
223

神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
224 225
]

神楽坂玲奈's avatar
0.0.4  
神楽坂玲奈 committed
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
.controller 'UserController', ['$scope','$rootScope', '$http', ($scope, $rootScope, $http)->
    db.user.findOne {}, (err, doc)->
      $rootScope.current_user = doc
      $scope.$digest()

    $scope.sign_in = (user)->
      $scope.signing = true
      $http.get 'http://my-card.in/users/me.json',
        params: user
      .success (data)->
        $scope.signing = false
        if data == 'true'
          $rootScope.current_user = {
            name: user.name
            password: user.password
          }
          if user.remember_me
            db.user.update {}, user, {upsert: true}, (err)->
              throw err if err

        else
          alert '登录失败'
    $scope.sign_out = ()->
      $rootScope.current_user = null
神楽坂玲奈's avatar
神楽坂玲奈 committed
250
      $scope.$apply()
神楽坂玲奈's avatar
0.0.4  
神楽坂玲奈 committed
251 252 253 254 255 256
      db.user.remove {}, (err)->
        throw err if err

    $scope.candy_url = ()->
      "candy/index.html?bosh=http://localhost:5280/http-bind&jid=#{encodeURIComponent $rootScope.current_user.name}@my-card.in&password=#{encodeURIComponent $rootScope.current_user.password}" if $rootScope.current_user
]