Switch branches/tags
v1.1 v1.0 deploy-production-2014-11-24-131637 deploy-production-2014-09-26-170709 deploy-production-2014-09-12-174308 deploy-production-2014-07-29-115314 deploy-production-2014-07-28-141144 deploy-production-2014-07-24-155854 deploy-production-2014-07-24-153730 deploy-production-2014-07-09-152824 deploy-production-2014-07-07-112318 deploy-production-2014-06-26-085130 deploy-production-2014-06-18-095115 deploy-production-2014-06-10-162455 deploy-production-2014-06-08-223808 deploy-production-2014-06-08-204644 deploy-production-2014-06-08-173620 deploy-production-2014-06-08-152724 deploy-production-2014-06-07-224935 deploy-production-2014-06-07-085527 deploy-beta-2014-11-24-130502 deploy-beta-2014-09-26-164357 deploy-beta-2014-09-17-175800 deploy-beta-2014-09-16-112256 deploy-beta-2014-09-12-152930 deploy-beta-2014-07-29-115057 deploy-beta-2014-07-28-141039 deploy-beta-2014-07-24-155808 deploy-beta-2014-07-24-133704 deploy-beta-2014-07-23-124036 deploy-beta-2014-07-22-184425 deploy-beta-2014-07-22-184049 deploy-beta-2014-07-21-123414 deploy-beta-2014-07-21-121121 deploy-beta-2014-07-19-201439 deploy-beta-2014-07-09-173712 deploy-beta-2014-07-08-113852 deploy-beta-2014-07-08-111618 deploy-beta-2014-06-30-171011 deploy-beta-2014-06-30-120154 deploy-beta-2014-06-29-164515 deploy-beta-2014-06-28-095723 deploy-beta-2014-06-26-084022 deploy-beta-2014-06-25-172012 deploy-beta-2014-06-25-164239 deploy-beta-2014-06-25-163055 deploy-beta-2014-06-15-112432 deploy-beta-2014-06-15-103921 deploy-beta-2014-06-13-154941 deploy-beta-2014-06-12-123655 deploy-beta-2014-06-10-170747 deploy-beta-2014-06-10-170615 deploy-beta-2014-06-10-100855 deploy-beta-2014-06-10-093341 deploy-beta-2014-06-08-223610 deploy-beta-2014-06-08-204537 deploy-beta-2014-06-08-173607 deploy-beta-2014-06-08-151042 deploy-beta-2014-06-08-143017 deploy-beta-2014-06-08-105057 deploy-beta-2014-06-07-224811 deploy-beta-2014-06-07-085738 deploy-alpha-2014-11-26-140815 deploy-alpha-2014-11-24-130358 deploy-alpha-2014-11-11-154612 deploy-alpha-2014-10-20-141323 deploy-alpha-2014-09-26-163913 deploy-alpha-2014-09-15-174056 deploy-alpha-2014-09-12-173235 deploy-alpha-2014-09-12-152313 deploy-alpha-2014-09-04-123408 deploy-alpha-2014-09-04-111256 deploy-alpha-2014-09-04-110523 deploy-alpha-2014-09-02-203805 deploy-alpha-2014-09-02-203616 deploy-alpha-2014-08-29-150456 deploy-alpha-2014-08-28-183753 deploy-alpha-2014-08-18-112606 deploy-alpha-2014-08-18-104803 deploy-alpha-2014-08-11-101035 deploy-alpha-2014-08-01-154714 deploy-alpha-2014-08-01-145001 deploy-alpha-2014-08-01-143719 deploy-alpha-2014-07-29-114600 deploy-alpha-2014-07-28-150800 deploy-alpha-2014-07-28-140929 deploy-alpha-2014-07-24-155715 deploy-alpha-2014-07-24-133602 deploy-alpha-2014-07-24-133237 deploy-alpha-2014-07-23-123833 deploy-alpha-2014-07-22-163841 deploy-alpha-2014-07-21-172936 deploy-alpha-2014-07-21-163251 deploy-alpha-2014-07-21-123225 deploy-alpha-2014-07-21-120934 deploy-alpha-2014-07-19-201349 deploy-alpha-2014-07-09-173748 deploy-alpha-2014-07-08-113807 deploy-alpha-2014-07-08-111545 deploy-alpha-2014-07-07-111323
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
375 lines (304 sloc) 10.4 KB
apiKey = "eb34bd67.megadroneshare"
# A deep merge of two objects (as opposed to the shallow merge from angular.extend)
merge = (obj1, obj2) ->
result = {} # (kinda non ideomatic, but oh well)
for k, v of obj1
newv = if (k of obj2) && (typeof v == "object")
merge(v, obj2[k]) # if an object merge
result[k] = newv
for k, v of obj2 # add missing keys
if !(k of result)
result[k] = v
atmosphereOptions =
contentType : 'application/json'
transport : 'websocket'
connectTimeout : 10000 # 10s timeout before fallback to streaming
reconnectInterval : 30000
enableXDR: true
timeout : 60000
pollingInterval : 5000
fallbackTransport: 'long-polling' # Server might has issues with 'long-polling'
api_key: apiKey
#onError: (resp) =>
# @log.error("Atmosphere error: #{resp}")
#onTransportFailure: (msg, resp) =>
# @log.error("Transport failure #{msg} #{resp}")
#onOpen: (resp) =>
#"Got open response #{resp.status}")
class DapiService
@$inject: ['$log', '$http', '$routeParams']
constructor: (@log, @http, routeParams) ->
useLocalServer = routeParams.local ? false
#useLocalServer = true
base = if useLocalServer
# Normally is recommended, but if you'd like cookies used for your application's login info
# you can create a CNAME under your domain that points to and reference the CNAME here.
path = '/api/v1/'
@apiBase = base + path
@log.debug("Creating service " + @urlBase())
# If set, this string is the human friendly error message about our last server error
@error = null
@config =
withCredentials: true # Needed to send cookies
useXDomain: true # needed to send cookies in POST
# FIXME - better to include in an auth header per RFC2617 Authorization: DroneApi apikey="blah.blah"
# api_key: "userkey.appkey"
Authorization: 'DroneApi apikey="' + apiKey + '"'
urlBase: ->
@apiBase + @endpoint
getError: =>
class RESTService extends DapiService
get: (params = {}) ->
@log.debug("Getting from #{@endpoint}")
cfg =
params: params
angular.extend(cfg, @config)
@http.get(@urlBase(), cfg).then (results) ->
# Return a URL that points to the specified ID
urlId: (id) ->
# Async read the specified ID
getId: (id) ->
@log.debug("Getting #{@endpoint}/#{id}")
c = angular.extend({}, @config)
@http.get(@urlId(id), c)
.then (results) ->
putId: (id, obj, c) =>
@log.debug("Saving #{@endpoint}/#{id}")
c = angular.extend(c ? {}, @config)
@http.put("#{@urlBase()}/#{id}", obj, c)
postId: (id, obj, c) =>
@log.debug("Posting to #{@endpoint}/#{id}")
c = merge(c ? {}, @config)"#{@urlBase()}/#{id}", obj, c)
delete: (id, c) =>
@log.debug("Deleting #{@endpoint}/#{id}")
c = angular.extend(c ? {}, @config)
@http.delete("#{@urlBase()}/#{id}", c)
# Dynamically create a new record
append: (obj, c) =>
@log.debug("Appending to #{@endpoint}")
c = angular.extend(c ? {}, @config)
@http.put("#{@urlBase()}", obj, c)
class AuthService extends RESTService
@$inject: ['$log', '$http', '$routeParams']
constructor: (log, http, routeParams) ->
super(log, http, routeParams)
@setLoggedOut() # Preinit user
@checkLogin() # Do an initial fetch
endpoint: "auth"
logout: () ->
create: (payload) ->
@log.debug("Attempting create for #{payload}")
@postId("create", payload)
.success (results) =>
@log.debug("Created in!")
login: (loginName, password) ->
# Use a form style post
config =
'Content-Type': 'application/x-www-form-urlencoded'
@log.debug("Attempting login for #{loginName}")
data = $.param
login: loginName
password: password
@postId("login", data, config)
.success (results) =>
@log.debug("Logged in!")
.error (results, status) =>
@log.debug("Not logged in #{results}, #{status}")
password_reset: (loginName) ->
@log.debug("Attempting password reset for #{loginName}")
@postId("pwreset/#{loginName}", {})
password_reset_confirm: (loginName, token, newPassword) ->
@log.debug("Attempting password confirm for #{loginName}")
@postId("pwreset/#{loginName}/#{token}", JSON.stringify(newPassword))
.success (results) =>
@log.debug("Password reset complete!")
email_confirm: (loginName, token) ->
@log.debug("Attempting email confirm for #{loginName}")
@postId("emailconfirm/#{loginName}/#{token}", {})
# Returns the updated user record
setLoggedIn: (userRecord) =>
@user = userRecord
@user.loggedIn = true
setLoggedOut: () =>
@user =
loggedIn: false
getUser: () =>
checkLogin: () ->
.then (results) =>
@log.debug("login complete!")
@error = null
, (results) =>
@log.error("Login check failed #{results.status}: #{results.statusText}")
if results.status == 0
@error = "DroneAPI server is offline, please try again later."
class UserService extends RESTService
endpoint: "user"
class VehicleService extends RESTService
endpoint: "vehicle"
vehicleTypes: [
class MissionService extends RESTService
@$inject: ['$log', '$http', '$routeParams', 'atmosphere', 'authService']
constructor: (log, http, routeParams, @atmosphere, @authService) ->
@fetchParams = @getFetchParams()
@createdAt = 'desc'
@userWatching = @authService.getUser()
super(log, http, routeParams)
endpoint: "mission"
getAllMissions: (fetchParams) =>
fetchParams or= @getFetchParams()
getUserMissions: (userLogin, filterParams = false) =>
fetchParams =
field_userName: userLogin
# if we want to limit the user data set even further
# and add more filters we should always use getUserMissions
# with the second param being arguments
angular.extend(fetchParams, filterParams) if filterParams
getVehicleTypeMissions: (vehicleType) =>
fetchParams =
field_vehicleType: vehicleType
getDurationMissions: (duration, opt = 'GT') =>
fetchParams = {}
fetchParams["field_flightDuration[#{opt}]"] = duration
getMaxAltMissions: (altitude, opt = 'GT') =>
fetchParams = {}
fetchParams["field_maxAlt[#{opt}]"] = altitude
getMaxGroundSpeedMissions: (speed, opt = 'GT') =>
fetchParams = {}
fetchParams["field_maxGroundspeed[#{opt}]"] = speed
getMaxAirSpeedMissions: (speed, opt = 'GT') =>
fetchParams = {}
fetchParams["field_maxAirspeed[#{opt}]"] = speed
getLatitudeMissions: (latitude, opt = 'GT') =>
fetchParams = {}
fetchParams["field_latitude[#{opt}]"] = latitude
getLongitudeMissions: (longitude, opt = 'GT') =>
fetchParams = {}
fetchParams["field_longitude[#{opt}"] = longitude
getMissionsFromParams: (params) =>
angular.extend(params, @getFetchParams())
getMissions: (params) =>
missions = @get(params)
missions.then @fixMissionRecords
fixMissionRecords: (results) =>
(@fixMissionRecord(record) for record in results)
fixMissionRecord: (record) =>
date = new Date(record.createdOn)
record.dateString = "#{date.toDateString()} - #{date.toLocaleTimeString()}"
record.text = record.summaryText ? "Mission #{}"
# If the user is looking at their own maps, then zoom in a bit more (because they are probably in same area of world)
isMine = @userWatching.loggedIn && (record.userName == @userWatching.login)
record.staticZoom = if isMine then 10 else 8
getFetchParams: ->
fetchParams =
order_by: 'createdAt'
order_dir: @createdAt
page_offset: 0
page_size: 12
atmosphere_connect: () =>
request =
url: @urlBase() + '/live'
angular.extend(request, @config)
angular.extend(request, atmosphereOptions)
if @authService.getUser().login?
request.headers.login = @authService.getUser().login
atmosphere_disconnect: () =>
get_staticmap: () =>
get_parameters: (id) =>
c = angular.extend({}, @config)
@http.get("#{@urlBase()}/#{id}/parameters.json", c)
.success (results) ->
get_plotdata: (id) =>
c = angular.extend({}, @config)
@http.get("#{@urlBase()}/#{id}/dseries", c)
.success (results) ->
get_analysis: (id) =>
c = angular.extend({}, @config)
@http.get("#{@urlBase()}/#{id}/analysis.json", c)
.success (results) ->
get_geojson: (id) =>
c = angular.extend({}, @config)
@http.get("#{@urlBase()}/#{id}/messages.geo.json", c)
# Server admin operations - not useful to users/developers
class AdminService extends RESTService
@$inject: ['$log', '$http', '$routeParams', 'atmosphere']
constructor: (log, http, routeParams, @atmosphere) ->
super(log, http, routeParams)
request =
url: @urlBase() + '/log'
angular.extend(request, @config)
angular.extend(request, atmosphereOptions)
endpoint: "admin"
startSim: (typ) =>"Service starting sim " + typ)
@postId("sim/" + typ)
importOld: (count) =>"importing " + count)
@postId("import/" + count)
getDebugInfo: () =>
module = angular.module('app')
module.service 'missionService', MissionService
module.service 'userService', UserService
module.service 'vehicleService', VehicleService
module.service 'authService', AuthService
module.service 'adminService', AdminService