Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jlukic committed Feb 17, 2017
1 parent ff74688 commit b175252
Show file tree
Hide file tree
Showing 3 changed files with 335 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Meteor Reload.sublime-keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"caption": "Meteor Reload: Sync File",
"command": "meteor_reload"
}
]
27 changes: 27 additions & 0 deletions Meteor Reload.sublime-settings
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
// Whether data should be transmitted when file is modified
"reload_on_modified": true,

// The amount of time in MS to debounce when using reload_on_modified
"reload_debounce": 300,

// The hostname for the machine that you are using
"hostname": "localhost",

// The port your meteor server is running
"port": 3000,

// The name of the server endpoint
"endpoint" : "/reval",

// Path to the root of the meteor server (windows be sure to escape backslashes, i.e. "C:\\My\\Project")
"path": "",

// Only files matching this local path will sync (windows paths require escaped backslashes)
// This can include partial paths, for example '/app', will match '/my/special/app'
"required_path": "",

// Only files matching this regex will be required (used to specify file types or other conditions)
"required_regex": "\\.(html|less|css|js)$",

}
302 changes: 302 additions & 0 deletions MeteorReload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
import sublime
import functools
import sublime_plugin
import urllib.request
import re


settings = sublime.load_settings("Meteor Reload.sublime-settings")

class meteorReload(sublime_plugin.EventListener):
pending = 0

def handleTimeout(self, view):
self.pending = self.pending - 1
if self.pending == 0:
view.run_command("meteor_reload")

def on_modified_async(self, view):
if settings.get('reload_on_modified') is True:
required_path = settings.get('required_path')
required_regex = settings.get('required_regex')
file_path = view.file_name()
if (file_path and file_path.find(required_path) >= 0 and re.search(required_regex, file_path)):
self.pending = self.pending + 1
sublime.set_timeout(functools.partial(self.handleTimeout, view), settings.get('reload_debounce'))

class meteorReloadCommand(sublime_plugin.TextCommand):
def run(self, view):
if (self.view.file_name()):
path = settings.get('path')
file_path = self.view.file_name().replace(path, '')
hostname = settings.get('hostname')
port = settings.get('port')
endpoint = settings.get('endpoint')
url = 'http://' + hostname + ':' + str(port) + endpoint + '?filePath=' + file_path
print (url)
data = self.view.substr(sublime.Region(0, self.view.size()))
request = HttpAsyncRequest(url)
request.set_content(str.encode(data))
request.set_header('Content-type', 'text/plain')
request.send()

# Library for doing async HTTP (threading yeah!)

_user_agent = "qualia"

import threading as _threading
_is_old = 3 / 2 == 1 # Yeah, I'm sure there's a better way. Deal with it.
if _is_old:
import urllib as _urllib
import urllib2 as _urllib2
import urlparse as _urlparse
else:
import urllib as _urllib
import urllib.parse as _urllib_parse
import urllib.request as _urllib_request

def _parse_url(url):
return _urlparse.urlparse(url)

def set_user_agent(value):
global _user_agent
_user_agent = value

def decode_url_value(value):
if _is_old:
return _urllib.unquote(value).decode('utf8')
else:
return _urllib_parse.unquote(value)

def encode_url_value(value):
if _is_old:
return _urllib2.quote(value.encode('utf8'))
else:
return _urllib_parse.quote(value)

def _send_impl(req_obj, method, url, headers, content):
if _is_old:
opener = _urllib2.build_opener(_urllib2.HTTPHandler)
if content == None:
request = _urllib2.Request(url)
else:
request = _urllib2.Request(url, data=content)
else:
opener = _urllib_request.build_opener(_urllib_request.HTTPHandler)
if content == None:
request = _urllib_request.Request(url)
else:
request = _urllib_request.Request(url, data=content)
for header in headers:
request.add_header(header[0], header[1])
request.get_method = lambda:method
output = opener.open(request)
content = output.read()
headers = {}
for header_key in output.headers.keys():
headers[header_key] = output.headers[header_key]
response_message = output.msg
response_code = output.code
req_obj._set_result(response_code, response_message, content, headers)

class HttpAsyncRequest:
def __init__(self, url):
bad_format = False
try:
if _is_old:
url_parts = _parse_url(url)
else:
url_parts = _urllib_parse.urlparse(url)
if url_parts.scheme == '' or url_parts.netloc == '':
bad_format = True
except:
bad_format = True
if bad_format:
raise Exception("Bad URL! Bad!")

self.mutex = _threading.Lock()
self.method = 'GET'
self.scheme = url_parts.scheme
self.host = url_parts.hostname
self.port = url_parts.port
self.path = url_parts.path
self.fragment = url_parts.fragment
self.params = url_parts.params
self.original_query = url_parts.query # use this if query params are not modified
self.query = None # if modified, clear original_query and populate this with a dictionary lookup
self.header_formatting = {} # preserves the formatting of the header key
self.header_values = {} # canonical key of header with list of values of that header
self.content = None
self.set_header('User-Agent', _user_agent)
self.done = False
self.response_code = -1
self.response_message = None
self.response_content = None
self.response_headers_values = None
self.response_headers_formatting = None

def send(self):
url = self.scheme + '://' + self.host

if self.port != None:
url += ':' + str(self.port)

if self.path != None and self.path != '':
if self.path[0] != '/':
self.path = '/' + self.path
url += self.path

if self.params != None and self.params != '':
url += ';' + self.params

if self.query == None:
if self.original_query != '':
url += '?' + self.original_query
else:
queries = []
keys = self.query.keys()[:]
keys.sort() # deterministic requests
for key in keys:
e_key = encode_url_value(key)
for value in self.query[key]:
e_value = encode_url_value(value)
queries.append(e_key + '=' + e_value)
url += '?' + '&'.join(queries)

if self.fragment != '':
url += '#' + self.fragment

headers = []
keys = list(self.header_formatting.keys())
keys.sort()
for key in keys:
f_key = self.header_formatting[key]
for value in self.header_values[key]:
headers.append((f_key, value))


thread = _threading.Thread(target = _send_impl, args = (self, self.method, url, headers, self.content))
thread.daemon = True
thread.start()

def _set_result(self, code, message, content, headers):
self.mutex.acquire()
try:
self.response_code = code
self.response_message = message
self.response_content = content
self.response_headers_values = {}
self.response_headers_formatting = {}
for key in headers.keys():
ckey = key.lower()
self.response_headers_values[ckey] = headers[key]
self.response_headers_formatting[ckey] = key
finally:
self.mutex.release()

def is_complete(self):
self.mutex.acquire()
try:
return self.response_code != -1
finally:
self.mutex.release()

def _ensure_request_complete(self):
if not self.is_complete():
raise Exception("Cannot access response until request is complete.")

def get_response_code(self):
self._ensure_request_complete()
return self.response_code

def get_response_message(self):
self._ensure_request_complete()
return self.response_message

def get_response_header_names(self):
self._ensure_request_complete()
output = list(self.response_headers_formatting.values())
output.sort()
return output

def get_response_header(self, name):
self._ensure_request_complete()
return self.response_headers_values.get(name.lower(), None)

def get_response_content(self, mode='t'):
self._ensure_request_complete()
output = self.response_content
if mode == 't':
return output.decode('utf-8')
else:
return output


def set_header(self, key, value):
self.header_formatting[key.lower()] = key
self.header_values[key.lower()] = [value]

def add_header(self, key, value):
canonical_key = key.lower()
existing_headers = self.header_values.get(canonical_key, None)
if existing_headers == None:
self.set_header(key, value)
else:
existing_headers.append(value)

def clear_header(self, key):
canonical_key = key.lower()
if self.header_values.get(canonical_key, None) != None:
self.header_values.pop(canonical_key)
self.header_formatting.pop(canonical_key)

def set_method(self, method):
self.method = method

def set_content(self, content):
self.content = content

def _init_query(self):
if self.query == None:
query = [] if self.original_query != '' else self.original_query.split('&')
lookup_values = {}
for item in query:
parts = item.split('=')
if len(parts) >= 2:
item_key = decode_url_value(parts[0])
item_value = decode_url_value('='.join(parts[1:]))
existing_values = lookup_values.get(item_key, None)
if existing_values == None:
existing_values = []
lookup_values[item_key] = existing_values
existing_values.append(item_value)
self.query = lookup_values

def set_query(self, key, value):
self._init_query()
self.query[key] = [value]

def add_query(self, key, value):
self._init_query()
values = self.query.get(key, None)
if values != None:
values.append(value)
else:
self.query[key] = [value]

def clear_query(self, key):
self._init_query()
if self.query.get(key, None) != None:
self.query.pop(key)

def set_port(self, port):
self.port = port

def set_fragment(self, fragment):
self.fragment = fragment

def clear_fragment(self):
self.fragment = None

def set_scehem(self, scheme):
self.scheme = scheme

0 comments on commit b175252

Please sign in to comment.