<commit_before>const auth = require('auth')
const bodyParser = require('body-parser')
const config = require('config')
const cp = require('child_process')
const express = require('express')
const jwt = require('jsonwebtoken')
const _ = require('lodash/fp')
const saml2 = require('saml2-js')
const url = require('url')
const u = require('utils')
const whitelist = require('whitelist')

const configPath = 'gs://broad-shibboleth-prod.appspot.com/configs/config.20200103a.json'

function escapeHtml(html) {
  return html
    .replace(/[<]/g, '<')
    .replace(/[>]/g, '>')
}

function decodeUriEncoded(s, shouldTrim = false) {
  const dec = decodeURIComponent
  const kvs = s.split('&')
  const pairs = _.map((kv) => kv.split('='))(kvs)
  return _.fromPairs(
    _.map(([k, v]) => [dec(shouldTrim ? k.trim() : k), dec(shouldTrim ? v.trim() : v)])(pairs)
  )
}

async function withConfig(req, res, next) {
  req.config = await config.maybeFetchConfigData(async () => {
    return (await auth.getBearerTokenFromMetadata()) || (await auth.getBearerTokenFromGcloudAuth())
  })
  next()
}

function verifyJwt(token, publicKey) {
  try {
    return jwt.verify(token, publicKey, {algorithms: ['RS256']})
  } catch (err) {
    return
  }
}

const app = express()

app.get('/hello', (req, res) => {
  res.send(`The time is: ${(new Date()).toISOString()}\n`)
})

app.get('/repl', async (req, res) => {
  function p(x) {
    let s = undefined
    if (_.isObject(x)) { s = JSON.stringify(x, null, 2) }
    else { s = x.toString() }
    res.send(s+'\n').end()
  }
  p(isWhiteListed('/example-return?token=asdf'))
})

app.post('/.src', async (req, res, next) => {
  const [type, value] = (req.headers['authorization'] || '').split(/\s+/)
  global.authCache = global.authCache || {}
  if (global.authCache[value]) {
    console.log('Using bearer token from cache.')
    req.locals = {isReloadOkay: true}
    next()
    return
  }
  const requiredPerm = 'appengine.applications.update'
  const permsCheck = u.httpreq({
    hostname: 'cloudresourcemanager.googleapis.com',
    path: `/v1/projects/${process.env.GOOGLE_CLOUD_PROJECT}:testIamPermissions`,
    method: 'post',
    headers: {'Authorization': req.headers['authorization'], 'Content-Type': 'application/json'}
  })
  permsCheck.req.write(JSON.stringify({permissions: [requiredPerm]}))
  permsCheck.req.end()
  await permsCheck.resp
  if (permsCheck.res.statusCode !== 200) {
    res.status(permsCheck.res.statusCode)
    return permsCheck.res.pipe(res)
  }
  permsCheck.body = await u.consumeStreamp(permsCheck.res)
  const grantedPerms = JSON.parse(permsCheck.body.toString()).permissions
  if (_.indexOf(requiredPerm)(grantedPerms) !== -1) {
    global.authCache[value] = true
    setTimeout(() => { delete global.authCache[value] }, 3600000)
    req.locals = {isReloadOkay: true}
    next()
  } else {
    res.send(JSON.stringify({error: {
      message: 'missing required permission',
      requiredPermission: requiredPerm,
      grantedPermissions: grantedPerms
    }}, null, 2)).end()
  }
})

app.get('/public-key.pem', withConfig, (req, res, next) => {
  res.setHeader('Content-Type', 'text/plain')
  res.send(req.config.data.prodKeyPublic).end()
})

app.get('/dev/public-key.pem', withConfig, (req, res, next) => {
  res.setHeader('Content-Type', 'text/plain')
  res.send(req.config.data.devKeyPublic).end()
})

app.get('/', (req, res, next) => {
  const exampleReturnUrl = '/example-return?token=<token>'
  const devStartUrl = `/dev/login?return-url=${encodeURIComponent(exampleReturnUrl)}`
  const prodStartUrl = `/login?return-url=${encodeURIComponent(exampleReturnUrl)}`
  res.send([
    '
Example Workflows for eRA Commons Account Verification
',
    `<p>return url:<br> <b>${escapeHtml(exampleReturnUrl)}</b></p>`,
    `<p>url-encoded:<br><b>${encodeURIComponent(exampleReturnUrl)}</b></p>`,
    '
Development Flow
',
    `<p>key url: <a href="/dev/public-key.pem">/dev/public-key.pem</a>`,
    `<p>start:<br><a href="${devStartUrl}">${devStartUrl}</a></p>`,
    '
Production Flow
',
    `<p>key url: <a href="/public-key.pem">/public-key.pem</a>`,
    `<p>start:<br><a href="${prodStartUrl}">${prodStartUrl}</a></p>`,
    ].join('')).end()
})

app.get('/dev/login', (req, res, next) => {
  const returnUrl = req.query['return-url']
  const isDev = process.env.NODE_ENV !== 'production' // set by App Engine
  res.set(
    'Set-Cookie',
    `return-url=${encodeURIComponent(returnUrl)}; Path=/; HttpOnly; SameSite=None` +
    (isDev ? '' : '; Secure')
  )
  res.send([
    '
Fake eRA Commons Login Page
',
    `<p>return URL: <b>${escapeHtml(returnUrl)}</b></p>`,
    '<form method="post">',
    '
Enter any "username" to continue:
',
    '<input type="text" name="fakeUsername">
',
    '
<input type="submit" value=""Sign-In"">
',
    '</form>',
  ].join('')).end()
})

app.post('/dev/login', withConfig, async (req, res, next) => {
  const body = await u.consumeStreamp(req)
  const cleaned = decodeUriEncoded(body.toString(), true)
  const cookies = decodeUriEncoded(req.get('cookie'))
  const fakeUsername = cleaned.fakeUsername.length === 0 ? undefined : cleaned.fakeUsername
  const payload = {'fake-era-commons-username': fakeUsername}
  const privateKey = req.config.data.devKeyPrivate
  const token = jwt.sign(payload, privateKey, {algorithm: 'RS256'})
  const returnUrl = cookies['return-url'].replace('<token>', token)
  res.send([
    '
"Sign-In" Successful!
',
    `<p>fake username: <b>${escapeHtml(fakeUsername)}</b></p>`,
    '
JWT
',
    '
signing key: (dev private key)
',
    '
verification key: /dev/public-key.pem
',
    `<p>token payload: <b>${escapeHtml(JSON.stringify(payload))}</b></p>`,
    `<p>token:<br><b>${token.match(/.{1,40}/g).join('<br>')}</b></p>`,
    '
Return URL
',
    `<a href="${returnUrl}">${returnUrl.match(/.{1,40}/g).join('<br>')}</a>`,
  ].join('')).end()
})

app.get('/example-return', withConfig, (req, res, next) => {
  const token = req.query.token
  const [header, payload, signature] =
    _.map((x) => Buffer.from(x, 'base64').toString())(token.split('.'))
  const devPublicKey = req.config.data.devKeyPublic
  const prodPublicKey = req.config.data.prodKeyPublic
  const devVerified = verifyJwt(token, devPublicKey) && 'passed' || 'failed'
  const prodVerified = verifyJwt(token, prodPublicKey) && 'passed' || 'failed'
  res.send([
    '
Example Return Page
',
    `<p>header: <b>${header}</b></p>`,
    `<p>payload: <b>${payload}</b></p>`,
    '
Verification
',
    `<p>dev: <b>${devVerified}</b>`,
    `<p>prod: <b>${prodVerified}</b>`,
  ].join('')).end()
})

function maybeCreateSp(config) {
  if (global.sp) return global.sp;
  global.sp = new saml2.ServiceProvider({
    entity_id: 'https://broad-shibboleth-prod.appspot.com',
    private_key: config.data.spKey,
    certificate: config.data.spCert,
    assert_endpoint: 'https://broad-shibboleth-prod.appspot.com/assert'
  })
  return global.sp
}

const withSp = [withConfig, (req, res, next) => {
  req.sp = maybeCreateSp(req.config)
  next()
}]

function maybeCreateIdp(config) {
  if (global.idp) return global.idp;
  global.idp = new saml2.IdentityProvider({
    sso_login_url: "https://auth.nih.gov/affwebservices/public/saml2sso",
    sso_logout_url: "https://auth.nih.gov/affwebservices/public/saml2sso",
    certificates: [config.data.idpCert],
    sign_get_request: true
  })
  return global.idp
}

const withIdp = [withConfig, (req, res, next) => {
  req.idp = maybeCreateIdp(req.config)
  next()
}]

app.get("/metadata.xml", withSp, function(req, res) {
  res.type('application/xml').send(req.sp.create_metadata()).end()
})

app.get("/login", [withSp, withIdp], function(req, res) {
  const returnUrl = req.query['return-url']
  res.set(
    'Set-Cookie',
    `return-url=${encodeURIComponent(returnUrl)}; Path=/; HttpOnly; Secure; SameSite=None`
  )
  req.sp.create_login_request_url(req.idp, {}, (err, loginUrl, requestId) => {
    if (err) return console.error(err)
    res.redirect(loginUrl)
  })
})

function isWhiteListed(urlString) {
  let url = undefined
  try {
    url = new URL(urlString)
  } catch (e) {
    return false
  }
  if (url.protocol !== 'https:') return false;
  const parsedWhitelist = _.map((x) => new URL(x))(whitelist)
  const match = _.find((x) => {
    if (url.origin === x.origin) {
      return url.pathname.startsWith(x.pathname)
    }
    return false
  })(parsedWhitelist)
  return match ? true : false
}

function redirectOrPause(res, returnUrl, token) {
  if (isWhiteListed(returnUrl)) {
    return res.redirect(returnUrl)
  } else {
    const returnUrlWithRedaction = returnUrl.replace(token, '[redacted]')
    res.send([
      '
Un-Trusted Return URL
',
      `<p>The provided return URL:</p>`,
      `<p><b>${escapeHtml(returnUrlWithRedaction)}</b></p>`,
      `<p>is not trusted. Contact `,
      `<a href="https://support.terra.bio/hc/en-us">Terra Support</a>`,
      ` to request that your URL be added to the trusted list.</p>`,
      `<p style="font-size: small;">Full URL for diagnosis:<br>${escapeHtml(returnUrl)}</p>`
    ].join('')).end()
  }
}

app.post("/assert", [withSp, withIdp], bodyParser.urlencoded({extended: true}), function(req, res) {
  const options = {request_body: req.body}
  req.sp.post_assert(req.idp, options, function(err, samlResponse) {
    // Note: If an error is thrown within this callback, the reported error will be
    // "Callback was already called." So that is usually a red herring.
    if (err != null) {
      console.error(err)
      return res.status(500)
    }
    try {
      const cookies = decodeUriEncoded(req.get('cookie'))
      const privateKey = req.config.data.prodKeyPrivate
      const payload = {eraCommonsUsername: samlResponse.user.name_id}
      const token = jwt.sign(payload, privateKey, {algorithm: 'RS256'})
      const returnUrl = cookies['return-url'].replace('<token>', token)
      return redirectOrPause(res, returnUrl, token)
    } catch (e) {
      console.error(e)
      return res.status(500)
    }
  })
})

module.exports = app
<commit_msg>Add shutdown warning for old version.<commit_after>const auth = require('auth')
const bodyParser = require('body-parser')
const config = require('config')
const cp = require('child_process')
const express = require('express')
const jwt = require('jsonwebtoken')
const _ = require('lodash/fp')
const saml2 = require('saml2-js')
const url = require('url')
const u = require('utils')
const whitelist = require('whitelist')

const configPath = 'gs://broad-shibboleth-prod.appspot.com/configs/config.20200103a.json'

function escapeHtml(html) {
  return html
    .replace(/[<]/g, '<')
    .replace(/[>]/g, '>')
}

function decodeUriEncoded(s, shouldTrim = false) {
  const dec = decodeURIComponent
  const kvs = s.split('&')
  const pairs = _.map((kv) => kv.split('='))(kvs)
  return _.fromPairs(
    _.map(([k, v]) => [dec(shouldTrim ? k.trim() : k), dec(shouldTrim ? v.trim() : v)])(pairs)
  )
}

async function withConfig(req, res, next) {
  req.config = await config.maybeFetchConfigData(async () => {
    return (await auth.getBearerTokenFromMetadata()) || (await auth.getBearerTokenFromGcloudAuth())
  })
  next()
}

function verifyJwt(token, publicKey) {
  try {
    return jwt.verify(token, publicKey, {algorithms: ['RS256']})
  } catch (err) {
    return
  }
}

const app = express()

app.use((req, res, next) => {
  if (req.headers['host'] !== 'shibboleth.dsde-prod.broadinstitute.org') {
    return next()
  }
  res.status(400)
  res.write('This version of the Shibboleth service has been permanently shut down.')
  res.write(' The current version is\navailable at broad-shibboleth-prod.appspot.com.')
  res.write(' Contact support@terra.bio for migration assistance.\n')
  res.end()
})

app.get('/hello', (req, res) => {
  res.send(`The time is: ${(new Date()).toISOString()}\n`)
})

app.get('/repl', async (req, res) => {
  function p(x) {
    let s = undefined
    if (_.isObject(x)) { s = JSON.stringify(x, null, 2) }
    else { s = x.toString() }
    res.send(s+'\n').end()
  }
  p(isWhiteListed('/example-return?token=asdf'))
})

app.post('/.src', async (req, res, next) => {
  const [type, value] = (req.headers['authorization'] || '').split(/\s+/)
  global.authCache = global.authCache || {}
  if (global.authCache[value]) {
    console.log('Using bearer token from cache.')
    req.locals = {isReloadOkay: true}
    next()
    return
  }
  const requiredPerm = 'appengine.applications.update'
  const permsCheck = u.httpreq({
    hostname: 'cloudresourcemanager.googleapis.com',
    path: `/v1/projects/${process.env.GOOGLE_CLOUD_PROJECT}:testIamPermissions`,
    method: 'post',
    headers: {'Authorization': req.headers['authorization'], 'Content-Type': 'application/json'}
  })
  permsCheck.req.write(JSON.stringify({permissions: [requiredPerm]}))
  permsCheck.req.end()
  await permsCheck.resp
  if (permsCheck.res.statusCode !== 200) {
    res.status(permsCheck.res.statusCode)
    return permsCheck.res.pipe(res)
  }
  permsCheck.body = await u.consumeStreamp(permsCheck.res)
  const grantedPerms = JSON.parse(permsCheck.body.toString()).permissions
  if (_.indexOf(requiredPerm)(grantedPerms) !== -1) {
    global.authCache[value] = true
    setTimeout(() => { delete global.authCache[value] }, 3600000)
    req.locals = {isReloadOkay: true}
    next()
  } else {
    res.send(JSON.stringify({error: {
      message: 'missing required permission',
      requiredPermission: requiredPerm,
      grantedPermissions: grantedPerms
    }}, null, 2)).end()
  }
})

app.get('/public-key.pem', withConfig, (req, res, next) => {
  res.setHeader('Content-Type', 'text/plain')
  res.send(req.config.data.prodKeyPublic).end()
})

app.get('/dev/public-key.pem', withConfig, (req, res, next) => {
  res.setHeader('Content-Type', 'text/plain')
  res.send(req.config.data.devKeyPublic).end()
})

app.get('/', (req, res, next) => {
  const exampleReturnUrl = '/example-return?token=<token>'
  const devStartUrl = `/dev/login?return-url=${encodeURIComponent(exampleReturnUrl)}`
  const prodStartUrl = `/login?return-url=${encodeURIComponent(exampleReturnUrl)}`
  res.send([
    '
Example Workflows for eRA Commons Account Verification
',
    `<p>return url:<br> <b>${escapeHtml(exampleReturnUrl)}</b></p>`,
    `<p>url-encoded:<br><b>${encodeURIComponent(exampleReturnUrl)}</b></p>`,
    '
Development Flow
',
    `<p>key url: <a href="/dev/public-key.pem">/dev/public-key.pem</a>`,
    `<p>start:<br><a href="${devStartUrl}">${devStartUrl}</a></p>`,
    '
Production Flow
',
    `<p>key url: <a href="/public-key.pem">/public-key.pem</a>`,
    `<p>start:<br><a href="${prodStartUrl}">${prodStartUrl}</a></p>`,
    ].join('')).end()
})

app.get('/dev/login', (req, res, next) => {
  const returnUrl = req.query['return-url']
  const isDev = process.env.NODE_ENV !== 'production' // set by App Engine
  res.set(
    'Set-Cookie',
    `return-url=${encodeURIComponent(returnUrl)}; Path=/; HttpOnly; SameSite=None` +
    (isDev ? '' : '; Secure')
  )
  res.send([
    '
Fake eRA Commons Login Page
',
    `<p>return URL: <b>${escapeHtml(returnUrl)}</b></p>`,
    '<form method="post">',
    '
Enter any "username" to continue:
',
    '<input type="text" name="fakeUsername">
',
    '
<input type="submit" value=""Sign-In"">
',
    '</form>',
  ].join('')).end()
})

app.post('/dev/login', withConfig, async (req, res, next) => {
  const body = await u.consumeStreamp(req)
  const cleaned = decodeUriEncoded(body.toString(), true)
  const cookies = decodeUriEncoded(req.get('cookie'))
  const fakeUsername = cleaned.fakeUsername.length === 0 ? undefined : cleaned.fakeUsername
  const payload = {'fake-era-commons-username': fakeUsername}
  const privateKey = req.config.data.devKeyPrivate
  const token = jwt.sign(payload, privateKey, {algorithm: 'RS256'})
  const returnUrl = cookies['return-url'].replace('<token>', token)
  res.send([
    '
"Sign-In" Successful!
',
    `<p>fake username: <b>${escapeHtml(fakeUsername)}</b></p>`,
    '
JWT
',
    '
signing key: (dev private key)
',
    '
verification key: /dev/public-key.pem
',
    `<p>token payload: <b>${escapeHtml(JSON.stringify(payload))}</b></p>`,
    `<p>token:<br><b>${token.match(/.{1,40}/g).join('<br>')}</b></p>`,
    '
Return URL
',
    `<a href="${returnUrl}">${returnUrl.match(/.{1,40}/g).join('<br>')}</a>`,
  ].join('')).end()
})

app.get('/example-return', withConfig, (req, res, next) => {
  const token = req.query.token
  const [header, payload, signature] =
    _.map((x) => Buffer.from(x, 'base64').toString())(token.split('.'))
  const devPublicKey = req.config.data.devKeyPublic
  const prodPublicKey = req.config.data.prodKeyPublic
  const devVerified = verifyJwt(token, devPublicKey) && 'passed' || 'failed'
  const prodVerified = verifyJwt(token, prodPublicKey) && 'passed' || 'failed'
  res.send([
    '
Example Return Page
',
    `<p>header: <b>${header}</b></p>`,
    `<p>payload: <b>${payload}</b></p>`,
    '
Verification
',
    `<p>dev: <b>${devVerified}</b>`,
    `<p>prod: <b>${prodVerified}</b>`,
  ].join('')).end()
})

function maybeCreateSp(config) {
  if (global.sp) return global.sp;
  global.sp = new saml2.ServiceProvider({
    entity_id: 'https://broad-shibboleth-prod.appspot.com',
    private_key: config.data.spKey,
    certificate: config.data.spCert,
    assert_endpoint: 'https://broad-shibboleth-prod.appspot.com/assert'
  })
  return global.sp
}

const withSp = [withConfig, (req, res, next) => {
  req.sp = maybeCreateSp(req.config)
  next()
}]

function maybeCreateIdp(config) {
  if (global.idp) return global.idp;
  global.idp = new saml2.IdentityProvider({
    sso_login_url: "https://auth.nih.gov/affwebservices/public/saml2sso",
    sso_logout_url: "https://auth.nih.gov/affwebservices/public/saml2sso",
    certificates: [config.data.idpCert],
    sign_get_request: true
  })
  return global.idp
}

const withIdp = [withConfig, (req, res, next) => {
  req.idp = maybeCreateIdp(req.config)
  next()
}]

app.get("/metadata.xml", withSp, function(req, res) {
  res.type('application/xml').send(req.sp.create_metadata()).end()
})

app.get("/login", [withSp, withIdp], function(req, res) {
  const returnUrl = req.query['return-url']
  res.set(
    'Set-Cookie',
    `return-url=${encodeURIComponent(returnUrl)}; Path=/; HttpOnly; Secure; SameSite=None`
  )
  req.sp.create_login_request_url(req.idp, {}, (err, loginUrl, requestId) => {
    if (err) return console.error(err)
    res.redirect(loginUrl)
  })
})

function isWhiteListed(urlString) {
  let url = undefined
  try {
    url = new URL(urlString)
  } catch (e) {
    return false
  }
  if (url.protocol !== 'https:') return false;
  const parsedWhitelist = _.map((x) => new URL(x))(whitelist)
  const match = _.find((x) => {
    if (url.origin === x.origin) {
      return url.pathname.startsWith(x.pathname)
    }
    return false
  })(parsedWhitelist)
  return match ? true : false
}

function redirectOrPause(res, returnUrl, token) {
  if (isWhiteListed(returnUrl)) {
    return res.redirect(returnUrl)
  } else {
    const returnUrlWithRedaction = returnUrl.replace(token, '[redacted]')
    res.send([
      '
Un-Trusted Return URL
',
      `<p>The provided return URL:</p>`,
      `<p><b>${escapeHtml(returnUrlWithRedaction)}</b></p>`,
      `<p>is not trusted. Contact `,
      `<a href="https://support.terra.bio/hc/en-us">Terra Support</a>`,
      ` to request that your URL be added to the trusted list.</p>`,
      `<p style="font-size: small;">Full URL for diagnosis:<br>${escapeHtml(returnUrl)}</p>`
    ].join('')).end()
  }
}

app.post("/assert", [withSp, withIdp], bodyParser.urlencoded({extended: true}), function(req, res) {
  const options = {request_body: req.body}
  req.sp.post_assert(req.idp, options, function(err, samlResponse) {
    // Note: If an error is thrown within this callback, the reported error will be
    // "Callback was already called." So that is usually a red herring.
    if (err != null) {
      console.error(err)
      return res.status(500)
    }
    try {
      const cookies = decodeUriEncoded(req.get('cookie'))
      const privateKey = req.config.data.prodKeyPrivate
      const payload = {eraCommonsUsername: samlResponse.user.name_id}
      const token = jwt.sign(payload, privateKey, {algorithm: 'RS256'})
      const returnUrl = cookies['return-url'].replace('<token>', token)
      return redirectOrPause(res, returnUrl, token)
    } catch (e) {
      console.error(e)
      return res.status(500)
    }
  })
})

module.exports = app
<|endoftext|>


<commit_before>export const updateContextMiddleware = store => next => action => {

    const result = next(action),
          state  = store.getState();

    if (action.type === "@@reduxReactRouter/routerDidChange" && state.router)
    {
        // Generate a specific action to update the context
        const action = {
            type: "ACTION_UPDATE_CONTEXT",
            context: state.router.location.query
        };
        store.dispatch(action);
    }

    return result;
}

// TODO: We need to find a way to plug middlewares like this one.
// as it is very specific to Nuage features (VSS or AAR)
export const updateVisualizationTypeMiddleware = store => next => action => {
    const result = next(action),
          state  = store.getState();

    if (action.type === "@@reduxReactRouter/routerDidChange" && state.router && 'dashboards' in state.router.location)
    {
        const id = state.router.params.id;

        if (id && id.length > 3) {
            const action = {
                type: "ACTION_UPDATE_VISUALIZATION_TYPE",
                visualizationType: id.substr(0, 3).toUpperCase()
            };
            store.dispatch(action);
        }
    }

    return result;
}
<commit_msg>Fixed visualization type switch between vss and aar<commit_after>export const updateContextMiddleware = store => next => action => {

    const result = next(action),
          state  = store.getState();

    if (action.type === "@@reduxReactRouter/routerDidChange" && state.router)
    {
        // Generate a specific action to update the context
        const action = {
            type: "ACTION_UPDATE_CONTEXT",
            context: state.router.location.query
        };
        store.dispatch(action);
    }

    return result;
}

// TODO: We need to find a way to plug middlewares like this one.
// as it is very specific to Nuage features (VSS or AAR)
export const updateVisualizationTypeMiddleware = store => next => action => {
    const result = next(action),
          state  = store.getState();

    if (action.type === "@@reduxReactRouter/routerDidChange" && state.router && state.router.location.pathname.indexOf('dashboards') !== -1)
    {
        const id           = state.router.params.id,
              previousType = state.interface.get("visualizationType"),
              nextType     = id && id.length > 3 ? id.substr(0, 3).toUpperCase() : null;

        if (nextType && nextType !== previousType) {
            const action = {
                type: "ACTION_UPDATE_VISUALIZATION_TYPE",
                visualizationType: nextType
            };
            store.dispatch(action);
        }
    }

    return result;
}
<|endoftext|>


<commit_before>import * as THREE from 'three';
// import CANNON from 'cannon';
import keymaster from 'keymaster';
import XboxController from './controllers/xbox';
import StaticRotationFollowCamera from './StaticRotationFollowCamera';
import Box from './objects/Box';
// import Ball from './objects/Ball';
import Player from './Player';
import Game from './Game';
import {SCENE, PHYSICS,} from './Game';
import Tunnel from './levels/Tunnel';

// SCENE, CAMERA, RENDERER
const game = new Game();
let aspect = window.innerWidth / window.innerHeight;
const followCamera = new StaticRotationFollowCamera();
followCamera.position.z = 1;
followCamera.position.y = 1;

const audioLoader = new THREE.AudioLoader();
const listener = new THREE.AudioListener();
followCamera.add(listener);

const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.domElement.setAttribute('tabIndex', '0');
renderer.domElement.focus();

window.onresize = () => {
  aspect = window.innerWidth / window.innerHeight;
  followCamera.aspect = aspect;
  followCamera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
};

const controller = new XboxController();
controller.onButton('axis_left', (event) => {
  console.log(event.value);
});

// LIGHTS
const ambientLight = new THREE.AmbientLight(0x444444, 0.5);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(25, 50, 25);
light.castShadow = true;
SCENE.add(ambientLight);
SCENE.add(light);

light.shadow.mapSize.width = 4096;
light.shadow.mapSize.height = 4096;
light.shadow.camera.near = 1;
light.shadow.camera.far = 100;
light.shadow.camera.left = -20;
light.shadow.camera.right = 20;
light.shadow.camera.down = -20;
light.shadow.camera.top = 20;

// GAME OBJECTS
// const ball = new Ball(0.05, 32, '#ff0000');
// ball.position.set(0, 0.1, 0.2);

const player = new Player(15, 0.05, 32, '#ff0000');

// PHYSICS
// game.addObject(ball);
game.setPlayer(player);

const boxSpawnAmount = 10;
for (let i = 0; i < boxSpawnAmount; i++) {
  const box = new Box(0.1, 0.1, 0.1, '#ffff00');
  box.position.set(0, 0.2, -0.2 * i);
  game.addObject(box);
}

// SOUNDS
audioLoader.load('../sounds/thump.mp3', (buffer) => {
  for (const object of game.objects) {
    object.onCollide((e) => {
      const contact = e.contact;
      const hitSpeed = Math.abs(contact.getImpactVelocityAlongNormal());
      const volumeFactor = 0.02;
      const volume = Math.min(1, volumeFactor * hitSpeed);
      if (volume > volumeFactor) {
        const sound = new THREE.PositionalAudio(listener);
        sound.setBuffer(buffer);
        sound.setRefDistance(1);
        sound.setVolume(volume);
        object.mesh.add(sound);
        sound.play();
      }
    });
  }
});

game.loadLevel(new Tunnel());

// GAME LOOP
let previousTime;
function render() {
  const time = new Date().getTime();
  const delta = time - previousTime;
  previousTime = time;

  // PLAYER CONTROLS
  controller.handleInput();
  const up = keymaster.isPressed('w');
  const down = keymaster.isPressed('s');
  const left = keymaster.isPressed('a');
  const right = keymaster.isPressed('d');

  if (up) PHYSICS.controlGravity(1, 0);
  if (down) PHYSICS.controlGravity(-1, 0);
  if (left) PHYSICS.controlGravity(0, -1);
  if (right) PHYSICS.controlGravity(0, 1);

  game.update(delta);

  // const heading = new THREE.Vector3(forceDirection.x, forceDirection.z, 0);
  // if (heading.length() !== 0) heading.normalize();

  followCamera.update(ball.position);

  renderer.render(SCENE, followCamera);

  requestAnimationFrame(render);
}
render();
<commit_msg>Corrected update camera parameter.<commit_after>import * as THREE from 'three';
// import CANNON from 'cannon';
import keymaster from 'keymaster';
import XboxController from './controllers/xbox';
import StaticRotationFollowCamera from './StaticRotationFollowCamera';
import Box from './objects/Box';
// import Ball from './objects/Ball';
import Player from './Player';
import Game from './Game';
import {SCENE, PHYSICS,} from './Game';
import Tunnel from './levels/Tunnel';

// SCENE, CAMERA, RENDERER
const game = new Game();
let aspect = window.innerWidth / window.innerHeight;
const followCamera = new StaticRotationFollowCamera();
followCamera.position.z = 1;
followCamera.position.y = 1;

const audioLoader = new THREE.AudioLoader();
const listener = new THREE.AudioListener();
followCamera.add(listener);

const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.domElement.setAttribute('tabIndex', '0');
renderer.domElement.focus();

window.onresize = () => {
  aspect = window.innerWidth / window.innerHeight;
  followCamera.aspect = aspect;
  followCamera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
};

const controller = new XboxController();
controller.onButton('axis_left', (event) => {
  console.log(event.value);
});

// LIGHTS
const ambientLight = new THREE.AmbientLight(0x444444, 0.5);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(25, 50, 25);
light.castShadow = true;
SCENE.add(ambientLight);
SCENE.add(light);

light.shadow.mapSize.width = 4096;
light.shadow.mapSize.height = 4096;
light.shadow.camera.near = 1;
light.shadow.camera.far = 100;
light.shadow.camera.left = -20;
light.shadow.camera.right = 20;
light.shadow.camera.down = -20;
light.shadow.camera.top = 20;

// GAME OBJECTS
// const ball = new Ball(0.05, 32, '#ff0000');
// ball.position.set(0, 0.1, 0.2);

const player = new Player(15, 0.05, 32, '#ff0000');

// PHYSICS
// game.addObject(ball);
game.setPlayer(player);

const boxSpawnAmount = 10;
for (let i = 0; i < boxSpawnAmount; i++) {
  const box = new Box(0.1, 0.1, 0.1, '#ffff00');
  box.position.set(0, 0.2, -0.2 * i);
  game.addObject(box);
}

// SOUNDS
audioLoader.load('../sounds/thump.mp3', (buffer) => {
  for (const object of game.objects) {
    object.onCollide((e) => {
      const contact = e.contact;
      const hitSpeed = Math.abs(contact.getImpactVelocityAlongNormal());
      const volumeFactor = 0.02;
      const volume = Math.min(1, volumeFactor * hitSpeed);
      if (volume > volumeFactor) {
        const sound = new THREE.PositionalAudio(listener);
        sound.setBuffer(buffer);
        sound.setRefDistance(1);
        sound.setVolume(volume);
        object.mesh.add(sound);
        sound.play();
      }
    });
  }
});

game.loadLevel(new Tunnel());

// GAME LOOP
let previousTime;
function render() {
  const time = new Date().getTime();
  const delta = time - previousTime;
  previousTime = time;

  // PLAYER CONTROLS
  controller.handleInput();
  const up = keymaster.isPressed('w');
  const down = keymaster.isPressed('s');
  const left = keymaster.isPressed('a');
  const right = keymaster.isPressed('d');

  if (up) PHYSICS.controlGravity(1, 0);
  if (down) PHYSICS.controlGravity(-1, 0);
  if (left) PHYSICS.controlGravity(0, -1);
  if (right) PHYSICS.controlGravity(0, 1);

  game.update(delta);

  // const heading = new THREE.Vector3(forceDirection.x, forceDirection.z, 0);
  // if (heading.length() !== 0) heading.normalize();

  followCamera.update(player.position);

  renderer.render(SCENE, followCamera);

  requestAnimationFrame(render);
}
render();
<|endoftext|>


<commit_before>(function () {
  const UNAUTHORIZED = 401;
  const REQUEST_FINISHED = 4;
  var keycloakRedirect = {
    authenticate: (config, client, window) => {
      if (config.backend === void 0) {
        throw "Missing backend in config.";
      }
      if (config.clientId === void 0) {
        throw "Missing clientId in config.";
      }
      if (config.keycloakUrl === void 0) {
        throw "Missing keycloakUrl in config.";
      }

      client.withCredentials = true;
      client.open("GET", config.backend + "/oauth/expired", true);
      client.send();
      client.onreadystatechange = () => {
        if (client.readyState === REQUEST_FINISHED && client.status === UNAUTHORIZED) {
          window.location = config.keycloakUrl + encodeURI("?redirect_uri=\"" + window.location + "\"&client_id=\"" + config.clientId + "\"&response_type=code");
        }
      };
    }
  };
  module.exports = keycloakRedirect;
}());
<commit_msg>IBM-109: Remove quotes from url query string<commit_after>(function () {
  const UNAUTHORIZED = 401;
  const REQUEST_FINISHED = 4;
  var keycloakRedirect = {
    authenticate: (config, client, window) => {
      if (config.backend === void 0) {
        throw "Missing backend in config.";
      }
      if (config.clientId === void 0) {
        throw "Missing clientId in config.";
      }
      if (config.keycloakUrl === void 0) {
        throw "Missing keycloakUrl in config.";
      }

      client.withCredentials = true;
      client.open("GET", config.backend + "/oauth/expired", true);
      client.send();
      client.onreadystatechange = () => {
        if (client.readyState === REQUEST_FINISHED && client.status === UNAUTHORIZED) {
          window.location = config.keycloakUrl + encodeURI(`?redirect_uri="${window.location}"&client_id="${config.clientId}"&response_type=code`);
        }
      };
    }
  };
  module.exports = keycloakRedirect;
}());
<|endoftext|>


<commit_before>import Vue from 'vue'
import App from './App.vue'

Vue.config.debug = true;

new Vue({
    el: '#app',
    template: "<App/>",
    components: {App}
});
<commit_msg>import swipe component<commit_after>import Vue from 'vue'
import App from './App.vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'

Vue.use(VueAwesomeSwiper)

Vue.config.debug = true;

new Vue({
    el: '#app',
    template: "<App/>",
    components: {App}
});
<|endoftext|>


<commit_before>"use strict";

/** @constructor */
function v86(bus)
{
    /** @type {boolean} */
    this.running = false;

    /** @type {boolean} */
    this.stopped = false;

    /** @type {CPU} */
    this.cpu = new CPU();

    this.bus = bus;
    bus.register("cpu-init", this.init, this);
    bus.register("cpu-run", this.run, this);
    bus.register("cpu-stop", this.stop, this);
    bus.register("cpu-restart", this.restart, this);

    this.register_tick();
}

v86.prototype.run = function()
{
    if(!this.running)
    {
        this.bus.send("emulator-started");
        this.fast_next_tick();
    }
};

v86.prototype.do_tick = function()
{
    if(this.stopped)
    {
        this.stopped = this.running = false;
        this.bus.send("emulator-stopped");
        return;
    }

    this.running = true;
    var dt = this.cpu.main_run();

    if(dt <= 0)
    {
        this.fast_next_tick();
    }
    else
    {
        this.next_tick(dt);
    }
};

v86.prototype.stop = function()
{
    if(this.running)
    {
        this.stopped = true;
    }
};

v86.prototype.restart = function()
{
    this.cpu.reset();
    this.cpu.load_bios();
};

v86.prototype.init = function(settings)
{
    this.cpu.init(settings, this.bus);
    this.bus.send("emulator-ready");
};

if(typeof setImmediate !== "undefined")
{
    v86.prototype.fast_next_tick = function()
    {
        setImmediate(() => { this.do_tick(); });
    };

    v86.prototype.register_tick = function() {};
}
else if(typeof window !== "undefined" && typeof postMessage !== "undefined")
{
    // setImmediate shim for the browser.
    // TODO: Make this deactivatable, for other applications
    //       using postMessage

    /** @const */
    let MAGIC_POST_MESSAGE = 0xAA55;

    v86.prototype.fast_next_tick = function()
    {
        window.postMessage(MAGIC_POST_MESSAGE, "*");
    };

    v86.prototype.register_tick = function()
    {
        window.addEventListener("message", (e) =>
        {
            if(e.source === window && e.data === MAGIC_POST_MESSAGE)
            {
                this.do_tick();
            }
        }, false);
    };
}
else
{
    v86.prototype.fast_next_tick = function()
    {
        setTimeout(() => { this.do_tick(); }, 0);
    };

    v86.prototype.register_tick = function() {};
}

if(typeof document !== "undefined" && typeof document.hidden === "boolean")
{
    v86.prototype.next_tick = function(t)
    {
        if(t < 4 || document.hidden)
        {
            // Avoid sleeping for 1 second (happens if page is not
            // visible), it can break boot processes. Also don't try to
            // sleep for less than 4ms, since the value is clamped up
            this.fast_next_tick();
        }
        else
        {
            setTimeout(() => { this.do_tick(); }, t);
        }
    };
}
else
{
    // In environments that aren't browsers, we might as well use setTimeout
    v86.prototype.next_tick = function(t)
    {
        setTimeout(() => { this.do_tick(); }, t);
    };
}

v86.prototype.save_state = function()
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.save_state();
};

v86.prototype.restore_state = function(state)
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.restore_state(state);
};

if(typeof performance === "object" && performance.now)
{
    v86.microtick = function()
    {
        return performance.now();
    };
}
//else if(typeof process === "object" && process.hrtime)
//{
//    v86.microtick = function()
//    {
//        var t = process.hrtime();
//        return t[0] * 1000 + t[1] / 1e6;
//    };
//}
else
{
    v86.microtick = Date.now;
}
<commit_msg>Make Closure Compiler happy<commit_after>"use strict";

/** @constructor */
function v86(bus)
{
    /** @type {boolean} */
    this.running = false;

    /** @type {boolean} */
    this.stopped = false;

    /** @type {CPU} */
    this.cpu = new CPU();

    this.bus = bus;
    bus.register("cpu-init", this.init, this);
    bus.register("cpu-run", this.run, this);
    bus.register("cpu-stop", this.stop, this);
    bus.register("cpu-restart", this.restart, this);

    this.register_tick();
}

v86.prototype.run = function()
{
    if(!this.running)
    {
        this.bus.send("emulator-started");
        this.fast_next_tick();
    }
};

v86.prototype.do_tick = function()
{
    if(this.stopped)
    {
        this.stopped = this.running = false;
        this.bus.send("emulator-stopped");
        return;
    }

    this.running = true;
    var dt = this.cpu.main_run();

    if(dt <= 0)
    {
        this.fast_next_tick();
    }
    else
    {
        this.next_tick(dt);
    }
};

v86.prototype.stop = function()
{
    if(this.running)
    {
        this.stopped = true;
    }
};

v86.prototype.restart = function()
{
    this.cpu.reset();
    this.cpu.load_bios();
};

v86.prototype.init = function(settings)
{
    this.cpu.init(settings, this.bus);
    this.bus.send("emulator-ready");
};

if(typeof setImmediate !== "undefined")
{
    /** @this {v86} */
    var fast_next_tick = function()
    {
        setImmediate(() => { this.do_tick(); });
    };

    /** @this {v86} */
    var register_tick = function() {};
}
else if(typeof window !== "undefined" && typeof postMessage !== "undefined")
{
    // setImmediate shim for the browser.
    // TODO: Make this deactivatable, for other applications
    //       using postMessage

    /** @const */
    let MAGIC_POST_MESSAGE = 0xAA55;

    /** @this {v86} */
    fast_next_tick = function()
    {
        window.postMessage(MAGIC_POST_MESSAGE, "*");
    };

    /** @this {v86} */
    register_tick = function()
    {
        window.addEventListener("message", (e) =>
        {
            if(e.source === window && e.data === MAGIC_POST_MESSAGE)
            {
                this.do_tick();
            }
        }, false);
    };
}
else
{
    /** @this {v86} */
    fast_next_tick = function()
    {
        setTimeout(() => { this.do_tick(); }, 0);
    };

    /** @this {v86} */
    register_tick = function() {};
}

v86.prototype.fast_next_tick = fast_next_tick;
v86.prototype.register_tick = register_tick;

if(typeof document !== "undefined" && typeof document.hidden === "boolean")
{
    /** @this {v86} */
    var next_tick = function(t)
    {
        if(t < 4 || document.hidden)
        {
            // Avoid sleeping for 1 second (happens if page is not
            // visible), it can break boot processes. Also don't try to
            // sleep for less than 4ms, since the value is clamped up
            this.fast_next_tick();
        }
        else
        {
            setTimeout(() => { this.do_tick(); }, t);
        }
    };
}
else
{
    // In environments that aren't browsers, we might as well use setTimeout
    /** @this {v86} */
    next_tick = function(t)
    {
        setTimeout(() => { this.do_tick(); }, t);
    };
}

v86.prototype.next_tick = next_tick;

v86.prototype.save_state = function()
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.save_state();
};

v86.prototype.restore_state = function(state)
{
    // TODO: Should be implemented here, not on cpu
    return this.cpu.restore_state(state);
};

if(typeof performance === "object" && performance.now)
{
    v86.microtick = function()
    {
        return performance.now();
    };
}
//else if(typeof process === "object" && process.hrtime)
//{
//    v86.microtick = function()
//    {
//        var t = process.hrtime();
//        return t[0] * 1000 + t[1] / 1e6;
//    };
//}
else
{
    v86.microtick = Date.now;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017-present PlatformIO <contact@platformio.org>
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */

import * as misc from './misc';
import * as pioNodeHelpers from 'platformio-node-helpers';
import * as piodebug from 'platformio-vscode-debug';
import * as utils from './utils';

import InstallationManager from './installer/manager';
import PIOHome from './home';
import PIOTerminal from './terminal';
import QuickAccessTreeProvider from './views/quick-access-tree';
import StateStorage from './state-storage';
import TaskManager from './tasks/manager';
import fs from 'fs-plus';
import path from 'path';
import vscode from 'vscode';

class PlatformIOVSCodeExtension {
  constructor() {
    this.context = undefined;
    this.pioTerm = undefined;
    this.pioHome = undefined;
    this.subscriptions = [];

    this._enterpriseSettings = undefined;
  }

  async activate(context) {
    this.context = context;
    this.stateStorage = new StateStorage(context.globalState);
    this.pioHome = new PIOHome();
    this.pioTerm = new PIOTerminal();

    this.subscriptions.push(this.pioHome, this.pioTerm);

    const hasPIOProject = !!utils.getActivePIOProjectDir();
    if (!hasPIOProject && this.getSetting('activateOnlyOnPlatformIOProject')) {
      return;
    }

    // temporary workaround for https://github.com/Microsoft/vscode/issues/58348
    if (
      !vscode.workspace
        .getConfiguration('extensions')
        .has('showRecommendationsOnlyOnDemand')
    ) {
      vscode.workspace
        .getConfiguration('extensions')
        .update('showRecommendationsOnlyOnDemand', true);
    }

    this.patchOSEnviron();
    await this.startInstaller();
    this.subscriptions.push(this.handleUseDevelopmentPIOCoreConfiguration());

    vscode.commands.executeCommand('setContext', 'pioCoreReady', true);
    if (typeof this.getEnterpriseSetting('onPIOCoreReady') === 'function') {
      await this.getEnterpriseSetting('onPIOCoreReady')();
    }

    this.subscriptions.push(
      vscode.window.registerTreeDataProvider(
        'platformio-activitybar.quickAccess',
        new QuickAccessTreeProvider()
      )
    );

    if (!hasPIOProject) {
      await this.startPIOHome();
      this.initToolbar({ filterCommands: ['platformio-ide.showHome'] });
      return;
    }

    if (this.getSetting('updateTerminalPathConfiguration')) {
      this.pioTerm.updateEnvConfiguration();
    }

    this.registerGlobalCommands();
    this.subscriptions.push(new TaskManager());
    this.initDebug();
    this.initToolbar({
      ignoreCommands: this.getEnterpriseSetting('ignoreToolbarCommands')
    });
    this.initProjectIndexer();
    this.startPIOHome();

    misc.maybeRateExtension(this.stateStorage);
    misc.warnAboutConflictedExtensions();
    this.subscriptions.push(
      vscode.window.onDidChangeActiveTextEditor(editor =>
        misc.warnAboutInoFile(editor, this.stateStorage)
      )
    );
  }

  getSetting(id) {
    return vscode.workspace.getConfiguration('platformio-ide').get(id);
  }

  loadEnterpriseSettings() {
    const ext = vscode.extensions.all.find(
      item =>
        item.id.startsWith('platformio.') &&
        item.id !== 'platformio.platformio-ide' &&
        item.isActive
    );
    return ext && ext.exports ? ext.exports.settings : undefined;
  }

  getEnterpriseSetting(id, defaultValue = undefined) {
    if (!this._enterpriseSettings) {
      this._enterpriseSettings = this.loadEnterpriseSettings();
    }
    if (this._enterpriseSettings && id in this._enterpriseSettings) {
      return this._enterpriseSettings[id];
    }
    return defaultValue;
  }

  patchOSEnviron() {
    const extraVars = {
      PLATFORMIO_IDE: utils.getIDEVersion()
    };
    // handle HTTP proxy settings
    const http_proxy = vscode.workspace.getConfiguration('http').get('proxy');
    if (http_proxy && !process.env.HTTP_PROXY && !process.env.http_proxy) {
      extraVars['HTTP_PROXY'] = http_proxy;
    }
    if (!vscode.workspace.getConfiguration('http').get('proxyStrictSSL')) {
      // https://stackoverflow.com/questions/48391750/disable-python-requests-ssl-validation-for-an-imported-module
      extraVars['CURL_CA_BUNDLE'] = '';
    }
    if (http_proxy && !process.env.HTTPS_PROXY && !process.env.https_proxy) {
      extraVars['HTTPS_PROXY'] = http_proxy;
    }
    pioNodeHelpers.proc.patchOSEnviron({
      caller: 'vscode',
      extraPath: this.getSetting('customPATH'),
      extraVars
    });
  }

  startInstaller() {
    return vscode.window.withProgress(
      {
        location: vscode.ProgressLocation.Window,
        title: 'PlatformIO'
      },
      async progress => {
        progress.report({
          message: 'Checking PlatformIO Core installation...'
        });

        const im = new InstallationManager(this.context.globalState);
        if (im.locked()) {
          vscode.window.showInformationMessage(
            'PlatformIO IDE installation has been suspended, because PlatformIO ' +
              'IDE Installer is already started in another window.'
          );
        } else if (await im.check()) {
          return;
        } else {
          progress.report({
            message: 'Installing PlatformIO IDE...'
          });
          const outputChannel = vscode.window.createOutputChannel(
            'PlatformIO Installation'
          );
          outputChannel.show();

          outputChannel.appendLine('Installing PlatformIO Core...');
          outputChannel.appendLine(
            'It may take a few minutes depending on your connection speed'
          );
          outputChannel.appendLine(
            'Please do not close this window and do not ' +
              'open other folders until this process is completed.'
          );

          try {
            im.lock();
            await im.install();
            outputChannel.appendLine('PlatformIO IDE installed successfully.\n');
            outputChannel.appendLine('Please restart VSCode.');
            const action = 'Reload Now';
            const selected = await vscode.window.showInformationMessage(
              'PlatformIO IDE has been successfully installed! Please reload window',
              action
            );
            if (selected === action) {
              vscode.commands.executeCommand('workbench.action.reloadWindow');
            }
          } catch (err) {
            outputChannel.appendLine('Failed to install PlatformIO IDE.');
            utils.notifyError('Installation Manager', err);
          } finally {
            im.unlock();
          }
        }
        im.destroy();
        return Promise.reject(undefined);
      }
    );
  }

  async startPIOHome() {
    if (
      this.getSetting('disablePIOHomeStartup') ||
      !(await pioNodeHelpers.home.showAtStartup('vscode'))
    ) {
      return;
    }
    vscode.commands.executeCommand('platformio-ide.showHome');
  }

  registerGlobalCommands() {
    this.subscriptions.push(
      vscode.commands.registerCommand('platformio-ide.showHome', startUrl =>
        this.pioHome.toggle(startUrl)
      ),
      vscode.commands.registerCommand('platformio-ide.newTerminal', () =>
        this.pioTerm.new().show()
      ),
      vscode.commands.registerCommand('platformio-ide.openPIOCoreCLI', () =>
        this.pioTerm.sendText('pio --help')
      ),
      vscode.commands.registerCommand('platformio-ide.startDebugging', () => {
        vscode.commands.executeCommand('workbench.view.debug');
        vscode.commands.executeCommand('workbench.debug.action.toggleRepl');
        vscode.commands.executeCommand('workbench.action.debug.start');
      }),
      vscode.commands.registerCommand('platformio-ide.updateGlobalLibs', () =>
        this.pioTerm.sendText('platformio lib --global update')
      ),
      vscode.commands.registerCommand('platformio-ide.updatePlatforms', () =>
        this.pioTerm.sendText('platformio platform update')
      ),
      vscode.commands.registerCommand('platformio-ide.updateCore', () =>
        this.pioTerm.sendText('platformio update')
      ),
      vscode.commands.registerCommand('platformio-ide.upgradeCore', () =>
        this.pioTerm.sendText('platformio upgrade')
      )
    );
  }

  initDebug() {
    piodebug.activate(this.context);
  }

  initToolbar({ filterCommands, ignoreCommands }) {
    if (this.getSetting('disableToolbar')) {
      return;
    }
    [
      ['$(home)', 'PlatformIO: Home', 'platformio-ide.showHome'],
      ['$(check)', 'PlatformIO: Build', 'platformio-ide.build'],
      ['$(arrow-right)', 'PlatformIO: Upload', 'platformio-ide.upload'],
      [
        '$(cloud-upload)',
        'PlatformIO: Upload to remote device',
        'platformio-ide.remote'
      ],
      ['$(trashcan)', 'PlatformIO: Clean', 'platformio-ide.clean'],
      ['$(beaker)', 'PlatformIO: Test', 'platformio-ide.test'],
      ['$(checklist)', 'PlatformIO: Run Task...', 'workbench.action.tasks.runTask'],
      ['$(plug)', 'PlatformIO: Serial Monitor', 'platformio-ide.serialMonitor'],
      ['$(terminal)', 'PlatformIO: New Terminal', 'platformio-ide.newTerminal']
    ]
      .filter(
        item =>
          (!filterCommands || filterCommands.includes(item[2])) &&
          (!ignoreCommands || !ignoreCommands.includes(item[2]))
      )
      .reverse()
      .forEach((item, index) => {
        const [text, tooltip, command] = item;
        const sbItem = vscode.window.createStatusBarItem(
          vscode.StatusBarAlignment.Left,
          10 + index
        );
        sbItem.text = text;
        sbItem.tooltip = tooltip;
        sbItem.command = command;
        sbItem.show();
        this.subscriptions.push(sbItem);
      });
  }

  initProjectIndexer() {
    const observer = new pioNodeHelpers.project.ProjectObserver({
      ide: 'vscode',
      createFileSystemWatcher: vscode.workspace.createFileSystemWatcher,
      createDirSystemWatcher: dir =>
        vscode.workspace.createFileSystemWatcher(path.join(dir, '*')),
      withProgress: task =>
        vscode.window.withProgress(
          {
            location: vscode.ProgressLocation.Window,
            title: 'PlatformIO: IntelliSense Index Rebuild'
          },
          task
        )
    });

    const doUpdate = () => {
      observer.update(
        this.getSetting('autoRebuildAutocompleteIndex') &&
          vscode.workspace.workspaceFolders
          ? vscode.workspace.workspaceFolders.map(folder => folder.uri.fsPath)
          : []
      );
    };

    this.subscriptions.push(
      observer,
      vscode.workspace.onDidChangeWorkspaceFolders(doUpdate.bind(this)),
      vscode.workspace.onDidChangeConfiguration(doUpdate.bind(this)),
      vscode.commands.registerCommand('platformio-ide.rebuildProjectIndex', () => {
        doUpdate(); // re-scan PIO Projects
        observer.rebuildIndex();
      })
    );
    doUpdate();
  }

  handleUseDevelopmentPIOCoreConfiguration() {
    return vscode.workspace.onDidChangeConfiguration(e => {
      if (
        !e.affectsConfiguration('platformio-ide.useDevelopmentPIOCore') ||
        !this.getSetting('useBuiltinPIOCore')
      ) {
        return;
      }
      const envDir = pioNodeHelpers.core.getEnvDir();
      if (!envDir || !fs.isDirectorySync(envDir)) {
        return;
      }
      pioNodeHelpers.home.shutdownServer();
      const delayedJob = () => {
        try {
          fs.removeSync(envDir);
        } catch (err) {
          console.warn(err);
        }
        vscode.window.showInformationMessage(
          'Please restart VSCode to apply the changes.'
        );
      };
      setTimeout(delayedJob, 2000);
    });
  }

  disposeLocalSubscriptions() {
    vscode.commands.executeCommand('setContext', 'pioCoreReady', false);
    pioNodeHelpers.misc.disposeSubscriptions(this.subscriptions);
  }

  deactivate() {
    this.disposeLocalSubscriptions();
  }
}

export const extension = new PlatformIOVSCodeExtension();

export function activate(context) {
  extension.activate(context);
  return extension;
}

export function deactivate() {
  extension.deactivate();
  piodebug.deactivate();
}
<commit_msg>Bump version to 2.0.0-beta.2Fix global commands<commit_after>/**
 * Copyright (c) 2017-present PlatformIO <contact@platformio.org>
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */

import * as misc from './misc';
import * as pioNodeHelpers from 'platformio-node-helpers';
import * as piodebug from 'platformio-vscode-debug';
import * as utils from './utils';

import InstallationManager from './installer/manager';
import PIOHome from './home';
import PIOTerminal from './terminal';
import QuickAccessTreeProvider from './views/quick-access-tree';
import StateStorage from './state-storage';
import TaskManager from './tasks/manager';
import fs from 'fs-plus';
import path from 'path';
import vscode from 'vscode';

class PlatformIOVSCodeExtension {
  constructor() {
    this.context = undefined;
    this.pioTerm = undefined;
    this.pioHome = undefined;
    this.subscriptions = [];

    this._enterpriseSettings = undefined;
  }

  async activate(context) {
    this.context = context;
    this.stateStorage = new StateStorage(context.globalState);
    this.pioHome = new PIOHome();
    this.pioTerm = new PIOTerminal();

    this.subscriptions.push(this.pioHome, this.pioTerm);

    const hasPIOProject = !!utils.getActivePIOProjectDir();
    if (!hasPIOProject && this.getSetting('activateOnlyOnPlatformIOProject')) {
      return;
    }

    // temporary workaround for https://github.com/Microsoft/vscode/issues/58348
    if (
      !vscode.workspace
        .getConfiguration('extensions')
        .has('showRecommendationsOnlyOnDemand')
    ) {
      vscode.workspace
        .getConfiguration('extensions')
        .update('showRecommendationsOnlyOnDemand', true);
    }

    this.patchOSEnviron();
    await this.startInstaller();
    this.subscriptions.push(this.handleUseDevelopmentPIOCoreConfiguration());

    vscode.commands.executeCommand('setContext', 'pioCoreReady', true);
    if (typeof this.getEnterpriseSetting('onPIOCoreReady') === 'function') {
      await this.getEnterpriseSetting('onPIOCoreReady')();
    }

    this.subscriptions.push(
      vscode.window.registerTreeDataProvider(
        'platformio-activitybar.quickAccess',
        new QuickAccessTreeProvider()
      )
    );

    this.registerGlobalCommands();

    if (!hasPIOProject) {
      await this.startPIOHome();
      this.initToolbar({ filterCommands: ['platformio-ide.showHome'] });
      return;
    }

    if (this.getSetting('updateTerminalPathConfiguration')) {
      this.pioTerm.updateEnvConfiguration();
    }

    this.subscriptions.push(new TaskManager());
    this.initDebug();
    this.initToolbar({
      ignoreCommands: this.getEnterpriseSetting('ignoreToolbarCommands')
    });
    this.initProjectIndexer();
    this.startPIOHome();

    misc.maybeRateExtension(this.stateStorage);
    misc.warnAboutConflictedExtensions();
    this.subscriptions.push(
      vscode.window.onDidChangeActiveTextEditor(editor =>
        misc.warnAboutInoFile(editor, this.stateStorage)
      )
    );
  }

  getSetting(id) {
    return vscode.workspace.getConfiguration('platformio-ide').get(id);
  }

  loadEnterpriseSettings() {
    const ext = vscode.extensions.all.find(
      item =>
        item.id.startsWith('platformio.') &&
        item.id !== 'platformio.platformio-ide' &&
        item.isActive
    );
    return ext && ext.exports ? ext.exports.settings : undefined;
  }

  getEnterpriseSetting(id, defaultValue = undefined) {
    if (!this._enterpriseSettings) {
      this._enterpriseSettings = this.loadEnterpriseSettings();
    }
    if (this._enterpriseSettings && id in this._enterpriseSettings) {
      return this._enterpriseSettings[id];
    }
    return defaultValue;
  }

  patchOSEnviron() {
    const extraVars = {
      PLATFORMIO_IDE: utils.getIDEVersion()
    };
    // handle HTTP proxy settings
    const http_proxy = vscode.workspace.getConfiguration('http').get('proxy');
    if (http_proxy && !process.env.HTTP_PROXY && !process.env.http_proxy) {
      extraVars['HTTP_PROXY'] = http_proxy;
    }
    if (!vscode.workspace.getConfiguration('http').get('proxyStrictSSL')) {
      // https://stackoverflow.com/questions/48391750/disable-python-requests-ssl-validation-for-an-imported-module
      extraVars['CURL_CA_BUNDLE'] = '';
    }
    if (http_proxy && !process.env.HTTPS_PROXY && !process.env.https_proxy) {
      extraVars['HTTPS_PROXY'] = http_proxy;
    }
    pioNodeHelpers.proc.patchOSEnviron({
      caller: 'vscode',
      extraPath: this.getSetting('customPATH'),
      extraVars
    });
  }

  startInstaller() {
    return vscode.window.withProgress(
      {
        location: vscode.ProgressLocation.Window,
        title: 'PlatformIO'
      },
      async progress => {
        progress.report({
          message: 'Checking PlatformIO Core installation...'
        });

        const im = new InstallationManager(this.context.globalState);
        if (im.locked()) {
          vscode.window.showInformationMessage(
            'PlatformIO IDE installation has been suspended, because PlatformIO ' +
              'IDE Installer is already started in another window.'
          );
        } else if (await im.check()) {
          return;
        } else {
          progress.report({
            message: 'Installing PlatformIO IDE...'
          });
          const outputChannel = vscode.window.createOutputChannel(
            'PlatformIO Installation'
          );
          outputChannel.show();

          outputChannel.appendLine('Installing PlatformIO Core...');
          outputChannel.appendLine(
            'It may take a few minutes depending on your connection speed'
          );
          outputChannel.appendLine(
            'Please do not close this window and do not ' +
              'open other folders until this process is completed.'
          );

          try {
            im.lock();
            await im.install();
            outputChannel.appendLine('PlatformIO IDE installed successfully.\n');
            outputChannel.appendLine('Please restart VSCode.');
            const action = 'Reload Now';
            const selected = await vscode.window.showInformationMessage(
              'PlatformIO IDE has been successfully installed! Please reload window',
              action
            );
            if (selected === action) {
              vscode.commands.executeCommand('workbench.action.reloadWindow');
            }
          } catch (err) {
            outputChannel.appendLine('Failed to install PlatformIO IDE.');
            utils.notifyError('Installation Manager', err);
          } finally {
            im.unlock();
          }
        }
        im.destroy();
        return Promise.reject(undefined);
      }
    );
  }

  async startPIOHome() {
    if (
      this.getSetting('disablePIOHomeStartup') ||
      !(await pioNodeHelpers.home.showAtStartup('vscode'))
    ) {
      return;
    }
    vscode.commands.executeCommand('platformio-ide.showHome');
  }

  registerGlobalCommands() {
    this.subscriptions.push(
      vscode.commands.registerCommand('platformio-ide.showHome', startUrl =>
        this.pioHome.toggle(startUrl)
      ),
      vscode.commands.registerCommand('platformio-ide.newTerminal', () =>
        this.pioTerm.new().show()
      ),
      vscode.commands.registerCommand('platformio-ide.openPIOCoreCLI', () =>
        this.pioTerm.sendText('pio --help')
      ),
      vscode.commands.registerCommand('platformio-ide.startDebugging', () => {
        vscode.commands.executeCommand('workbench.view.debug');
        vscode.commands.executeCommand('workbench.debug.action.toggleRepl');
        vscode.commands.executeCommand('workbench.action.debug.start');
      }),
      vscode.commands.registerCommand('platformio-ide.updateGlobalLibs', () =>
        this.pioTerm.sendText('platformio lib --global update')
      ),
      vscode.commands.registerCommand('platformio-ide.updatePlatforms', () =>
        this.pioTerm.sendText('platformio platform update')
      ),
      vscode.commands.registerCommand('platformio-ide.updateCore', () =>
        this.pioTerm.sendText('platformio update')
      ),
      vscode.commands.registerCommand('platformio-ide.upgradeCore', () =>
        this.pioTerm.sendText('platformio upgrade')
      )
    );
  }

  initDebug() {
    piodebug.activate(this.context);
  }

  initToolbar({ filterCommands, ignoreCommands }) {
    if (this.getSetting('disableToolbar')) {
      return;
    }
    [
      ['$(home)', 'PlatformIO: Home', 'platformio-ide.showHome'],
      ['$(check)', 'PlatformIO: Build', 'platformio-ide.build'],
      ['$(arrow-right)', 'PlatformIO: Upload', 'platformio-ide.upload'],
      [
        '$(cloud-upload)',
        'PlatformIO: Upload to remote device',
        'platformio-ide.remote'
      ],
      ['$(trashcan)', 'PlatformIO: Clean', 'platformio-ide.clean'],
      ['$(beaker)', 'PlatformIO: Test', 'platformio-ide.test'],
      ['$(checklist)', 'PlatformIO: Run Task...', 'workbench.action.tasks.runTask'],
      ['$(plug)', 'PlatformIO: Serial Monitor', 'platformio-ide.serialMonitor'],
      ['$(terminal)', 'PlatformIO: New Terminal', 'platformio-ide.newTerminal']
    ]
      .filter(
        item =>
          (!filterCommands || filterCommands.includes(item[2])) &&
          (!ignoreCommands || !ignoreCommands.includes(item[2]))
      )
      .reverse()
      .forEach((item, index) => {
        const [text, tooltip, command] = item;
        const sbItem = vscode.window.createStatusBarItem(
          vscode.StatusBarAlignment.Left,
          10 + index
        );
        sbItem.text = text;
        sbItem.tooltip = tooltip;
        sbItem.command = command;
        sbItem.show();
        this.subscriptions.push(sbItem);
      });
  }

  initProjectIndexer() {
    const observer = new pioNodeHelpers.project.ProjectObserver({
      ide: 'vscode',
      createFileSystemWatcher: vscode.workspace.createFileSystemWatcher,
      createDirSystemWatcher: dir =>
        vscode.workspace.createFileSystemWatcher(path.join(dir, '*')),
      withProgress: task =>
        vscode.window.withProgress(
          {
            location: vscode.ProgressLocation.Window,
            title: 'PlatformIO: IntelliSense Index Rebuild'
          },
          task
        )
    });

    const doUpdate = () => {
      observer.update(
        this.getSetting('autoRebuildAutocompleteIndex') &&
          vscode.workspace.workspaceFolders
          ? vscode.workspace.workspaceFolders.map(folder => folder.uri.fsPath)
          : []
      );
    };

    this.subscriptions.push(
      observer,
      vscode.workspace.onDidChangeWorkspaceFolders(doUpdate.bind(this)),
      vscode.workspace.onDidChangeConfiguration(doUpdate.bind(this)),
      vscode.commands.registerCommand('platformio-ide.rebuildProjectIndex', () => {
        doUpdate(); // re-scan PIO Projects
        observer.rebuildIndex();
      })
    );
    doUpdate();
  }

  handleUseDevelopmentPIOCoreConfiguration() {
    return vscode.workspace.onDidChangeConfiguration(e => {
      if (
        !e.affectsConfiguration('platformio-ide.useDevelopmentPIOCore') ||
        !this.getSetting('useBuiltinPIOCore')
      ) {
        return;
      }
      const envDir = pioNodeHelpers.core.getEnvDir();
      if (!envDir || !fs.isDirectorySync(envDir)) {
        return;
      }
      pioNodeHelpers.home.shutdownServer();
      const delayedJob = () => {
        try {
          fs.removeSync(envDir);
        } catch (err) {
          console.warn(err);
        }
        vscode.window.showInformationMessage(
          'Please restart VSCode to apply the changes.'
        );
      };
      setTimeout(delayedJob, 2000);
    });
  }

  disposeLocalSubscriptions() {
    vscode.commands.executeCommand('setContext', 'pioCoreReady', false);
    pioNodeHelpers.misc.disposeSubscriptions(this.subscriptions);
  }

  deactivate() {
    this.disposeLocalSubscriptions();
  }
}

export const extension = new PlatformIOVSCodeExtension();

export function activate(context) {
  extension.activate(context);
  return extension;
}

export function deactivate() {
  extension.deactivate();
  piodebug.deactivate();
}
<|endoftext|>


<commit_before>// Copyright 2014 Flávio Ribeiro <flavio@bem.tv>.
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIPlugin = require('ui_plugin');
var JST = require('./jst');
var Styler = require('./styler');
var _ = require('underscore');

var Settings = ('./settings');
var ResourceRequester = require('./resource_requester');

class P2PHLS extends UIPlugin {
  get name() { return 'p2phls'; }
  get tagName() { return 'object' }
  get template() { return JST.p2phls }
  get attributes() {
    return {
      'data-p2phls': '',
      'type': 'application/x-shockwave-flash'
    }
  }

  initialize(options) {
    super(options)
    this.src = this.getSource(options.src)
    this.swfPath = "assets/P2PHLSPlayer.swf"
    this.setupBrowser()
    this.createResourceRequester()
    this.highDefinition = false
    this.autoPlay = options.autoPlay
    this.defaultSettings = {left: ["playstop", "volume"], default: [], right: ["fullscreen", "hd"]}
    this.settings = _.extend({}, this.defaultSettings)
    this.addListeners()
  }

  createResourceRequester() {
    var requesterOptions = {currentState: this.getCurrentState.bind(this), swarm: btoa(this.src)}
    this.resourceRequester = new ResourceRequester(requesterOptions)
  }

  getSource(source) {
    return source.replace("p2p+http", "http")
  }

  setupBrowser() {
    this.isChrome = navigator.userAgent.match(/chrome/i)
    this.isFirefox = navigator.userAgent.match(/firefox/i)
  }

  requestResource(url) {
    this.currentUrl = url
    this.resourceRequester.requestResource(url, (chunk, method) => this.resourceLoaded(chunk, method))
  }

  resourceLoaded(chunk, method) {
    if (this.currentUrl) {
      this.currentUrl = null
      this.el.resourceLoaded(chunk)
      this.updateStats(method)
    } else {
      console.log("It seems a deadlock happened with timers on swarm.")
    }
  }

  updateStats(method=null) {
    if (method == "p2p") this.recv_p2p++
    else if (method == "cdn") this.recv_cdn++
    var swarmSize = this.resourceRequester.p2pManager.swarm.size()
    var chunksSent = this.resourceRequester.p2pManager.swarm.chunksSent
    var stats = {chunksFromP2P: this.recv_p2p, chunksFromCDN: this.recv_cdn,
                swarmSize: swarmSize, chunksSent: chunksSent}
    this.triggerStats(stats)
  }

  addListeners() {
    WP3.Mediator.on(this.uniqueId + ':flashready', () => this.bootstrap())
    WP3.Mediator.on(this.uniqueId + ':timeupdate', (params) => this.updateTime(params))
    WP3.Mediator.on(this.uniqueId + ':playbackstate', (state) => this.setPlaybackState(state))
    WP3.Mediator.on(this.uniqueId + ':highdefinition', (isHD) => this.updateHighDefinition(isHD))
    WP3.Mediator.on(this.uniqueId + ':requestresource', (url) => this.requestResource(url))
  }

  stopListening() {
    super()
    WP3.Mediator.off(this.uniqueId + ':flashready')
    WP3.Mediator.off(this.uniqueId + ':timeupdate')
    WP3.Mediator.off(this.uniqueId + ':playbackstate')
    WP3.Mediator.off(this.uniqueId + ':highdefinition')
  }

  hiddenCallback() {
    this.hiddenId = setTimeout(() => this.el.globoPlayerSmoothSetLevel(0), 10000)
  }

  visibleCallback() {
    if (this.hiddenId) {
      clearTimeout(this.hiddenId)
    }
    if (!this.el.globoGetAutoLevel()) {
      this.el.globoPlayerSmoothSetLevel(-1)
    }
  }

  bootstrap() {
    this.el.width = "100%"
    this.el.height = "100%"
    this.trigger('playback:ready', this.name)
    this.currentState = "IDLE"
    this.autoPlay && this.play()
    this.ready = true
    this.el.playerSetminBufferLength(10)
    this.el.playerSetlowBufferLength(Settings.lowBufferLength)
    this.recv_cdn = 0
    this.recv_p2p = 0
    this.updateStats()
    this.triggerStats({status: "on"});
  }

  triggerStats(metrics) {
    this.trigger('playback:p2phlsstats:add', metrics);
  }

  updateHighDefinition(isHD) {
    this.highDefinition = (isHD === "true");
    this.trigger('playback:highdefinitionupdate')
  }

  updateTime(params) {
    var duration, position = params.split(",")
    var previousDvrEnabled = this.dvrEnabled
    this.dvrEnabled = (this.playbackType === 'live' && duration > 240)
    var duration = this.getDuration()
    if (this.playbackType === 'live') {
      if (position >= duration) {
        position = duration
      }
      this.trigger('playback:timeupdate', position, duration, this.name)
    } else {
      this.trigger('playback:timeupdate', this.el.globoGetPosition(), duration, this.name)
    }
    if (this.dvrEnabled != previousDvrEnabled) {
      this.updateSettings()
    }
  }

  play() {
    if (this.el.currentState === 'PAUSED') {
      this.el.globoPlayerResume()
    } else {
      this.firstPlay()
    }
    this.trigger('playback:play', this.name)
  }

  getPlaybackType() {
    return this.playbackType? this.playbackType: null;
  }

  getCurrentBitrate() {
    var currentLevel = this.getLevels()[this.el.globoGetLevel()]
    return currentLevel.bitrate
  }

  getLastProgramDate() {
    var programDate = this.el.globoGetLastProgramDate()
    // normalizing for BRT
    return programDate - 1.08e+7
  }

  isHighDefinition() {
    return this.highDefinition
  }

  getLevels() {
    if (!this.levels || this.levels.length === 0) {
      this.levels = this.el.globoGetLevels()
    }
    return this.levels
  }

  setPlaybackState(state) {
    if (state === "PLAYING_BUFFERING" && this.el.globoGetbufferLength() < 1 && this.currentState !== "PLAYING_BUFFERING")  {
      this.trigger('playback:buffering', this.name)
    } else if (state === "PLAYING" && this.currentState === "PLAYING_BUFFERING") {
      this.trigger('playback:bufferfull', this.name)
    } else if (state === "IDLE") {
      this.trigger('playback:ended', this.name)
      this.trigger('playback:timeupdate', 0, this.el.globoGetDuration(), this.name)
    }
    this.currentState = state;
    this.triggerStats({state: this.currentState, currentBitrate: this.toKB(this.getCurrentBitrate())})
    this.updatePlaybackType()
  }

  updatePlaybackType() {
    if (!this.playbackType) {
      this.playbackType = this.el.globoGetType()
      if (this.playbackType) {
        this.playbackType = this.playbackType.toLowerCase()
        this.updateSettings()
      }
    }
  }

  firstPlay() {
    this.el.globoPlayerLoad(this.src)
    this.el.globoPlayerPlay()
  }

  volume(value) {
    this.el.globoPlayerVolume(value)
  }

  pause() {
    this.el.globoPlayerPause()
  }

  stop() {
    this.el.globoPlayerStop()
    this.trigger('playback:timeupdate', 0, this.name)
  }

  isPlaying() {
    if (this.currentState) {
      return !!(this.currentState.match(/playing/i))
    }
    return false
  }

  getCurrentState() {
    return this.currentState
  }

  getDuration() {
    if (!!this.duration) {
      this.duration = this.el.globoGetDuration()
    }
    return this.duration
  }

  seek(time) {
    if (time < 0) {
      this.el.globoPlayerSeek(time)
    } else {
      var duration = this.getDuration()
      time = duration * time / 100
      // seek operations to a time within 2 seconds from live stream will position playhead back to live
      if (this.playbackType === 'live' && duration - time < 2)
        time = -1
      this.el.globoPlayerSeek(time)
    }
  }

  timeUpdate(time, duration) {
    this.trigger('playback:timeupdate', time, duration, this.name)
  }

  destroy() {
    this.stopListening()
    this.$el.remove()
  }

  setupFirefox() {
    var $el = this.$('embed')
    $el.attr('data-hls', '')
    this.setElement($el[0])
  }

  updateSettings() {
    this.settings = _.extend({}, this.defaultSettings)
    if (this.playbackType === "vod" || this.dvrEnabled) {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.default = ["seekbar"]
    }
    this.trigger('playback:settingsupdate', this.name)
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.$el.html(this.template({cid: this.cid, swfPath: this.swfPath, playbackId: this.uniqueId}))
    this.$el.append(style)
    this.el.id = this.cid
    if(this.isFirefox) { //FIXME remove it from here
      this.setupFirefox()
    }
    return this
  }

  toKB(num) {
    return Math.floor(num/1000)
  }
}

P2PHLS.canPlay = function(resource) {
  return !!(window.webkitRTCPeerConnection || window.mozRTCPeerConnection) && !!resource.match("p2p\\+http:(.*)")
}

module.exports = window.P2PHLS = P2PHLS;
<commit_msg>main: report buffer length<commit_after>// Copyright 2014 Flávio Ribeiro <flavio@bem.tv>.
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIPlugin = require('ui_plugin');
var JST = require('./jst');
var Styler = require('./styler');
var _ = require('underscore');

var Settings = ('./settings');
var ResourceRequester = require('./resource_requester');

class P2PHLS extends UIPlugin {
  get name() { return 'p2phls'; }
  get tagName() { return 'object' }
  get template() { return JST.p2phls }
  get attributes() {
    return {
      'data-p2phls': '',
      'type': 'application/x-shockwave-flash'
    }
  }

  initialize(options) {
    super(options)
    this.src = this.getSource(options.src)
    this.swfPath = "assets/P2PHLSPlayer.swf"
    this.setupBrowser()
    this.createResourceRequester()
    this.highDefinition = false
    this.autoPlay = options.autoPlay
    this.defaultSettings = {left: ["playstop", "volume"], default: [], right: ["fullscreen", "hd"]}
    this.settings = _.extend({}, this.defaultSettings)
    this.addListeners()
  }

  createResourceRequester() {
    var requesterOptions = {currentState: this.getCurrentState.bind(this), swarm: btoa(this.src)}
    this.resourceRequester = new ResourceRequester(requesterOptions)
  }

  getSource(source) {
    return source.replace("p2p+http", "http")
  }

  setupBrowser() {
    this.isChrome = navigator.userAgent.match(/chrome/i)
    this.isFirefox = navigator.userAgent.match(/firefox/i)
  }

  requestResource(url) {
    this.currentUrl = url
    this.resourceRequester.requestResource(url, (chunk, method) => this.resourceLoaded(chunk, method))
  }

  resourceLoaded(chunk, method) {
    if (this.currentUrl) {
      this.currentUrl = null
      this.el.resourceLoaded(chunk)
      this.updateStats(method)
    } else {
      console.log("It seems a deadlock happened with timers on swarm.")
    }
  }

  updateStats(method=null) {
    if (method == "p2p") this.recv_p2p++
    else if (method == "cdn") this.recv_cdn++
    var swarmSize = this.resourceRequester.p2pManager.swarm.size()
    var chunksSent = this.resourceRequester.p2pManager.swarm.chunksSent
    var stats = {chunksFromP2P: this.recv_p2p, chunksFromCDN: this.recv_cdn,
                swarmSize: swarmSize, chunksSent: chunksSent}
    this.triggerStats(stats)
  }

  addListeners() {
    WP3.Mediator.on(this.uniqueId + ':flashready', () => this.bootstrap())
    WP3.Mediator.on(this.uniqueId + ':timeupdate', (params) => this.updateTime(params))
    WP3.Mediator.on(this.uniqueId + ':playbackstate', (state) => this.setPlaybackState(state))
    WP3.Mediator.on(this.uniqueId + ':highdefinition', (isHD) => this.updateHighDefinition(isHD))
    WP3.Mediator.on(this.uniqueId + ':requestresource', (url) => this.requestResource(url))
  }

  stopListening() {
    super()
    WP3.Mediator.off(this.uniqueId + ':flashready')
    WP3.Mediator.off(this.uniqueId + ':timeupdate')
    WP3.Mediator.off(this.uniqueId + ':playbackstate')
    WP3.Mediator.off(this.uniqueId + ':highdefinition')
  }

  hiddenCallback() {
    this.hiddenId = setTimeout(() => this.el.globoPlayerSmoothSetLevel(0), 10000)
  }

  visibleCallback() {
    if (this.hiddenId) {
      clearTimeout(this.hiddenId)
    }
    if (!this.el.globoGetAutoLevel()) {
      this.el.globoPlayerSmoothSetLevel(-1)
    }
  }

  bootstrap() {
    this.el.width = "100%"
    this.el.height = "100%"
    this.trigger('playback:ready', this.name)
    this.currentState = "IDLE"
    this.autoPlay && this.play()
    this.ready = true
    this.el.playerSetminBufferLength(10)
    this.el.playerSetlowBufferLength(Settings.lowBufferLength)
    this.recv_cdn = 0
    this.recv_p2p = 0
    this.updateStats()
    this.triggerStats({status: "on"});
    this.bufferLengthTimer = setInterval(() => this.updateBufferLength(), 500)
  }

  updateBufferLength() {
    this.triggerStats({bufferLength: this.el.globoGetbufferLength()})
  }

  triggerStats(metrics) {
    this.trigger('playback:p2phlsstats:add', metrics);
  }

  updateHighDefinition(isHD) {
    this.highDefinition = (isHD === "true");
    this.trigger('playback:highdefinitionupdate')
  }

  updateTime(params) {
    var duration, position = params.split(",")
    var previousDvrEnabled = this.dvrEnabled
    this.dvrEnabled = (this.playbackType === 'live' && duration > 240)
    var duration = this.getDuration()
    if (this.playbackType === 'live') {
      if (position >= duration) {
        position = duration
      }
      this.trigger('playback:timeupdate', position, duration, this.name)
    } else {
      this.trigger('playback:timeupdate', this.el.globoGetPosition(), duration, this.name)
    }
    if (this.dvrEnabled != previousDvrEnabled) {
      this.updateSettings()
    }
  }

  play() {
    if (this.el.currentState === 'PAUSED') {
      this.el.globoPlayerResume()
    } else {
      this.firstPlay()
    }
    this.trigger('playback:play', this.name)
  }

  getPlaybackType() {
    return this.playbackType? this.playbackType: null;
  }

  getCurrentBitrate() {
    var currentLevel = this.getLevels()[this.el.globoGetLevel()]
    return currentLevel.bitrate
  }

  getLastProgramDate() {
    var programDate = this.el.globoGetLastProgramDate()
    // normalizing for BRT
    return programDate - 1.08e+7
  }

  isHighDefinition() {
    return this.highDefinition
  }

  getLevels() {
    if (!this.levels || this.levels.length === 0) {
      this.levels = this.el.globoGetLevels()
    }
    return this.levels
  }

  setPlaybackState(state) {
    if (state === "PLAYING_BUFFERING" && this.el.globoGetbufferLength() < 1 && this.currentState !== "PLAYING_BUFFERING")  {
      this.trigger('playback:buffering', this.name)
    } else if (state === "PLAYING" && this.currentState === "PLAYING_BUFFERING") {
      this.trigger('playback:bufferfull', this.name)
    } else if (state === "IDLE") {
      this.trigger('playback:ended', this.name)
      this.trigger('playback:timeupdate', 0, this.el.globoGetDuration(), this.name)
    }
    this.currentState = state;
    this.triggerStats({state: this.currentState, currentBitrate: this.toKB(this.getCurrentBitrate())})
    this.updatePlaybackType()
  }

  updatePlaybackType() {
    if (!this.playbackType) {
      this.playbackType = this.el.globoGetType()
      if (this.playbackType) {
        this.playbackType = this.playbackType.toLowerCase()
        this.updateSettings()
      }
    }
  }

  firstPlay() {
    this.el.globoPlayerLoad(this.src)
    this.el.globoPlayerPlay()
  }

  volume(value) {
    this.el.globoPlayerVolume(value)
  }

  pause() {
    this.el.globoPlayerPause()
  }

  stop() {
    this.el.globoPlayerStop()
    this.trigger('playback:timeupdate', 0, this.name)
  }

  isPlaying() {
    if (this.currentState) {
      return !!(this.currentState.match(/playing/i))
    }
    return false
  }

  getCurrentState() {
    return this.currentState
  }

  getDuration() {
    if (!!this.duration) {
      this.duration = this.el.globoGetDuration()
    }
    return this.duration
  }

  seek(time) {
    if (time < 0) {
      this.el.globoPlayerSeek(time)
    } else {
      var duration = this.getDuration()
      time = duration * time / 100
      // seek operations to a time within 2 seconds from live stream will position playhead back to live
      if (this.playbackType === 'live' && duration - time < 2)
        time = -1
      this.el.globoPlayerSeek(time)
    }
  }

  timeUpdate(time, duration) {
    this.trigger('playback:timeupdate', time, duration, this.name)
  }

  destroy() {
    this.stopListening()
    this.$el.remove()
  }

  setupFirefox() {
    var $el = this.$('embed')
    $el.attr('data-hls', '')
    this.setElement($el[0])
  }

  updateSettings() {
    this.settings = _.extend({}, this.defaultSettings)
    if (this.playbackType === "vod" || this.dvrEnabled) {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.default = ["seekbar"]
    }
    this.trigger('playback:settingsupdate', this.name)
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.$el.html(this.template({cid: this.cid, swfPath: this.swfPath, playbackId: this.uniqueId}))
    this.$el.append(style)
    this.el.id = this.cid
    if(this.isFirefox) { //FIXME remove it from here
      this.setupFirefox()
    }
    return this
  }

  toKB(num) {
    return Math.floor(num/1000)
  }
}

P2PHLS.canPlay = function(resource) {
  return !!(window.webkitRTCPeerConnection || window.mozRTCPeerConnection) && !!resource.match("p2p\\+http:(.*)")
}

module.exports = window.P2PHLS = P2PHLS;
<|endoftext|>