Scrimp
= {}
default_request = ->
request = service: (service for service of Scrimp.services)[0] protocol: (protocol for protocol of Scrimp.protocols)[0] host: "localhost" port: 9000 args: {} request.function = (func for func of Scrimp.services[request.service])[0] request
load_services = (data) ->
Scrimp.services = data for service, functions of Scrimp.services option = $('<option>').val(service).text(service) $('select.service-field').append(option)
load_structs = (data) ->
Scrimp.structs = data
load_protocols = (data) ->
Scrimp.protocols = data for protocol of Scrimp.protocols option = $('<option>').val(protocol).text(protocol) $('select.protocol-field').append(option)
service_changed = ->
$('select.function-field').empty() service = Scrimp.services[$('select.service-field').val()] if service for func, desc of Scrimp.services[$('select.service-field').val()] option = $('<option>').val(func).text(func) $('select.function-field').append(option) function_changed()
type_info = (info) ->
$type = $('<span>').addClass('type-info') if info.type == 'STRUCT' $type.text(info.class) else $type.text(info.type)
build_input = (info, value) ->
switch info.type when "BOOL" $input = $('<input type="checkbox">').addClass('bool-field') if info.default != undefined then $input.prop('checked', info.default) if value != undefined then $input.prop('checked', value) when "DOUBLE" $input = $('<input type="text">').addClass('double-field') if info.default != undefined then $input.val(info.default) if value != undefined then $input.val(value) when "BYTE", "I16", "I32", "I64" if info.enum $input = $('<select>').addClass('enum-field') for constval, name of info.enum $input.append $('<option>').val(name).text('' + constval + ' = ' + name) if info.default != undefined then $input.val(info.enum[info.default]) if value != undefined if isNaN(value) $input.val(value) else $input.val(info.enum[value]) else $input = $('<input type="text">').addClass('int-field') if info.default != undefined then $input.val(info.default) if value != undefined then $input.val(value) when "STRING" $input = $('<input type="text">').addClass('string-field') if info.default != undefined then $input.val(info.default) if value != undefined then $input.val(value) when "STRUCT" # TODO defaults $input = $('<ul>').addClass('struct-field') populate_struct $input, Scrimp.structs[info.class], value when "LIST", "SET" # TODO defaults $input = $('<ul>').addClass('list-field') add_element = (element) -> $li = $('<li>').addClass('list-field-element') $del = $('<a>').attr('href', '#').addClass('del').text('del').click -> $li.remove() $li.append($del) $li.append(type_info(info.element)) $li.append(build_input(info.element, element)) $input.children('li').last().before($li) $add = $('<a>').attr('href', '#').addClass('add').text('add').click -> add_element(element) $input.append($('<li>').append($add)) if value for element in value add_element(element) when "MAP" # TODO defaults $input = $('<ul>').addClass('map-field') add_kv = (key, value) -> $li = $('<li>').addClass('map-field-entry') $del = $('<a>').attr('href', '#').addClass('del').text('del').click -> $li.remove() $li.append($del) $key = $('<div>').addClass('map-field-key') $key.append($('<label>').addClass('map-field-label').text('key')) $key.append(type_info(info.key)) $key.append(build_input(info.key, key)) $li.append($key) $val = $('<div>').addClass('map-field-value') $val.append($('<label>').addClass('map-field-label').text('val')) $val.append(type_info(info.value)) $val.append(build_input(info.value, value)) $li.append($val) $input.children('li').last().before($li) $add = $('<a>').attr('href', '#').addClass('add').text('add').click -> add_kv(undefined, undefined) $input.append($('<li>').append($add)) if value for pair in value add_kv(pair[0], pair[1]) $input.addClass('request-field')
populate_struct = ($struct, fields, values) ->
if !values then values = {} for name, info of fields value = values[name] $include = $('<input type="checkbox">').addClass('include-field').prop('checked', value != undefined) $type = type_info(info) $label = $('<label>').addClass('struct-value').text(name) $input = build_input info, value $li = $('<li>').addClass('struct-field-entry') if info.optional then $li.append($include) $struct.append $li.append($label).append($type).append($input)
function_changed = ->
$('.args-field').empty() populate_struct $('.args-field'), Scrimp.services[$('select.service-field').val()][$('select.function-field').val()].args, Scrimp.last_json.args
load_structured_request = ->
try Scrimp.last_json = parsed = JSON.parse($('.request-json').val()) catch ex return confirm("Invalid JSON; changes will be lost!") if not (parsed.service of Scrimp.services) return confirm("Invalid service; changes will be lost!") if not (parsed.function of Scrimp.services[parsed.service]) return confirm("Invalid function; changes will be lost!") $('select.service-field').val(parsed.service) service_changed() $('select.function-field').val(parsed.function) function_changed() $('select.protocol-field').val(parsed.protocol) $('input.host-field').val(parsed.host) $('input.port-field').val(parsed.port) true
build_json_for_field = ($el) ->
if $el.hasClass('struct-field') json = {} $el.children('li').each (_, li) -> $li = $(li) $include = $li.children('.include-field') if !$include.size() || $include.prop('checked') json[$li.children('label.struct-value').text()] = build_json_for_field($li.children('.request-field')) null else if $el.hasClass('bool-field') json = (if $el.prop('checked') then true else false) else if $el.hasClass('double-field') json = parseFloat($el.val()) else if $el.hasClass('int-field') json = parseInt($el.val()) else if $el.hasClass('string-field') || $el.hasClass('enum-field') json = $el.val() else if $el.hasClass('list-field') json = [] $el.children('.list-field-element').each (_, li) -> $li = $(li) json.push(build_json_for_field($li.children('.request-field'))) else if $el.hasClass('map-field') json = [] $el.children('.map-field-entry').each (_, li) -> $li = $(li) json.push([build_json_for_field($li.children('.map-field-key').children('.request-field')), build_json_for_field($li.children('.map-field-value').children('.request-field'))]) json
build_raw_request = ->
request = service: $('select.service-field').val() function: $('select.function-field').val() protocol: $('select.protocol-field').val() host: $('input.host-field').val() port: $('input.port-field').val() args: build_json_for_field($('.args-field')) request
load_raw_request = ->
request = build_raw_request() $('.request-json').val(JSON.stringify(request, null, 2))
build_response_element = (value, info) ->
switch info.type when "BOOL" $('<span>').addClass('value-bool').text(value ? "true" : "false") when "BYTE", "I16", "I32", "I64", "DOUBLE" if info.enum # totally untested $constval = null for constval, name of info.enum if name == value $constval = $('<span>').addClass('value-enum-const').text(constval) $name = $('<span>').addClass('value-enum-name').text(value) $('<span>').addClass('value-enum').append($constval).append(' = ').append($name) else $('<span>').addClass('value-number').text(value) when "STRING" $('<span>').addClass('value-string').text(value) when "STRUCT" $ul = $('<ul>').addClass('value-struct') for name, content of value $li = $('<li>').addClass('value-struct-entry') $name = $('<span>').addClass('value-struct-entry-name').text(name) $li.append $name $li.append build_response_element(content, Scrimp.structs[info.class][name]) $ul.append $li $ul when "LIST", "SET" $ul = $('<ul>').addClass('value-list') for element in value $li = $('<li>').addClass('value-list-element') $li.append build_response_element(element, info.element) $ul.append $li $ul when "MAP" $ul = $('<ul>').addClass('value-map') for pair in value $li = $('<li>').addClass('value-map-entry') $key = $('<div>').addClass('value-map-key').append($('<span>').addClass('map-field-label').text('key')) $key.append build_response_element(pair[0], info.key) $li.append $key $value = $('<div>').addClass('value-map-value').append($('<span>').addClass('map-field-label').text('val')) $value.append build_response_element(pair[1], info.value) $li.append $value $ul.append $li $ul when "VOID" $('<span>').addClass('value-void').text('VOID (note: for oneway methods, success merely indicates the message was sent; it may not have been received or recognized)')
populate_structured_response = (request, response) ->
$details = $('.response-details') $details.empty() if response.return != undefined $('.response-error').hide() $('.response-success').show() $details.append build_response_element(response.return, Scrimp.services[request.service][request.function].returns) else $('.response-success').hide() for err, details of response # there's only one. this is awkward $('.response-error').text(err) if err == 'Thrift::ApplicationException' $details.append($('<p>').text(details.type)) $details.append($('<pre>').text(details.message)) else $detailsList = $('<dl>') for field, value of details $detailsList.append($('<dt>').text(field)) $detailsList.append($('<dd>').text(value)) $details.append($detailsList) $('.response-error').show()
$ ->
$.ajax success: load_services url: '/services' async: false # yeah yeah it's silly get over it $.ajax success: load_structs url: '/structs' async: false $.ajax success: load_protocols url: '/protocols' async: false $('select.service-field').change(service_changed) $('select.function-field').change(function_changed) $('.request-json').val(JSON.stringify(default_request(), null, 2)) $('.show-raw-request').click -> load_raw_request() $('.structured-request').hide() $('.raw-request').show() $('.show-structured-request').click -> if load_structured_request() $('.raw-request').hide() $('.structured-request').show() $('.show-structured-request').show() $('.invoke').click -> if $('.raw-request:hidden').size() load_raw_request() request = $('.request-json').val() $.post $('.request-form').attr('action'), request, (data) -> populate_structured_response JSON.parse(request), data $('.response-json').text(JSON.stringify(data, null, 2)) $('.response').show() false $('.show-raw-response').click -> $('.structured-response').hide() $('.raw-response').show() $('.show-structured-response').click -> $('.raw-response').hide() $('.structured-response').show() $('.show-structured-request').click()