<commit_before>fs = require 'fs-plus'
_ = require 'underscore-plus'
shell = require 'shell'
_path = require 'path'
convert = require './util/path-converter'
onmessage= require './onmessage'
AtomHelper = require './atom-helper'
FileSystemNode = require './file-system-node'
ShellAdapter = require './adapters/shell-adapter'
FSAdapter = require './adapters/fs-adapter'
SingleSocket = require 'single-socket'

require('dotenv').config
  path: _path.join(__dirname, '..', '.env'),
  silent: true

WS_SERVER_URL = (->
  config = _.defaults
    host: process.env['IDE_WS_HOST']
    port: process.env['IDE_WS_PORT']
    path: process.env['IDE_WS_PATH']
  ,
    host: 'ile.learn.co',
    port: 443,
    path: 'go_fs_server'
    protocol: 'wss'

  if config.port isnt 443
    config.protocol = 'ws'

  {protocol, host, port, path} = config

  "#{protocol}://#{host}:#{port}/#{path}"
)()

class VirtualFileSystem
  constructor: ->
    @atomHelper = new AtomHelper(this)
    @fs = new FSAdapter(this)
    @shell = new ShellAdapter(this)
    @projectNode = new FileSystemNode({})

    @setLocalPaths()

    @connect()
    @addOpener()

  setLocalPaths: ->
    @localRoot = _path.join(@atomHelper.configPath(), '.learn-ide')
    convert.configure({@localRoot})

    @logDirectory = _path.join(@localRoot, 'var', 'log')
    @receivedLog = _path.join(@logDirectory, 'received')
    @sentLog = _path.join(@logDirectory, 'sent')

    @cacheDirectory = _path.join(@localRoot, 'var', 'cache')
    @cachedProjectNode = _path.join(@cacheDirectory, 'project-node')

    fs.makeTreeSync(@logDirectory)
    fs.makeTreeSync(@cacheDirectory)

  connect: ->
    @websocket = new WebSocket "#{WS_SERVER_URL}?token=#{@atomHelper.token()}"

    @websocket.onopen = =>
      @activate()
      @init()

    @websocket.onmessage = (event) =>
      onmessage(event, this)

    @websocket.onerror = (err) =>
      console.error 'ERROR:', err
      @atomHelper.cannotConnect()

    @websocket.onclose = (event) =>
      console.log 'CLOSED:', event
      @atomHelper.disconnected()

  addOpener: ->
    @atomHelper.addOpener (uri) =>
      fs.stat uri, (err, stats) =>
        if err? and @hasPath(uri)
          @open(uri)

  serialize: ->
    @projectNode.serialize()

  cache: ->
    data = JSON.stringify(@serialize())
    fs.writeFile(@cachedProjectNode, data)

  setActivationState: (activationState) ->
    @activationState = activationState

  setProjectNode: (serializedNode, fromCache) ->
    @projectNode = new FileSystemNode(serializedNode)
    expansion = @activationState?.directoryExpansionStates

    @atomHelper.updateProject(@projectNode.localPath(), expansion)

    if fromCache
      return not @projectNode.path? and @atomHelper.loading()

    @sync(@projectNode.path)
    @activationState = undefined

  activate: ->
    fs.readFile @cachedProjectNode, (err, data) =>
      if err?
        console.error 'Unable to load cached project node:', err
        return @atomHelper.loading()

      try
        serializedNode = JSON.parse(data)
      catch error
        console.error 'Unable to parse cached project node:', error
        return @atomHelper.loading()

      @setProjectNode(serializedNode, true)

  expansionState: ->
    @activationState?.directoryExpansionStates

  send: (msg) ->
    convertedMsg = {}

    for own key, value of msg
      if typeof value is 'string' and value.startsWith(@localRoot)
        convertedMsg[key] = convert.localToRemote(value)
      else
        convertedMsg[key] = value<commit_msg>Only cache if project node exists<commit_after>fs = require 'fs-plus'
_ = require 'underscore-plus'
shell = require 'shell'
_path = require 'path'
convert = require './util/path-converter'
onmessage= require './onmessage'
AtomHelper = require './atom-helper'
FileSystemNode = require './file-system-node'
ShellAdapter = require './adapters/shell-adapter'
FSAdapter = require './adapters/fs-adapter'
SingleSocket = require 'single-socket'

require('dotenv').config
  path: _path.join(__dirname, '..', '.env'),
  silent: true

WS_SERVER_URL = (->
  config = _.defaults
    host: process.env['IDE_WS_HOST']
    port: process.env['IDE_WS_PORT']
    path: process.env['IDE_WS_PATH']
  ,
    host: 'ile.learn.co',
    port: 443,
    path: 'go_fs_server'
    protocol: 'wss'

  if config.port isnt 443
    config.protocol = 'ws'

  {protocol, host, port, path} = config

  "#{protocol}://#{host}:#{port}/#{path}"
)()

class VirtualFileSystem
  constructor: ->
    @atomHelper = new AtomHelper(this)
    @fs = new FSAdapter(this)
    @shell = new ShellAdapter(this)
    @projectNode = new FileSystemNode({})

    @setLocalPaths()

    @connect()
    @addOpener()

  setLocalPaths: ->
    @localRoot = _path.join(@atomHelper.configPath(), '.learn-ide')
    convert.configure({@localRoot})

    @logDirectory = _path.join(@localRoot, 'var', 'log')
    @receivedLog = _path.join(@logDirectory, 'received')
    @sentLog = _path.join(@logDirectory, 'sent')

    @cacheDirectory = _path.join(@localRoot, 'var', 'cache')
    @cachedProjectNode = _path.join(@cacheDirectory, 'project-node')

    fs.makeTreeSync(@logDirectory)
    fs.makeTreeSync(@cacheDirectory)

  connect: ->
    @websocket = new WebSocket "#{WS_SERVER_URL}?token=#{@atomHelper.token()}"

    @websocket.onopen = =>
      @activate()
      @init()

    @websocket.onmessage = (event) =>
      onmessage(event, this)

    @websocket.onerror = (err) =>
      console.error 'ERROR:', err
      @atomHelper.cannotConnect()

    @websocket.onclose = (event) =>
      console.log 'CLOSED:', event
      @atomHelper.disconnected()

  addOpener: ->
    @atomHelper.addOpener (uri) =>
      fs.stat uri, (err, stats) =>
        if err? and @hasPath(uri)
          @open(uri)

  serialize: ->
    @projectNode.serialize()

  cache: ->
    serializedNode = @serialize()

    if serializedNode.path?
      data = JSON.stringify(serializedNode)
      fs.writeFile(@cachedProjectNode, data)

  setActivationState: (activationState) ->
    @activationState = activationState

  setProjectNodeFromCache: (serializedNode) ->
    return if @projectNode.path?

    @projectNode = new FileSystemNode(serializedNode)
    expansion = @activationState?.directoryExpansionStates

    @atomHelper.updateProject(@projectNode.localPath(), expansion)

  setProjectNode: (serializedNode) ->
    @projectNode = new FileSystemNode(serializedNode)
    expansion = @activationState?.directoryExpansionStates
    @activationState = undefined

    @atomHelper.updateProject(@projectNode.localPath(), expansion)
    @sync(@projectNode.path)

  activate: ->
    fs.readFile @cachedProjectNode, (err, data) =>
      if err?
        console.error 'Unable to load cached project node:', err
        return @atomHelper.loading()

      try
        serializedNode = JSON.parse(data)
      catch error
        console.error 'Unable to parse cached project node:', error
        return @atomHelper.loading()

      @setProjectNodeFromCache(serializedNode)

  expansionState: ->
    @activationState?.directoryExpansionStates

  send: (msg) ->
    convertedMsg = {}

    for own key, value of msg
      if typeof value is 'string' and value.startsWith(@localRoot)
        convertedMsg[key] = convert.localToRemote(value)
      else
        convertedMsg[key] = value
{'fraction_non_alphanumeric': 0.13822923816060398, 'fraction_numerical': 0.0016472203157172271, 'mean_word_length': 3.4617268830373544, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1533495', 'n_tokens_mistral': 2320, 'n_tokens_neox': 2233, 'n_words': 477}