未整理的一些code

04/23/2024

服务端做接口转发并且流式输入流式输出

function iteratorToStream(url: string) {
  const dataStream = fetchData(url);
  let streamNext = dataStream.next
  return new ReadableStream({
    async pull(controller) {
      // @ts-ignore
      const { chunk, done, next } = await streamNext
      streamNext = next;
      controller.enqueue(Buffer.from(chunk))
      if (done) {
        setTimeout(() => {
          controller.close()
        }, 1000)
      }
    },
  })
}
 
function fetchData(url: string) {
  let res:any, length = 0, curLength = 0;
  function nextResHandler(resFn: any) {
    res = resFn
  }
  fetch(url).then(function(response) {
    length = Number(response.headers.get("content-length")) || 0;
    return response.arrayBuffer();
  }).then(function(chunk) {
    curLength += chunk.byteLength;
    res({
      chunk,
      next: new Promise(res => nextResHandler(res)),
      done: curLength >= length
    })
  })
  return {next: new Promise(res => nextResHandler(res))}
}
 
export async function POST() {
  const stream = iteratorToStream('url')
  return new Response(stream)
}

schema 校验

const schemaDefinitions = {
  data: {
    type: 'object',
    properties: {
      timestamp: {
        type: 'number',
      },
      version: {
        type: 'string'
      },
      current: {
        type: 'string'
      },
      playback: {
        type: '__playback',
        required: false,
      },
      entries: {
        type: 'array',
        required: true,
        items: {
          type: '__entry'
        }
      }
    }
  },
  playback: {
    type: 'object',
    properties: {
      isPlaying: { type: 'boolean' },
      nextSnapshotDelayInMs: { type: 'number' }
    }
  },
  entry: {
    type: 'object',
    properties: {
      timestamp: { type: 'number' },
      snapshot: { type: '__snapshot' }
    }
  },
  snapshot: {
    type: 'object',
    properties: {
      id: { type: 'string' }
    }
    // data: snapshotData,
  }
}
 
const BasicTypes = [
  'string', 'boolean', 'number'
]
 
function validRequired(data: any, def: any) {
  if (def.required && data === undefined) {
    return false
  } 
  return true
}
 
function validBasic(data: any, type: string) {
  if (type === 'string' && !validString(data)) {
    return false
  } else if (type === 'boolean' && !validBoolean(data)) {
    return false
  } else if (type === 'number' && !validNumber(data)) {
    return false
  }
  return true
}
 
function validString(data:any) {
  if (data === undefined) {
    return true
  }
  return typeof data === 'string'
}
 
function validBoolean(data:any) {
  if (data === undefined) {
    return true
  }
  return typeof data === "boolean"
}
function validNumber(data:any) {
  if (data === undefined) {
    return true
  }
  return typeof data === "number"
}
 
function validArray(data: any, prop: any) {
  if (data !== undefined && !Array.isArray(data)) {
    return false
  }
  for (let i = 0; i < data.length; i++) {
    const _data = data[i];
    if (BasicTypes.includes(prop.type)) {
      if (!validBasic(_data, prop.type)) {
        return false
      }
    } else if (prop.type === 'array') {
      if (!validArray(_data, prop.items)) {
        return false
      }
    } else if (prop.type.startsWith('__')) {
      if (!validateSchema(_data, prop.type.substring(2, prop.type.length))) {
        return false
      }
    }
    return true
  }
}
 
export default function validateSchema(data: any, def: string) {
  // @ts-ignore
  const curDef = schemaDefinitions[def]
  const props = Object.keys(curDef.properties);
  for (let i = 0; i < props.length; i++) {
    const propName = props[i],
      prop = curDef.properties[propName],
      propValue = data[propName];
    if (!validRequired(propValue, prop)) {
      return false
    }
    if (BasicTypes.includes(prop.type)) {
      if (!validBasic(propValue, prop.type)) {
      return false
      }
    } else if (prop.type === 'array') {
      if (!validArray(propValue, prop.items)) {
      return false
      }
      return true
    } else if (prop.type.startsWith('__')) {
      if (!validateSchema(data[propName], prop.type.substring(2, prop.type.length))) {
      return false
      }
    }
  }
  return true
}

接口调用获得流式数据/buffer数据

let bufferData;
fetch(request)
  .then(function(response) {
    length = Number(response.headers.get("content-length")) || 0;
    return response.arrayBuffer();
}).then(function(chunk) {
  if (!bufferData) {
    bufferData = chunk;
  } else {
    bufferData = Buffer.concat([bufferData, chunk]);
  }
}).finally(async () => {
  // bufferData
})

transform buffer data to string & json

const respDataString = new TextDecoder().decode(data)
const respData = JSON.parse(respDataString)

handle file drag & drop

function handleFileDrop(file) {
  return new Promise((res) => {
    const reader = new FileReader();
    reader.onprogress = function(e) {
    }
    reader.onloadend = function(e) {
      const result = e?.target?.result;
      res(result)
    }
    reader.readAsArrayBuffer(file);
  })
}
 
function app() {
  const handleDragEnter = () => {}
  const handleDragLeave = () => {}
 
  const handleDragOver = (e: any) => {
    e.preventDefault()
    e.stopPropagation();
  }
  const handleDrop = (e: any) => {
    e.preventDefault()
    e.stopPropagation();
    handleFileDrop(e.dataTransfer.files[0])
  return <div
    onDragEnter={handleDragEnter}
    onDragOver={handleDragOver}
    onDragLeave={handleDragLeave}
    onDrop={handleDrop}
  ></div>
}