github.com/manicqin/nomad@v0.9.5/ui/app/components/task-file.js (about) 1 import { inject as service } from '@ember/service'; 2 import Component from '@ember/component'; 3 import { computed } from '@ember/object'; 4 import { gt } from '@ember/object/computed'; 5 import { equal } from '@ember/object/computed'; 6 import RSVP from 'rsvp'; 7 import Log from 'nomad-ui/utils/classes/log'; 8 import timeout from 'nomad-ui/utils/timeout'; 9 10 export default Component.extend({ 11 token: service(), 12 13 classNames: ['boxed-section', 'task-log'], 14 15 'data-test-file-viewer': true, 16 17 allocation: null, 18 task: null, 19 file: null, 20 stat: null, // { Name, IsDir, Size, FileMode, ModTime, ContentType } 21 22 // When true, request logs from the server agent 23 useServer: false, 24 25 // When true, logs cannot be fetched from either the client or the server 26 noConnection: false, 27 28 clientTimeout: 1000, 29 serverTimeout: 5000, 30 31 mode: 'head', 32 33 fileComponent: computed('stat.ContentType', function() { 34 const contentType = this.stat.ContentType || ''; 35 36 if (contentType.startsWith('image/')) { 37 return 'image'; 38 } else if (contentType.startsWith('text/') || contentType.startsWith('application/json')) { 39 return 'stream'; 40 } else { 41 return 'unknown'; 42 } 43 }), 44 45 isLarge: gt('stat.Size', 50000), 46 47 fileTypeIsUnknown: equal('fileComponent', 'unknown'), 48 isStreamable: equal('fileComponent', 'stream'), 49 isStreaming: false, 50 51 catUrl: computed('allocation.id', 'task.name', 'file', function() { 52 const encodedPath = encodeURIComponent(`${this.task.name}/${this.file}`); 53 return `/v1/client/fs/cat/${this.allocation.id}?path=${encodedPath}`; 54 }), 55 56 fetchMode: computed('isLarge', 'mode', function() { 57 if (this.mode === 'streaming') { 58 return 'stream'; 59 } 60 61 if (!this.isLarge) { 62 return 'cat'; 63 } else if (this.mode === 'head' || this.mode === 'tail') { 64 return 'readat'; 65 } 66 }), 67 68 fileUrl: computed( 69 'allocation.id', 70 'allocation.node.httpAddr', 71 'fetchMode', 72 'useServer', 73 function() { 74 const address = this.get('allocation.node.httpAddr'); 75 const url = `/v1/client/fs/${this.fetchMode}/${this.allocation.id}`; 76 return this.useServer ? url : `//${address}${url}`; 77 } 78 ), 79 80 fileParams: computed('task.name', 'file', 'mode', function() { 81 // The Log class handles encoding query params 82 const path = `${this.task.name}/${this.file}`; 83 84 switch (this.mode) { 85 case 'head': 86 return { path, offset: 0, limit: 50000 }; 87 case 'tail': 88 return { path, offset: this.stat.Size - 50000, limit: 50000 }; 89 case 'streaming': 90 return { path, offset: 50000, origin: 'end' }; 91 default: 92 return { path }; 93 } 94 }), 95 96 logger: computed('fileUrl', 'fileParams', 'mode', function() { 97 // The cat and readat APIs are in plainText while the stream API is always encoded. 98 const plainText = this.mode === 'head' || this.mode === 'tail'; 99 100 // If the file request can't settle in one second, the client 101 // must be unavailable and the server should be used instead 102 const timing = this.useServer ? this.serverTimeout : this.clientTimeout; 103 const logFetch = url => 104 RSVP.race([this.token.authorizedRequest(url), timeout(timing)]).then( 105 response => { 106 if (!response || !response.ok) { 107 this.nextErrorState(response); 108 } 109 return response; 110 }, 111 error => this.nextErrorState(error) 112 ); 113 114 return Log.create({ 115 logFetch, 116 plainText, 117 params: this.fileParams, 118 url: this.fileUrl, 119 }); 120 }), 121 122 nextErrorState(error) { 123 if (this.useServer) { 124 this.set('noConnection', true); 125 } else { 126 this.send('failoverToServer'); 127 } 128 throw error; 129 }, 130 131 actions: { 132 toggleStream() { 133 this.set('mode', 'streaming'); 134 this.toggleProperty('isStreaming'); 135 }, 136 gotoHead() { 137 this.set('mode', 'head'); 138 this.set('isStreaming', false); 139 }, 140 gotoTail() { 141 this.set('mode', 'tail'); 142 this.set('isStreaming', false); 143 }, 144 failoverToServer() { 145 this.set('useServer', true); 146 }, 147 }, 148 });